diff --git a/package.json b/package.json index db7859b3279..fbf13590e6e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Hoppscotch (support@hoppscotch.io)", "private": true, "license": "MIT", - "packageManager": "pnpm@10.32.1", + "packageManager": "pnpm@10.33.2", "scripts": { "preinstall": "npx only-allow pnpm", "prepare": "husky", @@ -24,7 +24,7 @@ "./packages/*" ], "devDependencies": { - "@commitlint/cli": "20.5.0", + "@commitlint/cli": "20.5.2", "@commitlint/config-conventional": "20.5.0", "@hoppscotch/ui": "0.2.5", "@types/node": "24.10.1", @@ -35,32 +35,19 @@ }, "pnpm": { "overrides": { - "@hono/node-server@>=1.0.0 <1.19.10": "1.19.10", "@nestjs-modules/mailer>mjml": "5.0.0-alpha.4", + "@xmldom/xmldom": "0.8.13", "apiconnect-wsdl": "2.0.36", "body-parser": "2.2.1", "cross-spawn": "7.0.6", - "dompurify@>=3.0.0 <3.3.3": "3.3.3", - "effect@3.18.4": "3.20.0", "execa@<2.0.0": "2.0.0", - "flatted@>=3.0.0 <3.4.2": "3.4.2", "form-data": "4.0.4", - "glob@>=10.2.0 <10.5.0": "10.5.0", "glob@>=11.0.0 <11.1.0": "11.1.0", - "hono@>=4.0.0 <4.12.7": "4.12.7", - "liquidjs@>=10.0.0 <10.25.0": "10.25.0", - "lodash@>=4.0.0 <4.17.23": "4.17.23", - "mailparser@>=3.0.0 <3.9.3": "3.9.3", - "minimatch@>=3.0.0 <3.1.3": "3.1.5", + "lodash": "4.18.1", "minimatch@>=4.0.0 <4.2.5": "4.2.5", - "minimatch@>=5.0.0 <10.2.3": "10.2.3", - "path-to-regexp@>=8.0.0 <8.4.0": "8.4.0", - "preview-email@>=3.0.0 <3.1.1": "3.1.1", - "rollup@>=4.0.0 <4.59.0": "4.59.0", - "serialize-javascript@>=7.0.0 <7.0.3": "7.0.3", + "serialize-javascript@<7.0.3": "7.0.3", "subscriptions-transport-ws>ws": "7.5.10", - "svgo@4.0.0": "4.0.1", - "vue": "3.5.31", + "vue": "3.5.33", "ws": "8.17.1" }, "onlyBuiltDependencies": [ diff --git a/packages/hoppscotch-agent/package.json b/packages/hoppscotch-agent/package.json index ccf60607d15..37d668e80b0 100644 --- a/packages/hoppscotch-agent/package.json +++ b/packages/hoppscotch-agent/package.json @@ -1,7 +1,7 @@ { "name": "hoppscotch-agent", "private": true, - "version": "0.1.16", + "version": "0.1.17", "type": "module", "scripts": { "dev": "vite", @@ -21,32 +21,32 @@ "@tauri-apps/api": "2.1.1", "@tauri-apps/plugin-shell": "2.3.3", "@vueuse/core": "14.2.1", - "axios": "1.13.6", + "axios": "1.15.2", "fp-ts": "2.16.11", - "lodash-es": "4.17.23", - "vue": "3.5.31" + "lodash-es": "4.18.1", + "vue": "3.5.33" }, "devDependencies": { - "@iconify-json/lucide": "1.2.99", + "@iconify-json/lucide": "1.2.104", "@tauri-apps/cli": "2.9.3", "@types/lodash-es": "4.17.12", "@types/node": "24.10.1", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@vitejs/plugin-vue": "6.0.5", + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", + "@vitejs/plugin-vue": "6.0.6", "@vue/eslint-config-typescript": "14.7.0", - "autoprefixer": "10.4.27", + "autoprefixer": "10.5.0", "cross-env": "10.1.0", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", - "eslint-plugin-vue": "10.8.0", + "eslint-plugin-vue": "10.9.0", "globals": "16.5.0", - "postcss": "8.5.8", + "postcss": "8.5.10", "tailwindcss": "3.4.16", "typescript": "5.9.3", "unplugin-icons": "22.5.0", "unplugin-vue-components": "30.0.0", - "vite": "7.3.1", + "vite": "7.3.2", "vue-tsc": "2.2.0" } } diff --git a/packages/hoppscotch-agent/src-tauri/Cargo.lock b/packages/hoppscotch-agent/src-tauri/Cargo.lock index 6d8aa024221..fd52c1d2c1f 100644 --- a/packages/hoppscotch-agent/src-tauri/Cargo.lock +++ b/packages/hoppscotch-agent/src-tauri/Cargo.lock @@ -2070,7 +2070,7 @@ dependencies = [ [[package]] name = "hoppscotch-agent" -version = "0.1.16" +version = "0.1.17" dependencies = [ "aes-gcm", "axum", @@ -3950,9 +3950,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", "getrandom 0.3.4", diff --git a/packages/hoppscotch-agent/src-tauri/Cargo.toml b/packages/hoppscotch-agent/src-tauri/Cargo.toml index 7c00e83eb42..c8809b0ca3a 100644 --- a/packages/hoppscotch-agent/src-tauri/Cargo.toml +++ b/packages/hoppscotch-agent/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hoppscotch-agent" -version = "0.1.16" +version = "0.1.17" description = "A cross-platform HTTP request agent for Hoppscotch for advanced request handling including custom headers, certificates, proxies, and local system integration." authors = ["AndrewBastin", "CuriousCorrelation"] edition = "2021" diff --git a/packages/hoppscotch-agent/src-tauri/tauri.conf.json b/packages/hoppscotch-agent/src-tauri/tauri.conf.json index 9565ce7854e..d23437e4440 100644 --- a/packages/hoppscotch-agent/src-tauri/tauri.conf.json +++ b/packages/hoppscotch-agent/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2.0.0-rc", "productName": "Hoppscotch Agent", - "version": "0.1.16", + "version": "0.1.17", "identifier": "io.hoppscotch.agent", "build": { "beforeDevCommand": "pnpm dev", diff --git a/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json b/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json index e8645b629a7..657477e91ca 100644 --- a/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json +++ b/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2.0.0-rc", "productName": "Hoppscotch Agent Portable", - "version": "0.1.16", + "version": "0.1.17", "identifier": "io.hoppscotch.agent", "build": { "beforeDevCommand": "pnpm dev", diff --git a/packages/hoppscotch-backend/package.json b/packages/hoppscotch-backend/package.json index e8a85928ba6..59cb099bddf 100644 --- a/packages/hoppscotch-backend/package.json +++ b/packages/hoppscotch-backend/package.json @@ -1,6 +1,6 @@ { "name": "hoppscotch-backend", - "version": "2026.3.1", + "version": "2026.4.0", "description": "", "author": "", "private": true, @@ -33,39 +33,38 @@ "dependencies": { "@apollo/server": "5.5.0", "@as-integrations/express5": "1.1.2", - "@nestjs-modules/mailer": "2.0.2", - "@nestjs/apollo": "13.2.4", - "@nestjs/common": "11.1.17", - "@nestjs/config": "4.0.3", - "@nestjs/core": "11.1.17", - "@nestjs/graphql": "13.2.4", + "@nestjs-modules/mailer": "2.3.4", + "@nestjs/apollo": "13.3.0", + "@nestjs/common": "11.1.19", + "@nestjs/config": "4.0.4", + "@nestjs/core": "11.1.19", + "@nestjs/graphql": "13.3.0", "@nestjs/jwt": "11.0.2", "@nestjs/passport": "11.0.0", - "@nestjs/platform-express": "11.1.17", - "@nestjs/schedule": "6.1.1", - "@nestjs/swagger": "11.2.6", + "@nestjs/platform-express": "11.1.19", + "@nestjs/schedule": "6.1.3", + "@nestjs/swagger": "11.4.2", "@nestjs/terminus": "11.1.1", "@nestjs/throttler": "6.5.0", - "@prisma/adapter-pg": "7.5.0", - "@prisma/client": "7.5.0", + "@prisma/adapter-pg": "7.8.0", + "@prisma/client": "7.8.0", "argon2": "0.44.0", "bcrypt": "6.0.0", "class-transformer": "0.5.1", "class-validator": "0.15.1", "cookie": "1.1.1", "cookie-parser": "1.4.7", - "dotenv": "17.3.1", + "dotenv": "17.4.2", "express": "5.2.1", - "express-session": "1.19.0", "fp-ts": "2.16.11", - "graphql": "16.13.1", + "graphql": "16.13.2", "graphql-query-complexity": "1.1.0", "graphql-redis-subscriptions": "2.7.0", "graphql-subscriptions": "3.0.0", "handlebars": "4.7.9", "io-ts": "2.2.22", "morgan": "1.10.1", - "nodemailer": "8.0.4", + "nodemailer": "8.0.7", "passport": "0.7.0", "passport-github2": "0.1.12", "passport-google-oauth20": "2.0.0", @@ -73,8 +72,8 @@ "passport-local": "1.0.0", "passport-microsoft": "2.1.0", "pg": "8.20.0", - "posthog-node": "5.28.4", - "prisma": "7.5.0", + "posthog-node": "5.30.6", + "prisma": "7.8.0", "reflect-metadata": "0.2.2", "rimraf": "6.1.3", "rxjs": "7.8.2" @@ -82,35 +81,35 @@ "devDependencies": { "@eslint/eslintrc": "3.3.5", "@eslint/js": "10.0.1", - "@nestjs/cli": "11.0.16", - "@nestjs/schematics": "11.0.9", - "@nestjs/testing": "11.1.17", + "@nestjs/cli": "11.0.21", + "@nestjs/schematics": "11.1.0", + "@nestjs/testing": "11.1.19", "@relmify/jest-fp-ts": "2.1.1", "@types/bcrypt": "6.0.0", "@types/cookie-parser": "1.4.10", "@types/express": "5.0.6", "@types/jest": "30.0.0", - "@types/node": "25.5.0", - "@types/nodemailer": "7.0.11", + "@types/node": "25.6.0", + "@types/nodemailer": "8.0.0", "@types/passport-github2": "1.2.9", "@types/passport-google-oauth20": "2.0.17", "@types/passport-jwt": "4.0.1", "@types/passport-microsoft": "2.1.1", "@types/supertest": "7.2.0", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", + "@typescript-eslint/eslint-plugin": "8.59.1", + "@typescript-eslint/parser": "8.59.1", "cross-env": "10.1.0", - "eslint": "10.0.3", + "eslint": "10.2.1", "eslint-config-prettier": "10.1.8", "eslint-plugin-prettier": "5.5.5", - "globals": "17.4.0", + "globals": "17.5.0", "jest": "30.3.0", - "jest-mock-extended": "4.0.0", - "prettier": "3.8.1", + "jest-mock-extended": "4.0.1", + "prettier": "3.8.3", "source-map-support": "0.5.21", "supertest": "7.2.2", - "ts-jest": "29.4.6", - "ts-loader": "9.5.4", + "ts-jest": "29.4.9", + "ts-loader": "9.5.7", "ts-node": "10.9.2", "tsconfig-paths": "4.2.0", "typescript": "5.9.3" @@ -125,6 +124,14 @@ "../jest.setup.js" ], "preset": "ts-jest", + "transform": { + "^.+\\.(t|j)s$": [ + "ts-jest", + { + "diagnostics": false + } + ] + }, "clearMocks": true, "collectCoverage": true, "coverageDirectory": "coverage", diff --git a/packages/hoppscotch-backend/src/auth/stateless-state-store.ts b/packages/hoppscotch-backend/src/auth/stateless-state-store.ts new file mode 100644 index 00000000000..c511269346d --- /dev/null +++ b/packages/hoppscotch-backend/src/auth/stateless-state-store.ts @@ -0,0 +1,270 @@ +import * as crypto from 'crypto'; + +/** + * Module-level fallback secret for single-instance deployments + * where INFRA.SESSION_SECRET is not configured. + */ +const FALLBACK_SECRET = crypto.randomBytes(32).toString('hex'); + +/** + * Maximum serialized payload size in bytes. + * Prevents oversized state parameters that could break provider redirects + * or exceed URL length limits. + */ +const MAX_PAYLOAD_BYTES = 2048; + +/** + * Default cookie name used to bind the OAuth state to a specific browser session. + * Prevents login CSRF by ensuring the callback can only be completed + * by the same browser that initiated the OAuth flow. + */ +const DEFAULT_COOKIE_NAME = '__oauth_nonce'; + +/** + * A stateless OAuth state store for passport strategies. + * + * Instead of storing state in express-session (MemoryStore), this encodes + * the state as a signed, time-limited token passed through the OAuth `state` + * query parameter. The token format is: `base64url(payload).base64url(hmac)`. + * + * CSRF protection: A random nonce is generated per OAuth flow, stored in a + * SameSite=Lax HttpOnly cookie, and mixed into the HMAC signature. On + * callback, the nonce from the cookie is used to verify the signature, + * ensuring the same browser that started the flow completes it. + * + * This eliminates all server-side session state from the OAuth flow, making + * it fully compatible with horizontal scaling (multiple backend instances + * behind a load balancer). + * + * Supports both passport-oauth2 (Google, GitHub, Microsoft) which dispatches + * by `.length`, and passport-openidconnect (OIDC) which always calls with 5 args. + * + * IMPORTANT: For multi-instance deployments, `INFRA.SESSION_SECRET` must be + * set to the same value across all instances. + */ +export class StatelessStateStore { + private readonly secret: string; + private readonly maxAgeMs: number; + private readonly cookieName: string; + private readonly secureCookies: boolean; + + constructor( + secret?: string, + maxAgeMs: number = 600_000, + cookieName?: string, + secureCookies?: boolean, + ) { + if (!secret) { + if (process.env.NODE_ENV === 'production') { + throw new Error( + 'StatelessStateStore: INFRA.SESSION_SECRET must be set in production. Without a shared secret, OAuth callbacks will fail across load-balanced instances.', + ); + } + console.warn( + '[StatelessStateStore] INFRA.SESSION_SECRET not set; using ephemeral fallback. OAuth will fail in any multi-instance deployment.', + ); + } + this.secret = secret || FALLBACK_SECRET; + this.maxAgeMs = maxAgeMs; + this.cookieName = cookieName || DEFAULT_COOKIE_NAME; + this.secureCookies = secureCookies ?? false; + } + + /** + * Called by passport before redirecting to the OAuth provider. + * + * passport-oauth2 dispatches by `.length`: + * arity 5: store(req, verifier, state, meta, cb) — PKCE flow + * arity 4: store(req, state, meta, cb) — standard flow + * arity 3: store(req, meta, cb) — no state + * + * passport-openidconnect always calls with 5 args: + * store(req, ctx, appState, meta, cb) + * + * We declare 5 params so `.length === 5` satisfies both libraries. + * + * The token payload stores both `ctx` (OIDC context / PKCE verifier) and + * `state` (the app state, e.g. { redirect_uri }) so that verify() can + * return them both correctly to each library's restore/loaded callback. + */ + store( + req: any, + ctxOrState: any, + stateOrMeta: any, + metaOrCb: any, + cb?: Function, + ): void { + let ctx: any; + let state: any; + let callback: Function; + + if (typeof cb === 'function') { + // 5-arg: (req, verifier/ctx, state, meta, cb) + // For passport-oauth2 PKCE: verifier is a string, state is the app state + // For passport-openidconnect: ctx has { maxAge, nonce, issued }, state is app state + ctx = ctxOrState; + state = stateOrMeta; + callback = cb; + } else if (typeof metaOrCb === 'function') { + // 4-arg: (req, state, meta, cb) + ctx = undefined; + state = ctxOrState; + callback = metaOrCb; + } else if (typeof stateOrMeta === 'function') { + // 3-arg: (req, meta, cb) + ctx = undefined; + state = {}; + callback = stateOrMeta; + } else { + throw new Error('StatelessStateStore.store: invalid arguments'); + } + + try { + // Generate a browser-bound nonce for CSRF protection + const nonce = crypto.randomBytes(16).toString('hex'); + + const payload: any = { + state: state, + exp: Date.now() + this.maxAgeMs, + nonce: nonce, + }; + // Store ctx only if defined (OIDC context or PKCE verifier) + if (ctx !== undefined && ctx !== null) { + payload.ctx = ctx; + } + + const serialized = JSON.stringify(payload); + if (Buffer.byteLength(serialized) > MAX_PAYLOAD_BYTES) { + return callback( + new Error('OAuth state payload exceeds maximum allowed size'), + ); + } + + const encoded = this.encode(payload); + + // Set the nonce as a SameSite cookie to bind the OAuth flow to this browser + if (req.res) { + req.res.cookie(this.cookieName, nonce, { + httpOnly: true, + sameSite: 'lax', + secure: this.secureCookies, + maxAge: this.maxAgeMs, + path: '/', + }); + } + + callback(null, encoded); + } catch (err) { + callback(err); + } + } + + /** + * Called by passport on the callback to verify the state parameter. + * + * passport-oauth2 dispatches by `.length`: + * arity 4: verify(req, state, meta, cb) + * arity 3: verify(req, state, cb) + * + * passport-openidconnect always calls with 3 args: + * verify(req, handle, cb) → restored(err, ctx, state) + * + * We declare 3 params (matching both) since passport-oauth2 will dispatch + * to arity 3 when `.length === 3`. + * + * Return semantics (second arg → third arg of cb): + * passport-oauth2: cb(null, ok:truthy|string, appState) + * passport-openidconnect: cb(null, ctx:{maxAge,nonce,issued}, appState) + * + * We return the stored ctx (or `true` when ctx was not stored) as the + * second arg, and the app state as the third arg. This satisfies both: + * - passport-oauth2 just needs truthy (or a PKCE verifier string) + * - passport-openidconnect needs the OIDC context object + */ + verify(req: any, providedState: string, cb: Function): void { + try { + // Read the browser-bound nonce from the cookie + const cookieNonce = req.cookies?.[this.cookieName]; + + // Clear the nonce cookie regardless of outcome + if (req.res) { + req.res.clearCookie(this.cookieName, { + path: '/', + httpOnly: true, + sameSite: 'lax', + secure: this.secureCookies, + }); + } + + if (!cookieNonce) { + return cb(null, false, { message: 'Missing OAuth nonce cookie' }); + } + + const payload = this.decode(providedState, cookieNonce); + if (!payload) { + return cb(null, false, { message: 'Invalid state signature' }); + } + + if (payload.exp && Date.now() > payload.exp) { + return cb(null, false, { message: 'State has expired' }); + } + + // Return ctx (OIDC context or PKCE verifier) as second arg, + // falling back to `true` for plain OAuth2 flows without ctx. + // Return the app state (e.g. { redirect_uri }) as third arg. + const ctx = payload.ctx !== undefined ? payload.ctx : true; + cb(null, ctx, payload.state); + } catch (err) { + cb(err); + } + } + + /** + * Decode and verify a signed state token. + * Returns null if the token is missing, malformed, or the signature is invalid. + */ + private decode(token: string, nonce?: string): any | null { + try { + if (!token) return null; + + const dotIndex = token.indexOf('.'); + if (dotIndex === -1) return null; + + const payloadStr = token.substring(0, dotIndex); + const signature = token.substring(dotIndex + 1); + + const expectedSignature = this.sign(payloadStr, nonce); + + if ( + signature.length !== expectedSignature.length || + !crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expectedSignature), + ) + ) { + return null; + } + + return JSON.parse(Buffer.from(payloadStr, 'base64url').toString()); + } catch { + return null; + } + } + + private encode(payload: any): string { + const payloadStr = Buffer.from(JSON.stringify(payload)).toString( + 'base64url', + ); + const signature = this.sign(payloadStr, payload.nonce); + return `${payloadStr}.${signature}`; + } + + private sign(data: string, nonce?: string): string { + const hmac = crypto.createHmac('sha256', this.secret); + hmac.update(data); + if (nonce) { + hmac.update(nonce); + } + return hmac.digest('base64url'); + } +} diff --git a/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts index 7c085d10772..17de3361607 100644 --- a/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts +++ b/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts @@ -8,6 +8,7 @@ import * as E from 'fp-ts/Either'; import { ConfigService } from '@nestjs/config'; import { validateEmail } from 'src/utils'; import { AUTH_EMAIL_NOT_PROVIDED_BY_OAUTH } from 'src/errors'; +import { StatelessStateStore } from '../stateless-state-store'; @Injectable() export class GithubStrategy extends PassportStrategy(Strategy) { @@ -21,7 +22,13 @@ export class GithubStrategy extends PassportStrategy(Strategy) { clientSecret: configService.get('INFRA.GITHUB_CLIENT_SECRET'), callbackURL: configService.get('INFRA.GITHUB_CALLBACK_URL'), scope: [configService.get('INFRA.GITHUB_SCOPE')], - store: true, + store: new StatelessStateStore( + configService.get('INFRA.SESSION_SECRET'), + undefined, + (configService.get('INFRA.SESSION_COOKIE_NAME') || + '__oauth_nonce') + '_github', + configService.get('INFRA.ALLOW_SECURE_COOKIES') === 'true', + ), }); } diff --git a/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts index 523392c0b72..7b5e1153e82 100644 --- a/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts +++ b/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts @@ -9,6 +9,7 @@ import { ConfigService } from '@nestjs/config'; import { Request } from 'express'; import { validateEmail } from 'src/utils'; import { AUTH_EMAIL_NOT_PROVIDED_BY_OAUTH } from 'src/errors'; +import { StatelessStateStore } from '../stateless-state-store'; @Injectable() export class GoogleStrategy extends PassportStrategy(Strategy) { @@ -23,7 +24,13 @@ export class GoogleStrategy extends PassportStrategy(Strategy) { callbackURL: configService.get('INFRA.GOOGLE_CALLBACK_URL'), scope: configService.get('INFRA.GOOGLE_SCOPE').split(','), passReqToCallback: true, - store: true, + store: new StatelessStateStore( + configService.get('INFRA.SESSION_SECRET'), + undefined, + (configService.get('INFRA.SESSION_COOKIE_NAME') || + '__oauth_nonce') + '_google', + configService.get('INFRA.ALLOW_SECURE_COOKIES') === 'true', + ), }); } diff --git a/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts index 885542dfc3f..262630e8cea 100644 --- a/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts +++ b/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts @@ -8,6 +8,7 @@ import * as E from 'fp-ts/Either'; import { ConfigService } from '@nestjs/config'; import { validateEmail } from 'src/utils'; import { AUTH_EMAIL_NOT_PROVIDED_BY_OAUTH } from 'src/errors'; +import { StatelessStateStore } from '../stateless-state-store'; @Injectable() export class MicrosoftStrategy extends PassportStrategy(Strategy) { @@ -22,7 +23,13 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy) { callbackURL: configService.get('INFRA.MICROSOFT_CALLBACK_URL'), scope: configService.get('INFRA.MICROSOFT_SCOPE').split(','), tenant: configService.get('INFRA.MICROSOFT_TENANT'), - store: true, + store: new StatelessStateStore( + configService.get('INFRA.SESSION_SECRET'), + undefined, + (configService.get('INFRA.SESSION_COOKIE_NAME') || + '__oauth_nonce') + '_microsoft', + configService.get('INFRA.ALLOW_SECURE_COOKIES') === 'true', + ), }); } diff --git a/packages/hoppscotch-backend/src/errors.ts b/packages/hoppscotch-backend/src/errors.ts index c3a64aff625..56bcbfbec83 100644 --- a/packages/hoppscotch-backend/src/errors.ts +++ b/packages/hoppscotch-backend/src/errors.ts @@ -462,6 +462,12 @@ export const USER_ENVIRONMENT_IS_NOT_GLOBAL = export const USER_ENVIRONMENT_UPDATE_FAILED = 'user_environment/user_env_update_failed' as const; +/** + * User environment not found for the user + * (UserEnvironmentsService) + */ +export const USER_ENVIRONMENT_NOT_FOUND = 'user_environment/not_found' as const; + /** * User environment invalid environment name * (UserEnvironmentsService) @@ -977,8 +983,8 @@ export const PUBLISHED_DOCS_DELETION_FAILED = 'published_docs/deletion_failed'; * Published Docs invalid environment * (PublishedDocsService) */ -export const PUBLISHED_DOCS_INVALID_ENVIRONMENT = - 'published_docs/invalid_environment'; +export const PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS = + 'published_docs/forbidden_environment_access'; /** * Published Docs not found diff --git a/packages/hoppscotch-backend/src/infra-config/dto/onboarding.dto.ts b/packages/hoppscotch-backend/src/infra-config/dto/onboarding.dto.ts index 71c35cfa22e..c3e38ec7ebd 100644 --- a/packages/hoppscotch-backend/src/infra-config/dto/onboarding.dto.ts +++ b/packages/hoppscotch-backend/src/infra-config/dto/onboarding.dto.ts @@ -114,6 +114,31 @@ export class SaveOnboardingConfigRequest { @IsOptional() @IsString() [InfraConfigEnum.MAILER_SMTP_IGNORE_TLS]: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + [InfraConfigEnum.MAILER_SMTP_AUTH_TYPE]: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_USER]: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_CLIENT_ID]: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_CLIENT_SECRET]: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_REFRESH_TOKEN]: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL]: string; } export class SaveOnboardingConfigResponse { @@ -204,4 +229,23 @@ export class GetOnboardingConfigResponse { @ApiProperty() @Expose() [InfraConfigEnum.MAILER_SMTP_IGNORE_TLS]: string; + + @ApiProperty() + @Expose() + [InfraConfigEnum.MAILER_SMTP_AUTH_TYPE]: string; + @ApiProperty() + @Expose() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_USER]: string; + @ApiProperty() + @Expose() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_CLIENT_ID]: string; + @ApiProperty() + @Expose() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_CLIENT_SECRET]: string; + @ApiProperty() + @Expose() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_REFRESH_TOKEN]: string; + @ApiProperty() + @Expose() + [InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL]: string; } diff --git a/packages/hoppscotch-backend/src/infra-config/helper.ts b/packages/hoppscotch-backend/src/infra-config/helper.ts index ee583316052..b2171817a5f 100644 --- a/packages/hoppscotch-backend/src/infra-config/helper.ts +++ b/packages/hoppscotch-backend/src/infra-config/helper.ts @@ -2,6 +2,7 @@ import { AuthProvider } from 'src/auth/helper'; import { ENV_INVALID_DATA_ENCRYPTION_KEY } from 'src/errors'; import { PrismaService } from 'src/prisma/prisma.service'; import { InfraConfigEnum } from 'src/types/InfraConfig'; +import { SMTPAuthType } from 'src/mailer/helper'; import { decrypt, encrypt } from 'src/utils'; import { randomBytes } from 'crypto'; @@ -243,6 +244,36 @@ export async function getDefaultInfraConfigs(): Promise { value: 'false', isEncrypted: false, }, + { + name: InfraConfigEnum.MAILER_SMTP_AUTH_TYPE, + value: SMTPAuthType.LOGIN, + isEncrypted: false, + }, + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_USER, + value: null, + isEncrypted: false, + }, + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_CLIENT_ID, + value: null, + isEncrypted: true, + }, + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_CLIENT_SECRET, + value: null, + isEncrypted: true, + }, + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_REFRESH_TOKEN, + value: null, + isEncrypted: true, + }, + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL, + value: null, + isEncrypted: false, + }, { name: InfraConfigEnum.GOOGLE_CLIENT_ID, value: null, diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.service.spec.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.service.spec.ts index d46fa15dc1d..bac795407b1 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.service.spec.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.service.spec.ts @@ -3,6 +3,7 @@ import { PrismaService } from 'src/prisma/prisma.service'; import { InfraConfigService } from './infra-config.service'; import { InfraConfigEnum } from 'src/types/InfraConfig'; import { + INFRA_CONFIG_INVALID_INPUT, INFRA_CONFIG_NOT_FOUND, INFRA_CONFIG_OPERATION_NOT_ALLOWED, INFRA_CONFIG_UPDATE_FAILED, @@ -292,4 +293,215 @@ describe('InfraConfigService', () => { ); }); }); + + describe('validateEnvValues', () => { + describe('MAILER_SMTP_AUTH_TYPE', () => { + it('should accept an empty value (defaults to login at runtime)', () => { + const result = infraConfigService.validateEnvValues([ + { name: InfraConfigEnum.MAILER_SMTP_AUTH_TYPE, value: '' }, + ]); + expect(result).toEqualRight(true); + }); + + it('should accept a known auth type', () => { + const result = infraConfigService.validateEnvValues([ + { name: InfraConfigEnum.MAILER_SMTP_AUTH_TYPE, value: 'oauth2' }, + ]); + expect(result).toEqualRight(true); + }); + + it('should reject an unknown auth type', () => { + const result = infraConfigService.validateEnvValues([ + { name: InfraConfigEnum.MAILER_SMTP_AUTH_TYPE, value: 'kerberos' }, + ]); + expect(result).toEqualLeft(INFRA_CONFIG_INVALID_INPUT); + }); + }); + + describe('MAILER_SMTP_OAUTH2_ACCESS_URL', () => { + it('should accept an empty value', () => { + const result = infraConfigService.validateEnvValues([ + { name: InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL, value: '' }, + ]); + expect(result).toEqualRight(true); + }); + + it('should accept a valid HTTPS URL', () => { + const result = infraConfigService.validateEnvValues([ + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL, + value: 'https://oauth2.googleapis.com/token', + }, + ]); + expect(result).toEqualRight(true); + }); + + it('should reject a malformed URL', () => { + const result = infraConfigService.validateEnvValues([ + { + name: InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL, + value: 'not-a-url', + }, + ]); + expect(result).toEqualLeft(INFRA_CONFIG_INVALID_INPUT); + }); + }); + }); + + describe('getOnboardingConfig', () => { + const RECOVERY_TOKEN = 'valid-recovery-token-123'; + + const mockConfigs = [ + { + name: InfraConfigEnum.ONBOARDING_RECOVERY_TOKEN, + value: RECOVERY_TOKEN, + }, + { name: InfraConfigEnum.GOOGLE_CLIENT_ID, value: 'google-id' }, + { + name: InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS, + value: 'google', + }, + ]; + + it('should return config values when token is valid', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + const result = + await infraConfigService.getOnboardingConfig(RECOVERY_TOKEN); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.ONBOARDING_RECOVERY_TOKEN]).toBe( + RECOVERY_TOKEN, + ); + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBe( + 'google-id', + ); + } + }); + + it('should return null values when token does not match', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + const result = + await infraConfigService.getOnboardingConfig('wrong-token'); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when token is empty string', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + const result = await infraConfigService.getOnboardingConfig(''); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when token is whitespace only', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + const result = await infraConfigService.getOnboardingConfig(' '); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when token is null', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + const result = await infraConfigService.getOnboardingConfig(null); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when token is undefined', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + const result = await infraConfigService.getOnboardingConfig(undefined); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when token is an array', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + // @ts-expect-error Testing invalid input + const result = await infraConfigService.getOnboardingConfig([]); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when token is a number', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(mockConfigs)); + + // @ts-expect-error Testing invalid input + const result = await infraConfigService.getOnboardingConfig(42); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return null values when ONBOARDING_RECOVERY_TOKEN is absent from configs', async () => { + const configsWithoutToken = mockConfigs.filter( + (c) => c.name !== InfraConfigEnum.ONBOARDING_RECOVERY_TOKEN, + ); + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.right(configsWithoutToken)); + + const result = + await infraConfigService.getOnboardingConfig(RECOVERY_TOKEN); + + expect(E.isRight(result)).toBe(true); + if (E.isRight(result)) { + expect(result.right[InfraConfigEnum.GOOGLE_CLIENT_ID]).toBeNull(); + } + }); + + it('should return left with error when getMany fails', async () => { + jest + .spyOn(infraConfigService, 'getMany') + .mockResolvedValueOnce(E.left(INFRA_CONFIG_NOT_FOUND)); + + const result = + await infraConfigService.getOnboardingConfig(RECOVERY_TOKEN); + + expect(result).toEqualLeft(INFRA_CONFIG_NOT_FOUND); + }); + }); }); diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts index ce43cd6841d..601d5ebbe69 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts @@ -4,6 +4,7 @@ import { PrismaService } from 'src/prisma/prisma.service'; import { InfraConfig as DBInfraConfig } from 'src/generated/prisma/client'; import * as E from 'fp-ts/Either'; import { InfraConfigEnum } from 'src/types/InfraConfig'; +import { SMTPAuthType } from 'src/mailer/helper'; import { AUTH_PROVIDER_NOT_SPECIFIED, DATABASE_TABLE_NOT_EXIST, @@ -607,7 +608,11 @@ export class InfraConfigService implements OnModuleInit, OnModuleDestroy { const recoveryToken = configs.right.find( (config) => config.name === InfraConfigEnum.ONBOARDING_RECOVERY_TOKEN, )?.value; - const tokenIsValid = token === recoveryToken; + + const tokenIsValid = + typeof token === 'string' && + token.trim().length > 0 && + token === recoveryToken; const onboardingConfig = configs.right.reduce((acc, config) => { acc[config.name] = tokenIsValid ? config.value : null; @@ -736,6 +741,18 @@ export class InfraConfigService implements OnModuleInit, OnModuleDestroy { if (value !== 'true' && value !== 'false') return fail(); break; + case InfraConfigEnum.MAILER_SMTP_AUTH_TYPE: + if ( + value && + !Object.values(SMTPAuthType).includes(value as SMTPAuthType) + ) + return fail(); + break; + + case InfraConfigEnum.MAILER_SMTP_OAUTH2_ACCESS_URL: + if (value && !validateUrl(value)) return fail(); + break; + case InfraConfigEnum.MAILER_SMTP_URL: if (!validateSMTPUrl(value)) return fail(); break; diff --git a/packages/hoppscotch-backend/src/infra-config/onboarding.controller.ts b/packages/hoppscotch-backend/src/infra-config/onboarding.controller.ts index f0c2ef636da..404ed6b3f3a 100644 --- a/packages/hoppscotch-backend/src/infra-config/onboarding.controller.ts +++ b/packages/hoppscotch-backend/src/infra-config/onboarding.controller.ts @@ -104,6 +104,24 @@ export class OnboardingController { type: GetOnboardingConfigResponse, }) async getOnboardingConfig(@Query('token') token: string) { + const onboardingStatus = + await this.infraConfigService.getOnboardingStatus(); + + if (E.isLeft(onboardingStatus)) + throwHTTPErr({ + message: onboardingStatus.left, + statusCode: HttpStatus.UNPROCESSABLE_ENTITY, + }); + + if ( + onboardingStatus.right.onboardingCompleted && + !onboardingStatus.right.canReRunOnboarding + ) + throwHTTPErr({ + message: ONBOARDING_CANNOT_BE_RERUN, + statusCode: HttpStatus.BAD_REQUEST, + }); + const onboardingConfig = await this.infraConfigService.getOnboardingConfig(token); diff --git a/packages/hoppscotch-backend/src/mailer/helper.ts b/packages/hoppscotch-backend/src/mailer/helper.ts index d38dc71b237..9d4788e2740 100644 --- a/packages/hoppscotch-backend/src/mailer/helper.ts +++ b/packages/hoppscotch-backend/src/mailer/helper.ts @@ -1,7 +1,15 @@ -import { TransportType } from '@nestjs-modules/mailer/dist/interfaces/mailer-options.interface'; +import type { MailerOptions } from '@nestjs-modules/mailer'; +import type SMTPConnection from 'nodemailer/lib/smtp-connection'; import { MAILER_SMTP_URL_UNDEFINED } from 'src/errors'; import { throwErr } from 'src/utils'; +type TransportType = NonNullable; + +export enum SMTPAuthType { + LOGIN = 'login', + OAUTH2 = 'oauth2', +} + function isSMTPCustomConfigsEnabled(value) { return value === 'true'; } @@ -21,20 +29,46 @@ export function getTransportOption(env): TransportType { } else { console.log('Using advanced mailer configuration'); - const smtpUser = env.INFRA.MAILER_SMTP_USER?.trim() || undefined; - const smtpPass = env.INFRA.MAILER_SMTP_PASSWORD?.trim() || undefined; + const authType = env.INFRA.MAILER_SMTP_AUTH_TYPE?.trim(); - // Both credentials must be provided together or both omitted - const hasUser = !!smtpUser; - const hasPass = !!smtpPass; - if (hasUser !== hasPass) { - throw new Error( - 'SMTP auth requires both MAILER_SMTP_USER and MAILER_SMTP_PASSWORD. Provide both or leave both empty for unauthenticated relay.', - ); - } + let auth: SMTPConnection.AuthenticationType | undefined; - const auth = - smtpUser && smtpPass ? { user: smtpUser, pass: smtpPass } : undefined; + if (authType === SMTPAuthType.OAUTH2) { + const oauth2User = env.INFRA.MAILER_SMTP_OAUTH2_USER?.trim() || undefined; + const oauth2ClientId = + env.INFRA.MAILER_SMTP_OAUTH2_CLIENT_ID?.trim() || undefined; + const oauth2ClientSecret = + env.INFRA.MAILER_SMTP_OAUTH2_CLIENT_SECRET?.trim() || undefined; + const oauth2RefreshToken = + env.INFRA.MAILER_SMTP_OAUTH2_REFRESH_TOKEN?.trim() || undefined; + const oauth2AccessUrl = + env.INFRA.MAILER_SMTP_OAUTH2_ACCESS_URL?.trim() || undefined; + + auth = { + type: SMTPAuthType.OAUTH2, + user: oauth2User, + clientId: oauth2ClientId, + clientSecret: oauth2ClientSecret, + refreshToken: oauth2RefreshToken, + accessUrl: oauth2AccessUrl, + }; + } else { + const smtpUser = env.INFRA.MAILER_SMTP_USER?.trim() || undefined; + const smtpPass = env.INFRA.MAILER_SMTP_PASSWORD?.trim() || undefined; + + const hasUser = !!smtpUser; + const hasPass = !!smtpPass; + if (hasUser !== hasPass) { + throw new Error( + 'SMTP auth requires both MAILER_SMTP_USER and MAILER_SMTP_PASSWORD. Provide both or leave both empty for unauthenticated relay.', + ); + } + + auth = + smtpUser && smtpPass + ? { type: SMTPAuthType.LOGIN, user: smtpUser, pass: smtpPass } + : undefined; + } return { host: env.INFRA.MAILER_SMTP_HOST, diff --git a/packages/hoppscotch-backend/src/mailer/mailer.module.ts b/packages/hoppscotch-backend/src/mailer/mailer.module.ts index da630b6c7b6..8c578c74f1b 100644 --- a/packages/hoppscotch-backend/src/mailer/mailer.module.ts +++ b/packages/hoppscotch-backend/src/mailer/mailer.module.ts @@ -1,6 +1,6 @@ import { Global, Module } from '@nestjs/common'; import { MailerModule as NestMailerModule } from '@nestjs-modules/mailer'; -import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter'; +import { HandlebarsAdapter } from '@nestjs-modules/mailer/adapters/handlebars.adapter'; import { MailerService } from './mailer.service'; import { loadInfraConfiguration } from 'src/infra-config/helper'; import { getMailerAddressFrom, getTransportOption } from './helper'; diff --git a/packages/hoppscotch-backend/src/main.ts b/packages/hoppscotch-backend/src/main.ts index 47f5e24827a..94be62be400 100644 --- a/packages/hoppscotch-backend/src/main.ts +++ b/packages/hoppscotch-backend/src/main.ts @@ -3,9 +3,7 @@ import { json } from 'express'; import { AppModule } from './app.module'; import cookieParser from 'cookie-parser'; import { ValidationPipe, VersioningType } from '@nestjs/common'; -import session from 'express-session'; import { emitGQLSchemaFile } from './gql-schema'; -import * as crypto from 'crypto'; import morgan from 'morgan'; import { ConfigService } from '@nestjs/config'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; @@ -50,21 +48,6 @@ async function bootstrap() { console.log(`Running in production: ${isProduction}`); console.log(`Port: ${configService.get('PORT')}`); - app.use( - session({ - // Allow overriding the default cookie name 'connect.sid' (which contains a dot). - // Some proxies/load balancers (like older Kong versions) cannot hash cookie names with dots, - // so we allow setting an alternative name via the INFRA.SESSION_COOKIE_NAME configuration. - name: - configService.get('INFRA.SESSION_COOKIE_NAME') || 'connect.sid', - secret: - configService.get('INFRA.SESSION_SECRET') || - crypto.randomBytes(16).toString('hex'), - resave: false, - saveUninitialized: false, - }), - ); - // Increase file upload limit to 100MB app.use( json({ diff --git a/packages/hoppscotch-backend/src/prisma/prisma-error-codes.ts b/packages/hoppscotch-backend/src/prisma/prisma-error-codes.ts index 0ae4819c73e..432a5715f4a 100644 --- a/packages/hoppscotch-backend/src/prisma/prisma-error-codes.ts +++ b/packages/hoppscotch-backend/src/prisma/prisma-error-codes.ts @@ -2,6 +2,7 @@ export enum PrismaError { DATABASE_UNREACHABLE = 'P1001', TABLE_DOES_NOT_EXIST = 'P2021', UNIQUE_CONSTRAINT_VIOLATION = 'P2002', + RECORD_NOT_FOUND = 'P2025', TRANSACTION_TIMEOUT = 'P2028', TRANSACTION_DEADLOCK = 'P2034', // write conflict or a deadlock } diff --git a/packages/hoppscotch-backend/src/published-docs/published-docs.service.spec.ts b/packages/hoppscotch-backend/src/published-docs/published-docs.service.spec.ts index 5d7769f4c89..c3b3aa0bbc3 100644 --- a/packages/hoppscotch-backend/src/published-docs/published-docs.service.spec.ts +++ b/packages/hoppscotch-backend/src/published-docs/published-docs.service.spec.ts @@ -4,10 +4,12 @@ import { PUBLISHED_DOCS_CREATION_FAILED, PUBLISHED_DOCS_DELETION_FAILED, PUBLISHED_DOCS_INVALID_COLLECTION, - PUBLISHED_DOCS_INVALID_ENVIRONMENT, + PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS, PUBLISHED_DOCS_NOT_FOUND, PUBLISHED_DOCS_UPDATE_FAILED, + TEAM_ENVIRONMENT_NOT_FOUND, TEAM_INVALID_ID, + USER_ENVIRONMENT_NOT_FOUND, } from 'src/errors'; import * as E from 'fp-ts/Either'; import { PrismaService } from 'src/prisma/prisma.service'; @@ -1491,7 +1493,7 @@ describe('createPublishedDoc - environment support', () => { userUid: user.uid, } as any); mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null); - mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(envData as any); + mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(envData as any); mockPrisma.publishedDocs.create.mockResolvedValueOnce({ ...userPublishedDoc, environmentID: 'env_1', @@ -1537,7 +1539,7 @@ describe('createPublishedDoc - environment support', () => { teamID: 'team_1', } as any); mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null); - mockPrisma.teamEnvironment.findFirst.mockResolvedValueOnce(envData as any); + mockPrisma.teamEnvironment.findUnique.mockResolvedValueOnce(envData as any); mockPrisma.publishedDocs.create.mockResolvedValueOnce({ ...teamPublishedDoc, environmentID: 'team_env_1', @@ -1568,14 +1570,14 @@ describe('createPublishedDoc - environment support', () => { userUid: user.uid, } as any); mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null); - mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(null); + mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(null); const result = await publishedDocsService.createPublishedDoc( { ...createArgs, environmentID: 'invalid_env' }, user, ); - expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT); + expect(result).toEqualLeft(USER_ENVIRONMENT_NOT_FOUND); }); test('should return error when team environment ID is invalid', async () => { @@ -1593,14 +1595,14 @@ describe('createPublishedDoc - environment support', () => { teamID: 'team_1', } as any); mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null); - mockPrisma.teamEnvironment.findFirst.mockResolvedValueOnce(null); + mockPrisma.teamEnvironment.findUnique.mockResolvedValueOnce(null); const result = await publishedDocsService.createPublishedDoc( teamArgs, user, ); - expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT); + expect(result).toEqualLeft(TEAM_ENVIRONMENT_NOT_FOUND); }); test('should create published doc without environment when environmentID is not provided', async () => { @@ -1640,7 +1642,7 @@ describe('updatePublishedDoc - environment support', () => { }; mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(userPublishedDoc); - mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(envData as any); + mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(envData as any); mockPrisma.publishedDocs.update.mockResolvedValueOnce({ ...userPublishedDoc, environmentID: 'env_2', @@ -1701,7 +1703,7 @@ describe('updatePublishedDoc - environment support', () => { test('should return error when updating with invalid environment ID', async () => { mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(userPublishedDoc); - mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(null); + mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(null); const result = await publishedDocsService.updatePublishedDoc( userPublishedDoc.id, @@ -1709,7 +1711,7 @@ describe('updatePublishedDoc - environment support', () => { user, ); - expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT); + expect(result).toEqualLeft(USER_ENVIRONMENT_NOT_FOUND); }); test('should not change environment when environmentID is not provided in update args', async () => { @@ -1743,7 +1745,7 @@ describe('updatePublishedDoc - environment support', () => { mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(teamPublishedDoc); mockPrisma.team.findFirst.mockResolvedValueOnce({ id: 'team_1' } as any); - mockPrisma.teamEnvironment.findFirst.mockResolvedValueOnce(envData as any); + mockPrisma.teamEnvironment.findUnique.mockResolvedValueOnce(envData as any); mockPrisma.publishedDocs.update.mockResolvedValueOnce({ ...teamPublishedDoc, environmentID: 'team_env_1', @@ -1796,7 +1798,7 @@ describe('getPublishedDocBySlugPublic - environment support', () => { mockUserCollectionService.exportUserCollectionToJSONObject.mockResolvedValueOnce( E.right(collectionData as any), ); - mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(envData as any); + mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(envData as any); const result = await publishedDocsService.getPublishedDocBySlugPublic( 'slug-collection-1', @@ -1894,14 +1896,14 @@ describe('getPublishedDocBySlugPublic - environment support', () => { E.right(collectionData as any), ); // Environment not found — fetchEnvironment returns Left - mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(null); + mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(null); const result = await publishedDocsService.getPublishedDocBySlugPublic( 'slug-collection-1', '1.0.0', ); - expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT); + expect(result).toEqualLeft(USER_ENVIRONMENT_NOT_FOUND); }); test('should return null environment fields when no environment is associated', async () => { diff --git a/packages/hoppscotch-backend/src/published-docs/published-docs.service.ts b/packages/hoppscotch-backend/src/published-docs/published-docs.service.ts index 4b090c4de7c..d84e2399b7b 100644 --- a/packages/hoppscotch-backend/src/published-docs/published-docs.service.ts +++ b/packages/hoppscotch-backend/src/published-docs/published-docs.service.ts @@ -13,12 +13,14 @@ import { PUBLISHED_DOCS_CREATION_FAILED, PUBLISHED_DOCS_DELETION_FAILED, PUBLISHED_DOCS_INVALID_COLLECTION, - PUBLISHED_DOCS_INVALID_ENVIRONMENT, + PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS, PUBLISHED_DOCS_NOT_FOUND, PUBLISHED_DOCS_UPDATE_FAILED, + TEAM_ENVIRONMENT_NOT_FOUND, TEAM_INVALID_COLL_ID, TEAM_INVALID_ID, USER_COLL_NOT_FOUND, + USER_ENVIRONMENT_NOT_FOUND, } from 'src/errors'; import * as E from 'fp-ts/Either'; import { PublishedDocs, PublishedDocsVersion } from './published-docs.model'; @@ -100,22 +102,43 @@ export class PublishedDocsService { environmentID: string, workspaceType: WorkspaceType, workspaceID: string, - ): Promise> { + ): Promise> { + // TEAM workspace environment if (workspaceType === WorkspaceType.TEAM) { - const env = await this.prisma.teamEnvironment.findFirst({ - where: { id: environmentID, teamID: workspaceID }, + const env = await this.prisma.teamEnvironment.findUnique({ + where: { id: environmentID }, }); - if (!env) return E.left(PUBLISHED_DOCS_INVALID_ENVIRONMENT); - return E.right({ name: env.name, variables: env.variables }); - } else if (workspaceType === WorkspaceType.USER) { - const env = await this.prisma.userEnvironment.findFirst({ - where: { id: environmentID, userUid: workspaceID }, + if (!env) return E.left(TEAM_ENVIRONMENT_NOT_FOUND); + + // Validate environment exists and belongs to the correct team + if (env.teamID !== workspaceID) + return E.left(PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS); + + return E.right({ + name: env.name, + variables: env.variables, + }); + } + + // USER workspace environment + if (workspaceType === WorkspaceType.USER) { + const env = await this.prisma.userEnvironment.findUnique({ + where: { id: environmentID }, + }); + if (!env) return E.left(USER_ENVIRONMENT_NOT_FOUND); + + // Validate environment exists and belongs to the correct user + if (env.userUid !== workspaceID) { + return E.left(PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS); + } + + return E.right({ + name: env.name ?? '', + variables: env.variables, }); - if (!env) return E.left(PUBLISHED_DOCS_INVALID_ENVIRONMENT); - return E.right({ name: env.name ?? '', variables: env.variables }); } - return E.left(PUBLISHED_DOCS_INVALID_ENVIRONMENT); + return E.left(PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS); } /** @@ -368,10 +391,8 @@ export class PublishedDocsService { ); if (E.isLeft(envResult)) return E.left(envResult.left); - if (E.isRight(envResult) && envResult.right) { - environmentName = envResult.right.name; - environmentVariables = envResult.right.variables; - } + environmentName = envResult.right.name; + environmentVariables = envResult.right.variables; } docToReturn = { @@ -577,10 +598,9 @@ export class PublishedDocsService { workspaceID, ); if (E.isLeft(envResult)) return E.left(envResult.left); - if (envResult.right) { - environmentName = envResult.right.name; - environmentVariables = envResult.right.variables; - } + + environmentName = envResult.right.name; + environmentVariables = envResult.right.variables; } // Attempt to create the published document @@ -697,11 +717,10 @@ export class PublishedDocsService { publishedDocs.workspaceID, ); if (E.isLeft(envResult)) return E.left(envResult.left); - if (envResult.right) { - environmentID = args.environmentID; - environmentName = envResult.right.name; - environmentVariables = envResult.right.variables; - } + + environmentID = args.environmentID; + environmentName = envResult.right.name; + environmentVariables = envResult.right.variables; } } diff --git a/packages/hoppscotch-backend/src/team-collection/team-collection.service.ts b/packages/hoppscotch-backend/src/team-collection/team-collection.service.ts index ba9258de8e8..40a98e76dfa 100644 --- a/packages/hoppscotch-backend/src/team-collection/team-collection.service.ts +++ b/packages/hoppscotch-backend/src/team-collection/team-collection.service.ts @@ -569,23 +569,24 @@ export class TeamCollectionService { collection.parentID, ); - const deletedCollection = await tx.teamCollection.delete({ - where: { id: collection.id }, - }); - - // if collection is deleted, update siblings orderIndexes - // if collection was deleted before the transaction started (race condition), do not update siblings orderIndexes - if (deletedCollection) { - // update siblings orderIndexes - await tx.teamCollection.updateMany({ - where: { - teamID: collection.teamID, - parentID: collection.parentID, - orderIndex: orderIndexCondition, - }, - data: { orderIndex: dataCondition }, + try { + await tx.teamCollection.delete({ + where: { id: collection.id }, }); + } catch (deleteError) { + // P2025: Record not found — already deleted by a concurrent transaction + if (deleteError?.code === PrismaError.RECORD_NOT_FOUND) return; + throw deleteError; } + + await tx.teamCollection.updateMany({ + where: { + teamID: collection.teamID, + parentID: collection.parentID, + orderIndex: orderIndexCondition, + }, + data: { orderIndex: dataCondition }, + }); } catch (error) { throw new ConflictException(error); } @@ -749,12 +750,7 @@ export class TeamCollectionService { // Get collection details of collectionID const collection = await this.getCollection(collectionID, tx); if (E.isLeft(collection)) return E.left(collection.left); - // lock the rows of the collection and its siblings - await this.prisma.lockTeamCollectionByTeamAndParent( - tx, - collection.right.teamID, - collection.right.parentID, - ); + // destCollectionID == null i.e move collection to root if (!destCollectionID) { if (!collection.right.parentID) { @@ -763,6 +759,12 @@ export class TeamCollectionService { return E.left(TEAM_COL_ALREADY_ROOT); } + await this.prisma.lockTeamCollectionByTeamAndParent( + tx, + collection.right.teamID, + collection.right.parentID, + ); + // Change parent from child to root i.e child collection becomes a root collection // Move child collection into root and update orderIndexes for root teamCollections const updatedCollection = await this.changeParentAndUpdateOrderIndex( @@ -806,12 +808,41 @@ export class TeamCollectionService { return E.left(TEAM_COLL_IS_PARENT_COLL); } - // lock the rows of the destination collection and its siblings - await this.prisma.lockTeamCollectionByTeamAndParent( - tx, - destCollection.right.teamID, - destCollection.right.parentID, - ); + // Acquire locks in deterministic order (sorted by parentID) to prevent deadlocks + // when two concurrent moves happen in opposite directions + const srcParentID = collection.right.parentID ?? ''; + const destParentID = destCollection.right.parentID ?? ''; + const teamID = collection.right.teamID; + + if (srcParentID === destParentID) { + await this.prisma.lockTeamCollectionByTeamAndParent( + tx, + teamID, + collection.right.parentID, + ); + } else if (srcParentID < destParentID) { + await this.prisma.lockTeamCollectionByTeamAndParent( + tx, + teamID, + collection.right.parentID, + ); + await this.prisma.lockTeamCollectionByTeamAndParent( + tx, + teamID, + destCollection.right.parentID, + ); + } else { + await this.prisma.lockTeamCollectionByTeamAndParent( + tx, + teamID, + destCollection.right.parentID, + ); + await this.prisma.lockTeamCollectionByTeamAndParent( + tx, + teamID, + collection.right.parentID, + ); + } // Change parent from null to teamCollection i.e collection becomes a child collection // Move root/child collection into another child collection and update orderIndexes of the previous parent diff --git a/packages/hoppscotch-backend/src/team-request/team-request.service.ts b/packages/hoppscotch-backend/src/team-request/team-request.service.ts index 19275881934..13c0e90d4ac 100644 --- a/packages/hoppscotch-backend/src/team-request/team-request.service.ts +++ b/packages/hoppscotch-backend/src/team-request/team-request.service.ts @@ -20,6 +20,7 @@ import { TeamRequest as DbTeamRequest, } from 'src/generated/prisma/client'; import { SortOptions } from 'src/types/SortOptions'; +import { PrismaError } from 'src/prisma/prisma-error-codes'; @Injectable() export class TeamRequestService { @@ -124,21 +125,23 @@ export class TeamRequestService { dbTeamReq.collectionID, ]); - const deletedTeamRequest = await tx.teamRequest.delete({ - where: { id: requestID }, - }); - - // if request is deleted, update orderIndexes of siblings - // if request was deleted before the transaction started (race condition), do not update siblings orderIndexes - if (deletedTeamRequest) { - await tx.teamRequest.updateMany({ - where: { - collectionID: dbTeamReq.collectionID, - orderIndex: { gte: dbTeamReq.orderIndex }, - }, - data: { orderIndex: { decrement: 1 } }, + try { + await tx.teamRequest.delete({ + where: { id: requestID }, }); + } catch (deleteError) { + // P2025: Record not found — already deleted by a concurrent transaction + if (deleteError?.code === PrismaError.RECORD_NOT_FOUND) return; + throw deleteError; } + + await tx.teamRequest.updateMany({ + where: { + collectionID: dbTeamReq.collectionID, + orderIndex: { gte: dbTeamReq.orderIndex }, + }, + data: { orderIndex: { decrement: 1 } }, + }); } catch (error) { throw new ConflictException(error); } diff --git a/packages/hoppscotch-backend/src/types/InfraConfig.ts b/packages/hoppscotch-backend/src/types/InfraConfig.ts index 5877ffba59f..26713b7c142 100644 --- a/packages/hoppscotch-backend/src/types/InfraConfig.ts +++ b/packages/hoppscotch-backend/src/types/InfraConfig.ts @@ -27,6 +27,13 @@ export enum InfraConfigEnum { MAILER_TLS_REJECT_UNAUTHORIZED = 'MAILER_TLS_REJECT_UNAUTHORIZED', MAILER_SMTP_IGNORE_TLS = 'MAILER_SMTP_IGNORE_TLS', + MAILER_SMTP_AUTH_TYPE = 'MAILER_SMTP_AUTH_TYPE', + MAILER_SMTP_OAUTH2_USER = 'MAILER_SMTP_OAUTH2_USER', + MAILER_SMTP_OAUTH2_CLIENT_ID = 'MAILER_SMTP_OAUTH2_CLIENT_ID', + MAILER_SMTP_OAUTH2_CLIENT_SECRET = 'MAILER_SMTP_OAUTH2_CLIENT_SECRET', + MAILER_SMTP_OAUTH2_REFRESH_TOKEN = 'MAILER_SMTP_OAUTH2_REFRESH_TOKEN', + MAILER_SMTP_OAUTH2_ACCESS_URL = 'MAILER_SMTP_OAUTH2_ACCESS_URL', + GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID', GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET', GOOGLE_CALLBACK_URL = 'GOOGLE_CALLBACK_URL', diff --git a/packages/hoppscotch-backend/src/user-collection/user-collection.service.spec.ts b/packages/hoppscotch-backend/src/user-collection/user-collection.service.spec.ts index 405fe9ea66a..7fa2b58db56 100644 --- a/packages/hoppscotch-backend/src/user-collection/user-collection.service.spec.ts +++ b/packages/hoppscotch-backend/src/user-collection/user-collection.service.spec.ts @@ -2380,3 +2380,165 @@ describe('exportUserCollectionToJSONObject', () => { expect(result).toEqualLeft(USER_COLL_NOT_FOUND); }); }); + +describe('importCollectionsFromJSON — collection-level script fields', () => { + // The backend treats `data` as an opaque JSON blob, so the script fields + // ride through transparently. The test asserts on both ends: the create + // call payload must carry script fields (proving import wrote them), and + // the export payload must surface them unchanged. Guards against any + // future refactor that destructures `data` and drops scripts on either + // side. + test('preRequestScript and testScript on root and folder survive import → export round-trip', async () => { + const importJSON = JSON.stringify([ + { + name: 'root-with-scripts', + folders: [ + { + name: 'child-folder', + folders: [], + requests: [], + data: JSON.stringify({ + auth: { authType: 'inherit', authActive: true }, + headers: [], + variables: [], + preRequestScript: 'pw.env.set("FOLDER_RAN", "yes");', + testScript: 'pw.test("folder", () => {});', + }), + }, + ], + requests: [], + data: JSON.stringify({ + auth: { authType: 'none', authActive: false }, + headers: [], + variables: [], + preRequestScript: 'pw.env.set("ROOT_RAN", "yes");', + testScript: 'pw.test("root", () => {});', + }), + }, + ]); + + const rootRowId = 'imported-root-id'; + const folderRowId = 'imported-folder-id'; + + // Capture what generatePrismaQueryObj writes into Prisma so the export + // path sees the same blob shape the import wrote. + const rootDataAtCreate = { + auth: { authType: 'none', authActive: false }, + headers: [], + variables: [], + preRequestScript: 'pw.env.set("ROOT_RAN", "yes");', + testScript: 'pw.test("root", () => {});', + }; + const folderDataAtCreate = { + auth: { authType: 'inherit', authActive: true }, + headers: [], + variables: [], + preRequestScript: 'pw.env.set("FOLDER_RAN", "yes");', + testScript: 'pw.test("folder", () => {});', + }; + + mockPrisma.$transaction.mockImplementation(async (fn) => fn(mockPrisma)); + mockPrisma.lockUserCollectionByParent.mockResolvedValue(undefined); + mockPrisma.userCollection.findFirst.mockResolvedValueOnce(null); + mockPrisma.userCollection.create.mockResolvedValueOnce({ + id: rootRowId, + orderIndex: 1, + parentID: null, + title: 'root-with-scripts', + userUid: user.uid, + type: ReqType.REST, + createdOn: currentTime, + updatedOn: currentTime, + data: rootDataAtCreate, + }); + + // Export-side mocks: root resolves once, then its child folder resolves. + mockPrisma.userCollection.findUniqueOrThrow + .mockResolvedValueOnce({ + id: rootRowId, + orderIndex: 1, + parentID: null, + title: 'root-with-scripts', + userUid: user.uid, + type: ReqType.REST, + createdOn: currentTime, + updatedOn: currentTime, + data: rootDataAtCreate, + }) + .mockResolvedValueOnce({ + id: folderRowId, + orderIndex: 1, + parentID: rootRowId, + title: 'child-folder', + userUid: user.uid, + type: ReqType.REST, + createdOn: currentTime, + updatedOn: currentTime, + data: folderDataAtCreate, + }); + + mockPrisma.userCollection.findMany + .mockResolvedValueOnce([ + { + id: folderRowId, + orderIndex: 1, + parentID: rootRowId, + title: 'child-folder', + userUid: user.uid, + type: ReqType.REST, + createdOn: currentTime, + updatedOn: currentTime, + data: folderDataAtCreate, + }, + ]) + .mockResolvedValueOnce([]); + + mockPrisma.userRequest.findMany + .mockResolvedValueOnce([]) + .mockResolvedValueOnce([]); + + const result = await userCollectionService.importCollectionsFromJSON( + importJSON, + user.uid, + null, + ReqType.REST, + ); + + expect(E.isRight(result)).toBe(true); + + // Import side: `userCollection.create` must receive script fields inside + // its `data` payload (root) and inside `children.create[0].data` (folder). + // Asserting against the create call args proves import preserved scripts; + // export-side mocks alone would only round-trip the values we pre-loaded. + const createCallArg = mockPrisma.userCollection.create.mock.calls[0][0] + .data as any; + expect(createCallArg.data.preRequestScript).toBe( + 'pw.env.set("ROOT_RAN", "yes");', + ); + expect(createCallArg.data.testScript).toBe( + 'pw.test("root", () => {});', + ); + const childCreateArg = createCallArg.children.create[0]; + expect(childCreateArg.data.preRequestScript).toBe( + 'pw.env.set("FOLDER_RAN", "yes");', + ); + expect(childCreateArg.data.testScript).toBe( + 'pw.test("folder", () => {});', + ); + + if (E.isRight(result)) { + const exported = JSON.parse(result.right.exportedCollection); + // `data` is JSON-stringified by transformCollectionData on export. + const rootData = JSON.parse(exported[0].data); + const folderData = JSON.parse(exported[0].folders[0].data); + expect(rootData.preRequestScript).toBe( + 'pw.env.set("ROOT_RAN", "yes");', + ); + expect(rootData.testScript).toBe('pw.test("root", () => {});'); + expect(folderData.preRequestScript).toBe( + 'pw.env.set("FOLDER_RAN", "yes");', + ); + expect(folderData.testScript).toBe('pw.test("folder", () => {});'); + } + }); +}); diff --git a/packages/hoppscotch-backend/src/user-collection/user-collection.service.ts b/packages/hoppscotch-backend/src/user-collection/user-collection.service.ts index 4bc13c90084..87b180f73c1 100644 --- a/packages/hoppscotch-backend/src/user-collection/user-collection.service.ts +++ b/packages/hoppscotch-backend/src/user-collection/user-collection.service.ts @@ -520,23 +520,24 @@ export class UserCollectionService { collection.parentID, ); - const deletedCollection = await tx.userCollection.delete({ - where: { id: collection.id }, - }); - - // if collection is deleted, update siblings orderIndexes - // if collection was deleted before the transaction started (race condition), do not update siblings orderIndexes - if (deletedCollection) { - // update orderIndexes - await tx.userCollection.updateMany({ - where: { - userUid: collection.userUid, - parentID: collection.parentID, - orderIndex: orderIndexCondition, - }, - data: { orderIndex: dataCondition }, + try { + await tx.userCollection.delete({ + where: { id: collection.id }, }); + } catch (deleteError) { + // P2025: Record not found — already deleted by a concurrent transaction + if (deleteError?.code === PrismaError.RECORD_NOT_FOUND) return; + throw deleteError; } + + await tx.userCollection.updateMany({ + where: { + userUid: collection.userUid, + parentID: collection.parentID, + orderIndex: orderIndexCondition, + }, + data: { orderIndex: dataCondition }, + }); } catch (error) { throw new ConflictException(error); } @@ -596,6 +597,12 @@ export class UserCollectionService { return E.left(USER_COLL_ALREADY_ROOT); } + await this.prisma.lockUserCollectionByParent( + tx, + userID, + collection.right.parentID, + ); + // Change parent from child to root i.e child collection becomes a root collection // Move child collection into root and update orderIndexes for child userCollections const updatedCollection = await this.changeParentAndUpdateOrderIndex( @@ -643,7 +650,40 @@ export class UserCollectionService { return E.left(USER_COLL_IS_PARENT_COLL); } - // Change parent from null to teamCollection i.e collection becomes a child collection + // Acquire locks in deterministic order (sorted by parentID) to prevent deadlocks + const srcParentID = collection.right.parentID ?? ''; + const destParentID = destCollection.right.parentID ?? ''; + + if (srcParentID === destParentID) { + await this.prisma.lockUserCollectionByParent( + tx, + userID, + collection.right.parentID, + ); + } else if (srcParentID < destParentID) { + await this.prisma.lockUserCollectionByParent( + tx, + userID, + collection.right.parentID, + ); + await this.prisma.lockUserCollectionByParent( + tx, + userID, + destCollection.right.parentID, + ); + } else { + await this.prisma.lockUserCollectionByParent( + tx, + userID, + destCollection.right.parentID, + ); + await this.prisma.lockUserCollectionByParent( + tx, + userID, + collection.right.parentID, + ); + } + // Move root/child collection into another child collection and update orderIndexes of the previous parent const updatedCollection = await this.changeParentAndUpdateOrderIndex( tx, diff --git a/packages/hoppscotch-cli/package.json b/packages/hoppscotch-cli/package.json index cf749c1e205..e3e1ee6442d 100644 --- a/packages/hoppscotch-cli/package.json +++ b/packages/hoppscotch-cli/package.json @@ -1,6 +1,6 @@ { "name": "@hoppscotch/cli", - "version": "0.30.3", + "version": "0.31.0", "description": "A CLI to run Hoppscotch test scripts in CI environments.", "homepage": "https://hoppscotch.io", "type": "module", @@ -42,16 +42,16 @@ "private": false, "dependencies": { "aws4fetch": "1.0.20", - "axios": "1.13.6", + "axios": "1.15.2", "axios-cookiejar-support": "6.0.5", "chalk": "5.6.2", "commander": "14.0.3", "isolated-vm": "6.1.2", "js-md5": "0.8.3", "jsonc-parser": "3.3.1", - "lodash-es": "4.17.23", + "lodash-es": "4.18.1", "papaparse": "5.5.3", - "qs": "6.15.0", + "qs": "6.15.1", "tough-cookie": "6.0.1", "verzod": "0.4.0", "xmlbuilder2": "4.0.3", @@ -65,11 +65,10 @@ "@types/papaparse": "5.5.2", "@types/qs": "6.15.0", "fp-ts": "2.16.11", - "prettier": "3.8.1", - "qs": "6.11.2", + "prettier": "3.8.3", "semver": "7.7.4", "tsup": "8.5.1", "typescript": "5.9.3", - "vitest": "4.1.2" + "vitest": "4.1.5" } } diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts b/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts index afdb5e6d0bd..42f7df625cd 100644 --- a/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts +++ b/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts @@ -539,6 +539,21 @@ describe("hopp test [options] ", { timeout: 100000 }, () => { // Clean up fs.unlinkSync(junitPath); }, 600000); // 600 second (10 minute) timeout + + test("Inherited collection-level scripts run in order across both sandboxes", async () => { + const args = `test ${getTestJsonFilePath( + "collection-level-scripts-coll.json", + "collection" + )}`; + + const defaultResult = await runCLIWithNetworkRetry(args); + if (defaultResult === null) return; + expect(defaultResult.error).toBeNull(); + + const legacyResult = await runCLIWithNetworkRetry(`${args} --legacy-sandbox`); + if (legacyResult === null) return; + expect(legacyResult.error).toBeNull(); + }); }); describe("Test `hopp test --env ` command:", () => { diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-scripts-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-scripts-coll.json new file mode 100644 index 00000000000..38bae83959e --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-scripts-coll.json @@ -0,0 +1,114 @@ +{ + "v": 12, + "name": "collection-level-scripts-coll", + "variables": [], + "description": null, + "folders": [ + { + "v": 12, + "name": "target-folder", + "variables": [], + "description": null, + "folders": [], + "requests": [ + { + "v": "17", + "id": "cl-script-req-1", + "name": "target-request", + "method": "GET", + "endpoint": "https://echo.hoppscotch.io", + "params": [], + "headers": [], + "preRequestScript": "pw.env.set(\"REQ_RAN\", \"yes\");\npw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->target-req\");", + "testScript": "pw.env.set(\"TEST_ORDER\", \"target-req\");\npw.env.set(\"ORDER_AT_REQ\", pw.env.get(\"TEST_ORDER\"));\npw.test(\"pre-script cascade ran in root->target-folder->target-req order\", () => {\n pw.expect(pw.env.get(\"PRE_ORDER\")).toBe(\"root->target-folder->target-req\");\n});\npw.test(\"all cascade pre-scripts committed env vars\", () => {\n pw.expect(pw.env.get(\"ROOT_RAN\")).toBe(\"yes\");\n pw.expect(pw.env.get(\"TARGET_FOLDER_RAN\")).toBe(\"yes\");\n pw.expect(pw.env.get(\"REQ_RAN\")).toBe(\"yes\");\n});\npw.test(\"request-level test observed request position in test-cascade\", () => {\n pw.expect(pw.env.get(\"ORDER_AT_REQ\")).toBe(\"target-req\");\n});", + "auth": { + "authType": "inherit", + "authActive": true + }, + "body": { + "contentType": null, + "body": null + }, + "requestVariables": [], + "responses": {}, + "description": null + }, + { + "v": "17", + "id": "cl-script-req-2", + "name": "sibling-request-in-target-folder", + "method": "GET", + "endpoint": "https://echo.hoppscotch.io", + "params": [], + "headers": [], + "preRequestScript": "pw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->sibling-req-in-target\");", + "testScript": "pw.env.set(\"TEST_ORDER\", \"sibling-req-in-target\");\npw.test(\"sibling request cascade is root->target-folder->this-request\", () => {\n pw.expect(pw.env.get(\"PRE_ORDER\")).toBe(\"root->target-folder->sibling-req-in-target\");\n});", + "auth": { + "authType": "inherit", + "authActive": true + }, + "body": { + "contentType": null, + "body": null + }, + "requestVariables": [], + "responses": {}, + "description": null + } + ], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "preRequestScript": "pw.env.set(\"TARGET_FOLDER_RAN\", \"yes\");\npw.env.set(\"TARGET_FOLDER_RUN_COUNT\", String((parseInt(pw.env.get(\"TARGET_FOLDER_RUN_COUNT\") || \"0\", 10)) + 1));\npw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->target-folder\");", + "testScript": "pw.env.set(\"TEST_ORDER\", pw.env.get(\"TEST_ORDER\") + \"->target-folder\");\npw.env.set(\"ORDER_AT_TARGET_FOLDER\", pw.env.get(\"TEST_ORDER\"));" + }, + { + "v": 12, + "name": "sibling-folder", + "variables": [], + "description": null, + "folders": [], + "requests": [ + { + "v": "17", + "id": "cl-script-req-3", + "name": "sibling-request-in-sibling-folder", + "method": "GET", + "endpoint": "https://echo.hoppscotch.io", + "params": [], + "headers": [], + "preRequestScript": "pw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->sibling-req-in-sibling\");", + "testScript": "pw.env.set(\"TEST_ORDER\", \"sibling-req-in-sibling\");\npw.test(\"sibling-folder cascade is root->sibling-folder->this-request (no target-folder leak)\", () => {\n pw.expect(pw.env.get(\"PRE_ORDER\")).toBe(\"root->sibling-folder->sibling-req-in-sibling\");\n});\npw.test(\"target-folder pre-script ran exactly twice (one per request in target-folder)\", () => {\n pw.expect(pw.env.get(\"TARGET_FOLDER_RUN_COUNT\")).toBe(\"2\");\n});", + "auth": { + "authType": "inherit", + "authActive": true + }, + "body": { + "contentType": null, + "body": null + }, + "requestVariables": [], + "responses": {}, + "description": null + } + ], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "preRequestScript": "pw.env.set(\"SIBLING_FOLDER_RAN\", \"yes\");\npw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->sibling-folder\");", + "testScript": "pw.env.set(\"TEST_ORDER\", pw.env.get(\"TEST_ORDER\") + \"->sibling-folder\");" + } + ], + "requests": [], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "preRequestScript": "pw.env.set(\"ROOT_RAN\", \"yes\");\npw.env.set(\"PRE_ORDER\", \"root\");", + "testScript": "pw.env.set(\"TEST_ORDER\", pw.env.get(\"TEST_ORDER\") + \"->root\");\npw.test(\"test-script cascade ran in request->folder->root order for every request\", () => {\n pw.expect([\"target-req->target-folder->root\", \"sibling-req-in-target->target-folder->root\", \"sibling-req-in-sibling->sibling-folder->root\"].includes(pw.env.get(\"TEST_ORDER\"))).toBe(true);\n});" +} diff --git a/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts b/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts index cf11cf0722c..774be70e797 100644 --- a/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts +++ b/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts @@ -144,6 +144,8 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_M headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -192,6 +194,8 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_M }, ], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -224,6 +228,8 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_M headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -273,6 +279,8 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_M }, ], description: null, + preRequestScript: "", + testScript: "", }, ]; @@ -513,12 +521,12 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp name: "Multiple child collections with authorization, headers and variables set at each level", folders: [ { - v: 11, + v: CollectionSchemaVersion, id: "clx1fjgah000110f8a5bs68gd", name: "folder-1", folders: [ { - v: 11, + v: CollectionSchemaVersion, id: "clx1fjwmm000410f8l1gkkr1a", name: "folder-11", folders: [], @@ -567,9 +575,11 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1fjyxm000510f8pv90dt43", name: "folder-12", folders: [], @@ -634,9 +644,11 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1fk1cv000610f88kc3aupy", name: "folder-13", folders: [], @@ -719,6 +731,8 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -764,14 +778,16 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1fjk9o000210f8j0573pls", name: "folder-2", folders: [ { - v: 11, + v: CollectionSchemaVersion, id: "clx1fk516000710f87sfpw6bo", name: "folder-21", folders: [], @@ -818,9 +834,11 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1fk72t000810f8gfwkpi5y", name: "folder-22", folders: [], @@ -885,9 +903,11 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1fk95g000910f8bunhaoo8", name: "folder-23", folders: [], @@ -957,6 +977,8 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -1008,15 +1030,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1fjmlq000310f86o4d3w2o", name: "folder-3", folders: [ { - v: 11, + v: CollectionSchemaVersion, id: "clx1iwq0p003e10f8u8zg0p85", name: "folder-31", folders: [], @@ -1063,9 +1087,11 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1izut7003m10f894ip59zg", name: "folder-32", folders: [], @@ -1130,9 +1156,11 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, { - v: 11, + v: CollectionSchemaVersion, id: "clx1j2ka9003q10f8cdbzpgpg", name: "folder-33", folders: [], @@ -1202,6 +1230,8 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -1266,6 +1296,8 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [ @@ -1321,6 +1353,8 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp }, ], description: null, + preRequestScript: "", + testScript: "", }, ]; @@ -1428,6 +1462,8 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_L headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }, { v: CollectionSchemaVersion, @@ -1476,6 +1512,8 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_L }, ], description: null, + preRequestScript: "", + testScript: "", }, { v: CollectionSchemaVersion, @@ -1490,6 +1528,8 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_L headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }, { v: CollectionSchemaVersion, @@ -1518,6 +1558,8 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_L }, ], description: null, + preRequestScript: "", + testScript: "", }, ], requests: [], @@ -1528,6 +1570,8 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_L headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }, ]; diff --git a/packages/hoppscotch-cli/src/__tests__/unit/pre-request-inheritance.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/pre-request-inheritance.spec.ts new file mode 100644 index 00000000000..d101b44c637 --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/unit/pre-request-inheritance.spec.ts @@ -0,0 +1,216 @@ +import { describe, expect, test } from "vitest"; +import { makeRESTRequest } from "@hoppscotch/data"; +import * as E from "fp-ts/Either"; + +import { preRequestScriptRunner } from "../../utils/pre-request"; +import { HoppEnvs } from "../../types/request"; + +const SAMPLE_ENVS: HoppEnvs = { + global: [], + selected: [], +}; + +const SAMPLE_REQUEST = makeRESTRequest({ + name: "request", + method: "GET", + endpoint: "https://example.com", + params: [], + headers: [], + preRequestScript: "", + testScript: "", + auth: { authActive: false, authType: "none" }, + body: { + contentType: null, + body: null, + }, + requestVariables: [], + description: null, + responses: {}, +}); + +describe("preRequestScriptRunner - inheritance", () => { + test("Inherited scripts execute in root → parent → request order", async () => { + const rootScript = `pw.env.set("ORDER", "root");`; + const parentScript = ` + const prev = pw.env.get("ORDER"); + pw.env.set("ORDER", prev + ",parent"); + `; + const request = makeRESTRequest({ + ...SAMPLE_REQUEST, + preRequestScript: ` + const prev = pw.env.get("ORDER"); + pw.env.set("ORDER", prev + ",request"); + `, + }); + + const result = await preRequestScriptRunner( + request, + SAMPLE_ENVS, + false, + undefined, + [rootScript, parentScript] + )(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const orderVar = result.right.updatedEnvs.selected.find( + (v) => v.key === "ORDER" + ); + expect(orderVar?.currentValue).toBe("root,parent,request"); + } + }); + + test("Inherited scripts set ENVs used in request endpoint resolution", async () => { + const rootScript = `pw.env.set("ENDPOINT", "https://example.com");`; + + const request = makeRESTRequest({ + ...SAMPLE_REQUEST, + endpoint: "<>", + preRequestScript: "", + }); + + const result = await preRequestScriptRunner( + request, + SAMPLE_ENVS, + false, + undefined, + [rootScript] + )(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + expect(result.right.effectiveRequest.effectiveFinalURL).toBe( + "https://example.com" + ); + } + }); + + test("Scripts with same local variable names do not collide (IIFE isolation)", async () => { + const rootScript = `const x = "root"; pw.env.set("ROOT_VAR", x);`; + const parentScript = `const x = "parent"; pw.env.set("PARENT_VAR", x);`; + + const request = makeRESTRequest({ + ...SAMPLE_REQUEST, + preRequestScript: `const x = "request"; pw.env.set("REQUEST_VAR", x);`, + }); + + const result = await preRequestScriptRunner( + request, + SAMPLE_ENVS, + false, + undefined, + [rootScript, parentScript] + )(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const envVars = result.right.updatedEnvs.selected; + expect(envVars.find((v) => v.key === "ROOT_VAR")?.currentValue).toBe( + "root" + ); + expect(envVars.find((v) => v.key === "PARENT_VAR")?.currentValue).toBe( + "parent" + ); + expect(envVars.find((v) => v.key === "REQUEST_VAR")?.currentValue).toBe( + "request" + ); + } + }); + + test("Empty inherited scripts are filtered out gracefully", async () => { + const validScript = `pw.env.set("ENDPOINT", "https://example.com");`; + + const request = makeRESTRequest({ + ...SAMPLE_REQUEST, + endpoint: "<>", + preRequestScript: "", + }); + + const result = await preRequestScriptRunner( + request, + SAMPLE_ENVS, + false, + undefined, + ["", " ", validScript, "\n"] + )(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + expect(result.right.effectiveRequest.effectiveFinalURL).toBe( + "https://example.com" + ); + } + }); + + test("Works correctly with no inherited scripts (backward compatibility)", async () => { + const request = makeRESTRequest({ + ...SAMPLE_REQUEST, + endpoint: "<>", + preRequestScript: `pw.env.set("ENDPOINT", "https://example.com");`, + }); + + const result = await preRequestScriptRunner( + request, + SAMPLE_ENVS, + false, + undefined, + [] + )(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + expect(result.right.effectiveRequest.effectiveFinalURL).toBe( + "https://example.com" + ); + } + }); + + // Regression: in the legacy (isolated-vm) sandbox, inherited scripts must + // execute sequentially in order. Pre-fix combineScriptsWithIIFE emitted an + // outer detached Promise that script.run did not await; sequential ordering + // was undefined. + // + // Note: the unit test exercises the sequential-ordering path. The + // post-`await` drop only surfaces with macrotask awaits (setTimeout) or + // cross-isolate Reference calls returning Promises — neither is exposed + // through the synchronous `pw.*` surface in node/legacy.ts, so it is not + // currently user-reachable in the CLI. The web worker path is where the + // post-`await` drop is user-reachable; covered by the smoke fixture in + // packages/hoppscotch-cli/src/__tests__/e2e/. + test("Legacy sandbox executes inherited scripts in order", async () => { + const rootScript = `pw.env.set("ORDER", "root");`; + const parentScript = ` + const prev = pw.env.get("ORDER"); + pw.env.set("ORDER", prev + ",parent"); + `; + const request = makeRESTRequest({ + ...SAMPLE_REQUEST, + preRequestScript: ` + const prev = pw.env.get("ORDER"); + pw.env.set("ORDER", prev + ",request"); + `, + }); + + const result = await preRequestScriptRunner( + request, + SAMPLE_ENVS, + true, + undefined, + [rootScript, parentScript] + )(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const orderVar = result.right.updatedEnvs.selected.find( + (v) => v.key === "ORDER" + ); + expect(orderVar?.currentValue).toBe("root,parent,request"); + } + }); +}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/scripting.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/scripting.spec.ts new file mode 100644 index 00000000000..a2aa4d46a89 --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/unit/scripting.spec.ts @@ -0,0 +1,168 @@ +import { describe, expect, test } from "vitest"; + +import { + combineScriptsWithIIFE, + stripModulePrefix, + MODULE_PREFIX, +} from "../../utils/scripting"; + +describe("scripting", () => { + describe("stripModulePrefix", () => { + test("strips 'export {};\\n' prefix", () => { + expect(stripModulePrefix("export {};\nconst x = 1;")).toBe( + "const x = 1;" + ); + }); + + test("strips 'export {};' prefix without newline", () => { + expect(stripModulePrefix("export {};const x = 1;")).toBe("const x = 1;"); + }); + + test("returns script unchanged if no prefix", () => { + expect(stripModulePrefix("const x = 1;")).toBe("const x = 1;"); + }); + + test("returns empty string unchanged", () => { + expect(stripModulePrefix("")).toBe(""); + }); + }); + + describe("combineScriptsWithIIFE", () => { + test("returns empty string for empty array", () => { + expect(combineScriptsWithIIFE([])).toBe(""); + }); + + test("returns empty string when all scripts are empty", () => { + expect(combineScriptsWithIIFE(["", " ", "\n"])).toBe(""); + }); + + test("wraps a single script in a sequential async IIFE", () => { + const result = combineScriptsWithIIFE(["const x = 1;"]); + + expect(result).toContain("async"); + expect(result).toContain("await"); + expect(result).toContain("const x = 1;"); + }); + + test("preserves script order (root → parent → child → request) for pre-request scripts", () => { + const rootScript = 'pw.env.set("token", "root");'; + const parentScript = 'pw.env.set("parent", "true");'; + const requestScript = 'pw.env.set("request", "true");'; + + const result = combineScriptsWithIIFE([ + rootScript, + parentScript, + requestScript, + ]); + + const rootIndex = result.indexOf(rootScript); + const parentIndex = result.indexOf(parentScript); + const requestIndex = result.indexOf(requestScript); + + expect(rootIndex).toBeLessThan(parentIndex); + expect(parentIndex).toBeLessThan(requestIndex); + }); + + test("preserves script order (request → child → parent → root) for test scripts", () => { + const requestScript = 'pw.test("request test", () => {});'; + const childScript = 'pw.test("child test", () => {});'; + const rootScript = 'pw.test("root test", () => {});'; + + // Simulates the reversal pattern used in test runner: + // combineScriptsWithIIFE([requestScript, ...inheritedTestScripts.slice().reverse()]) + const inheritedTestScripts = [rootScript, childScript]; + const result = combineScriptsWithIIFE([ + requestScript, + ...inheritedTestScripts.slice().reverse(), + ]); + + const requestIndex = result.indexOf(requestScript); + const childIndex = result.indexOf(childScript); + const rootIndex = result.indexOf(rootScript); + + expect(requestIndex).toBeLessThan(childIndex); + expect(childIndex).toBeLessThan(rootIndex); + }); + + test("filters out empty scripts while preserving non-empty ones", () => { + const script1 = "const a = 1;"; + const script2 = "const b = 2;"; + + const result = combineScriptsWithIIFE([script1, "", " ", script2]); + + expect(result).toContain(script1); + expect(result).toContain(script2); + + // Should only have 2 await statements (not 4) + const awaitCount = (result.match(/await/g) || []).length; + expect(awaitCount).toBe(2); + }); + + test("isolates variable scope between scripts (each wrapped in its own function)", () => { + const script1 = "const x = 1;"; + const script2 = "const x = 2;"; + + const result = combineScriptsWithIIFE([script1, script2]); + + // Both scripts should appear in separate async functions + const fnCount = (result.match(/async function\(\)/g) || []).length; + expect(fnCount).toBe(2); + }); + + test("strips module prefix from scripts before wrapping", () => { + const script = `${MODULE_PREFIX}const x = 1;`; + + const result = combineScriptsWithIIFE([script]); + + // The module prefix should be stripped + expect(result).not.toContain("export {};"); + expect(result).toContain("const x = 1;"); + }); + + test("experimental target generates sequential await chain wrapped in try/catch", () => { + const result = combineScriptsWithIIFE( + ["const a = 1;", "const b = 2;", "const c = 3;"], + "experimental" + ); + + // Outer wrapper captures the reporter lexically so user code that + // deletes the globalThis property cannot suppress error reporting. + expect(result).toMatch( + /^const __hoppReporter = globalThis\.__hoppReportScriptExecutionError;\s*try \{/ + ); + expect(result).toContain("await (async function() {"); + // Each script contributes one `await` in the body. + const awaitCount = (result.match(/\bawait\b/g) || []).length; + expect(awaitCount).toBe(3); + // Catch hands the error to the lexically captured reporter. + expect(result).toContain( + "} catch (__hoppScriptExecutionError) {" + ); + expect(result).toContain("__hoppReporter(__hoppScriptExecutionError);"); + }); + + test("legacy target generates sync IIFE chain with no await", () => { + const result = combineScriptsWithIIFE( + ["const a = 1;", "const b = 2;", "const c = 3;"], + "legacy" + ); + + // No `async` keyword, no `await` — legacy sandbox is sync-only. + expect(result).not.toContain("async"); + expect(result).not.toContain("await"); + // Leading `;` guards against ASI on the host script. + expect(result).toMatch(/^;\(function\(\) \{/); + // Each script wrapped in its own IIFE + const iifeCount = (result.match(/\.call\(this\);/g) || []).length; + expect(iifeCount).toBe(3); + }); + + test("default target is experimental (wrapped in try/catch)", () => { + const result = combineScriptsWithIIFE(["const x = 1;"]); + expect(result).toMatch( + /^const __hoppReporter = globalThis\.__hoppReportScriptExecutionError;\s*try \{/ + ); + expect(result).toContain("await (async function() {"); + }); + }); +}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/test-runner-inheritance.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/test-runner-inheritance.spec.ts new file mode 100644 index 00000000000..9e371aa7afc --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/unit/test-runner-inheritance.spec.ts @@ -0,0 +1,234 @@ +import { describe, expect, test } from "vitest"; +import { makeRESTRequest } from "@hoppscotch/data"; +import * as E from "fp-ts/Either"; + +import { testRunner } from "../../utils/test"; +import { HoppEnvs } from "../../types/request"; + +const SAMPLE_ENVS: HoppEnvs = { + global: [], + selected: [], +}; + +const SAMPLE_RESPONSE = { + status: 200, + headers: [], + body: {}, + statusText: "OK", + responseTime: 100, +}; + +const SAMPLE_REQUEST = makeRESTRequest({ + name: "request", + method: "GET", + endpoint: "https://example.com", + params: [], + headers: [], + preRequestScript: "", + testScript: "", + auth: { authActive: false, authType: "none" }, + body: { + contentType: null, + body: null, + }, + requestVariables: [], + description: null, + responses: {}, +}); + +describe("testRunner - inheritance", () => { + test("Inherited test scripts are executed and register test cases", async () => { + const rootTestScript = ` + pw.test("Root collection test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `; + + const result = await testRunner({ + request: makeRESTRequest({ + ...SAMPLE_REQUEST, + testScript: ` + pw.test("Request test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `, + }), + envs: SAMPLE_ENVS, + response: SAMPLE_RESPONSE, + legacySandbox: false, + inheritedTestScripts: [rootTestScript], + })(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const { testsReport } = result.right; + const descriptors = testsReport.map((r) => r.descriptor); + + expect(descriptors).toContain("Request test"); + expect(descriptors).toContain("Root collection test"); + } + }); + + test("Inherited test scripts execute in request → child → parent → root order", async () => { + const rootTestScript = ` + const prev = pw.env.get("ORDER"); + pw.env.set("ORDER", prev + ",root"); + `; + const parentTestScript = ` + const prev = pw.env.get("ORDER"); + pw.env.set("ORDER", prev + ",parent"); + `; + + const result = await testRunner({ + request: makeRESTRequest({ + ...SAMPLE_REQUEST, + testScript: `pw.env.set("ORDER", "request");`, + }), + envs: SAMPLE_ENVS, + response: SAMPLE_RESPONSE, + legacySandbox: false, + // Stored as root → parent, reversed to parent → root during execution + inheritedTestScripts: [rootTestScript, parentTestScript], + })(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const orderVar = result.right.envs.selected.find( + (v) => v.key === "ORDER" + ); + expect(orderVar?.currentValue).toBe("request,parent,root"); + } + }); + + test("Scripts with same local variable names do not collide (IIFE isolation)", async () => { + const rootTestScript = `const x = "root"; pw.env.set("ROOT_VAR", x);`; + const parentTestScript = `const x = "parent"; pw.env.set("PARENT_VAR", x);`; + + const result = await testRunner({ + request: makeRESTRequest({ + ...SAMPLE_REQUEST, + testScript: `const x = "request"; pw.env.set("REQUEST_VAR", x);`, + }), + envs: SAMPLE_ENVS, + response: SAMPLE_RESPONSE, + legacySandbox: false, + inheritedTestScripts: [rootTestScript, parentTestScript], + })(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const envVars = result.right.envs.selected; + expect(envVars.find((v) => v.key === "ROOT_VAR")?.currentValue).toBe( + "root" + ); + expect(envVars.find((v) => v.key === "PARENT_VAR")?.currentValue).toBe( + "parent" + ); + expect(envVars.find((v) => v.key === "REQUEST_VAR")?.currentValue).toBe( + "request" + ); + } + }); + + test("Empty inherited test scripts are filtered out gracefully", async () => { + const validScript = ` + pw.test("Valid inherited test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `; + + const result = await testRunner({ + request: makeRESTRequest({ + ...SAMPLE_REQUEST, + testScript: ` + pw.test("Request test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `, + }), + envs: SAMPLE_ENVS, + response: SAMPLE_RESPONSE, + legacySandbox: false, + inheritedTestScripts: ["", " ", validScript, "\n"], + })(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const { testsReport } = result.right; + const descriptors = testsReport.map((r) => r.descriptor); + + expect(descriptors).toContain("Request test"); + expect(descriptors).toContain("Valid inherited test"); + } + }); + + test("Works correctly with no inherited test scripts (backward compatibility)", async () => { + const result = await testRunner({ + request: makeRESTRequest({ + ...SAMPLE_REQUEST, + testScript: ` + pw.test("Solo request test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `, + }), + envs: SAMPLE_ENVS, + response: SAMPLE_RESPONSE, + legacySandbox: false, + inheritedTestScripts: [], + })(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const { testsReport } = result.right; + expect(testsReport.map((r) => r.descriptor)).toContain( + "Solo request test" + ); + } + }); + + // Regression: in the legacy (isolated-vm) sandbox, all `pw.test` blocks + // declared in inherited test scripts must register before the runner + // captures results. Pre-fix combineScriptsWithIIFE emitted an outer + // detached Promise so the registration order was undefined when multiple + // inherited scripts were present. + // + // Note: the post-`await` drop is not currently user-reachable here either + // (see pre-request-inheritance.spec.ts for context). User-facing coverage + // for the web worker async path is in packages/hoppscotch-cli/src/__tests__/e2e/. + test("Legacy sandbox registers inherited test scripts", async () => { + const rootTestScript = ` + pw.test("Root collection test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `; + + const result = await testRunner({ + request: makeRESTRequest({ + ...SAMPLE_REQUEST, + testScript: ` + pw.test("Request test", () => { + pw.expect(pw.response.status).toBe(200); + }); + `, + }), + envs: SAMPLE_ENVS, + response: SAMPLE_RESPONSE, + legacySandbox: true, + inheritedTestScripts: [rootTestScript], + })(); + + expect(result).toBeRight(); + + if (E.isRight(result)) { + const descriptors = result.right.testsReport.map((r) => r.descriptor); + expect(descriptors).toContain("Request test"); + expect(descriptors).toContain("Root collection test"); + } + }); +}); diff --git a/packages/hoppscotch-cli/src/interfaces/response.ts b/packages/hoppscotch-cli/src/interfaces/response.ts index 2ce16f2150c..aa426af8eb4 100644 --- a/packages/hoppscotch-cli/src/interfaces/response.ts +++ b/packages/hoppscotch-cli/src/interfaces/response.ts @@ -39,12 +39,14 @@ export interface RequestRunnerResponse extends TestResponse { * @property {TestResponse} response Response structure for test script runner. * @property {HoppEnvs} envs Environment variables for test script runner. * @property {boolean} legacySandbox Whether to use the legacy sandbox. + * @property {string[]} inheritedTestScripts Test scripts inherited from parent collections. */ export interface TestScriptParams { request: HoppRESTRequest; response: TestResponse; envs: HoppEnvs; legacySandbox: boolean; + inheritedTestScripts?: string[]; } /** diff --git a/packages/hoppscotch-cli/src/types/request.ts b/packages/hoppscotch-cli/src/types/request.ts index 023f86e9324..1aaca15c512 100644 --- a/packages/hoppscotch-cli/src/types/request.ts +++ b/packages/hoppscotch-cli/src/types/request.ts @@ -44,4 +44,6 @@ export type ProcessRequestParams = { delay: number; legacySandbox?: boolean; collectionVariables?: HoppCollectionVariable[]; + inheritedPreRequestScripts?: string[]; + inheritedTestScripts?: string[]; }; diff --git a/packages/hoppscotch-cli/src/utils/collections.ts b/packages/hoppscotch-cli/src/utils/collections.ts index 124b0471dc9..313e957ed7b 100644 --- a/packages/hoppscotch-cli/src/utils/collections.ts +++ b/packages/hoppscotch-cli/src/utils/collections.ts @@ -34,6 +34,7 @@ import { processRequest, } from "./request"; import { getTestMetrics } from "./test"; +import { filterValidScripts } from "./scripting"; const { WARN, FAIL, INFO } = exceptionColors; @@ -109,8 +110,21 @@ const processCollection = async ( envs: HoppEnvs, delay: number, requestsReport: RequestReport[], - legacySandbox?: boolean + legacySandbox?: boolean, + ancestorPreRequestScripts: string[] = [], + ancestorTestScripts: string[] = [] ) => { + // Accumulate scripts from root -> current collection for inheritance + // filterValidScripts strips empty, whitespace-only, and module-prefix-only scripts + const inheritedPreRequestScripts = filterValidScripts([ + ...ancestorPreRequestScripts, + collection.preRequestScript, + ]); + const inheritedTestScripts = filterValidScripts([ + ...ancestorTestScripts, + collection.testScript, + ]); + // Process each request in the collection for (const request of collection.requests) { const _request = preProcessRequest(request as HoppRESTRequest, collection); @@ -127,6 +141,8 @@ const processCollection = async ( delay, legacySandbox, collectionVariables, + inheritedPreRequestScripts, + inheritedTestScripts, }; // Request processing initiated message. @@ -188,7 +204,9 @@ const processCollection = async ( envs, delay, requestsReport, - legacySandbox + legacySandbox, + inheritedPreRequestScripts, + inheritedTestScripts ); } }; diff --git a/packages/hoppscotch-cli/src/utils/mutators.ts b/packages/hoppscotch-cli/src/utils/mutators.ts index 5348ba17d41..245486cd174 100644 --- a/packages/hoppscotch-cli/src/utils/mutators.ts +++ b/packages/hoppscotch-cli/src/utils/mutators.ts @@ -9,6 +9,9 @@ import { FormDataEntry } from "../types/request"; import { isHoppErrnoException } from "./checks"; import { getResourceContents } from "./getters"; +// Re-export from the canonical implementation in scripting.ts +export { stripModulePrefix } from "./scripting"; + const getValidRequests = ( collections: HoppCollection[], collectionFilePath: string @@ -158,19 +161,3 @@ export async function parseCollectionData( return getValidRequests(collectionSchemaParsedResult.data, pathOrId); } - -/** - * Module prefix added by Monaco editor for TypeScript module mode. - */ -const MODULE_PREFIX = "export {};\n" as const; - -/** - * Strips `export {};\n` prefix from scripts before sandbox execution. - * The prefix is added by the web app's Monaco editor for IntelliSense - * and must be removed before execution. - */ -export const stripModulePrefix = (script: string): string => { - return script.startsWith(MODULE_PREFIX) - ? script.slice(MODULE_PREFIX.length) - : script; -}; diff --git a/packages/hoppscotch-cli/src/utils/pre-request.ts b/packages/hoppscotch-cli/src/utils/pre-request.ts index dea46d10383..283f3721519 100644 --- a/packages/hoppscotch-cli/src/utils/pre-request.ts +++ b/packages/hoppscotch-cli/src/utils/pre-request.ts @@ -35,13 +35,17 @@ import { isHoppCLIError } from "./checks"; import { arrayFlatMap, arraySort, tupleToRecord } from "./functions/array"; import { getEffectiveFinalMetaData, getResolvedVariables } from "./getters"; import { stripComments } from "./jsonc"; -import { stripModulePrefix, toFormData } from "./mutators"; +import { toFormData } from "./mutators"; +import { combineScriptsWithIIFE, filterValidScripts } from "./scripting"; /** * Runs pre-request-script runner over given request which extracts set ENVs and * applies them on current request to generate updated request. * @param request HoppRESTRequest to be converted to EffectiveHoppRESTRequest. * @param envs Environment variables related to request. + * @param legacySandbox Whether to use the legacy sandbox. + * @param collectionVariables Collection variables to use. + * @param inheritedPreRequestScripts Pre-request scripts inherited from parent collections. * @returns EffectiveHoppRESTRequest that includes parsed ENV variables with in * request OR HoppCLIError with error code and related information. */ @@ -49,7 +53,8 @@ export const preRequestScriptRunner = ( request: HoppRESTRequest, envs: HoppEnvs, legacySandbox: boolean, - collectionVariables?: HoppCollectionVariable[] + collectionVariables?: HoppCollectionVariable[], + inheritedPreRequestScripts: string[] = [] ): TE.TaskEither< HoppCLIError, { effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs } @@ -57,10 +62,19 @@ export const preRequestScriptRunner = ( const experimentalScriptingSandbox = !legacySandbox; const hoppFetchHook = createHoppFetchHook(); + // Pre-request order: root → request. + const combinedScript = combineScriptsWithIIFE( + filterValidScripts([ + ...inheritedPreRequestScripts, + request.preRequestScript, + ]), + experimentalScriptingSandbox ? "experimental" : "legacy" + ); + return pipe( TE.of(request), - TE.chain(({ preRequestScript }) => - runPreRequestScript(stripModulePrefix(preRequestScript), { + TE.chain(() => + runPreRequestScript(combinedScript, { envs, experimentalScriptingSandbox, request, diff --git a/packages/hoppscotch-cli/src/utils/request.ts b/packages/hoppscotch-cli/src/utils/request.ts index d2ac8a7941e..3c42dd3850f 100644 --- a/packages/hoppscotch-cli/src/utils/request.ts +++ b/packages/hoppscotch-cli/src/utils/request.ts @@ -30,7 +30,7 @@ import { } from "./display"; import { getDurationInSeconds, getMetaDataPairs } from "./getters"; import { preRequestScriptRunner } from "./pre-request"; -import { getTestScriptParams, hasFailedTestCases, testRunner } from "./test"; +import { getTestScriptParams, hasAllTestsPassed, testRunner } from "./test"; /** * Processes given variable, which includes checking for secret variables @@ -232,8 +232,16 @@ export const processRequest = params: ProcessRequestParams ): T.Task<{ envs: HoppEnvs; report: RequestReport }> => async () => { - const { envs, path, request, delay, legacySandbox, collectionVariables } = - params; + const { + envs, + path, + request, + delay, + legacySandbox, + collectionVariables, + inheritedPreRequestScripts = [], + inheritedTestScripts = [], + } = params; // Initialising updatedEnvs with given parameter envs, will eventually get updated. const result = { @@ -258,17 +266,21 @@ export const processRequest = effectiveFinalParams: [], effectiveFinalURL: "", }; - let updatedEnvs = {}; // Fetch values for secret environment variables from system environment const processedEnvs = processEnvs(envs); - // Executing pre-request-script + // Default envs to the pre-script state so downstream consumers + // (test-runner, effectiveRequest builder) receive a well-shaped + // HoppEnvs even if the pre-request script fails. + let updatedEnvs: HoppEnvs = processedEnvs; + const preRequestRes = await preRequestScriptRunner( request, processedEnvs, legacySandbox ?? false, - collectionVariables + collectionVariables, + inheritedPreRequestScripts )(); if (E.isLeft(preRequestRes)) { printPreRequestRunner.fail(); @@ -317,12 +329,12 @@ export const processRequest = printRequestRunner.success(_requestRunnerRes); } - // Extracting test-script-runner parameters. const testScriptParams = getTestScriptParams( _requestRunnerRes, effectiveRequest, updatedEnvs, - legacySandbox ?? false + legacySandbox ?? false, + inheritedTestScripts ); // Executing test-runner. @@ -337,7 +349,7 @@ export const processRequest = report.result = false; } else { const { envs, testsReport, duration } = testRunnerRes.right; - const _hasFailedTestCases = hasFailedTestCases(testsReport); + const _allTestsPassed = hasAllTestsPassed(testsReport); // Check if any tests have uncaught runtime errors (e.g., ReferenceError, TypeError) // Don't include validation errors (they're reported as individual testcases) @@ -369,7 +381,7 @@ export const processRequest = // Updating report with current tests, result and duration. report.tests = testsReport; - report.result = report.result && _hasFailedTestCases; + report.result = report.result && _allTestsPassed; report.duration.test = duration; // Updating resulting envs from test-runner. diff --git a/packages/hoppscotch-cli/src/utils/scripting.ts b/packages/hoppscotch-cli/src/utils/scripting.ts new file mode 100644 index 00000000000..5b04271bf18 --- /dev/null +++ b/packages/hoppscotch-cli/src/utils/scripting.ts @@ -0,0 +1,71 @@ +/** + * Module prefix added by Monaco editor for TypeScript module mode. + * Enables IntelliSense and isolates variables across editor instances. + */ +export const MODULE_PREFIX = "export {};\n" as const; + +/** + * Strips `export {};` prefix (with or without newline) from scripts before execution + * (non-module context) or when exporting collections. + */ +export const stripModulePrefix = (script: string): string => { + if (script.startsWith(MODULE_PREFIX)) { + return script.slice(MODULE_PREFIX.length); + } + if (script.startsWith("export {};")) { + return script.slice("export {};".length); + } + return script; +}; + +export type CombineScriptsTarget = "experimental" | "legacy"; + +const wrapScript = (script: string, target: CombineScriptsTarget): string => { + const stripped = stripModulePrefix(script.trim()); + if (!stripped) return ""; + const asyncKeyword = target === "experimental" ? "async " : ""; + return `${asyncKeyword}function() {\n${stripped}\n}`; +}; + +/** + * Combines inherited scripts into a sequential chain. Each script runs in + * its own function for scope isolation. + * + * - `experimental`: `await (async function(){...})();` lines, evaluated in + * an async host context so each `await` settles before the next runs. + * - `legacy`: sync `(function(){...}).call(this);` lines. Top-level `await` + * is rejected at parse time. + */ +export const combineScriptsWithIIFE = ( + scripts: string[], + target: CombineScriptsTarget = "experimental" +): string => { + const fns = scripts.map((s) => wrapScript(s, target)).filter((s) => s); + if (fns.length === 0) return ""; + if (target === "experimental") { + // Wrap the awaited chain in try/catch so top-level throws / rejected + // awaits reach the host reporter; faraday-cage otherwise swallows + // async-boundary errors via its keepAlive loop. + const body = fns.map((fn) => `await (${fn})();`).join("\n"); + return [ + "const __hoppReporter = globalThis.__hoppReportScriptExecutionError;", + "try {", + body, + "} catch (__hoppScriptExecutionError) {", + " __hoppReporter(__hoppScriptExecutionError);", + "}", + ].join("\n"); + } + // Leading `;` guards against ASI: a prior `})` on the host line would + // otherwise be read as a call against our IIFE expression. + return fns.map((fn) => `;(${fn}).call(this);`).join("\n"); +}; + +export const filterValidScripts = ( + scripts: (string | undefined | null)[] +): string[] => + scripts.filter( + (script): script is string => + typeof script === "string" && + stripModulePrefix(script).trim().length > 0 + ); diff --git a/packages/hoppscotch-cli/src/utils/test.ts b/packages/hoppscotch-cli/src/utils/test.ts index f358bcf6112..d885b85060e 100644 --- a/packages/hoppscotch-cli/src/utils/test.ts +++ b/packages/hoppscotch-cli/src/utils/test.ts @@ -18,7 +18,7 @@ import { HoppEnvs } from "../types/request"; import { ExpectResult, TestMetrics, TestRunnerRes } from "../types/response"; import { getDurationInSeconds } from "./getters"; import { createHoppFetchHook } from "./hopp-fetch"; -import { stripModulePrefix } from "./mutators"; +import { combineScriptsWithIIFE, filterValidScripts } from "./scripting"; /** * Executes test script and runs testDescriptorParser to generate test-report using @@ -39,28 +39,46 @@ export const testRunner = ( TE.bind("test_response", () => pipe( TE.of(testScriptData), - TE.chain(({ request, response, envs, legacySandbox }) => { - const { status, statusText, headers, responseTime, body } = response; + TE.chain( + ({ + request, + response, + envs, + legacySandbox, + inheritedTestScripts = [], + }) => { + const { status, statusText, headers, responseTime, body } = + response; - const effectiveResponse = { - status, - statusText, - headers, - responseTime, - body, - }; + const effectiveResponse = { + status, + statusText, + headers, + responseTime, + body, + }; - const experimentalScriptingSandbox = !legacySandbox; - const hoppFetchHook = createHoppFetchHook(); + const experimentalScriptingSandbox = !legacySandbox; + const hoppFetchHook = createHoppFetchHook(); - return runTestScript(stripModulePrefix(request.testScript), { - envs, - request, - response: effectiveResponse, - experimentalScriptingSandbox, - hoppFetchHook, - }); - }) + // Test order: request → root (reverse of pre-request). + const combinedScript = combineScriptsWithIIFE( + filterValidScripts([ + request.testScript, + ...inheritedTestScripts.slice().reverse(), + ]), + experimentalScriptingSandbox ? "experimental" : "legacy" + ); + + return runTestScript(combinedScript, { + envs, + request, + response: effectiveResponse, + experimentalScriptingSandbox, + hoppFetchHook, + }); + } + ) ) ), @@ -160,7 +178,8 @@ export const getTestScriptParams = ( reqRunnerRes: RequestRunnerResponse, request: HoppRESTRequest, envs: HoppEnvs, - legacySandbox: boolean + legacySandbox: boolean, + inheritedTestScripts: string[] = [] ) => { const testScriptParams: TestScriptParams = { request, @@ -173,6 +192,7 @@ export const getTestScriptParams = ( }, envs, legacySandbox, + inheritedTestScripts, }; return testScriptParams; }; @@ -237,12 +257,11 @@ export const getFailedExpectedResults = (expectResults: ExpectResult[]) => ); /** - * Checks if any of the tests-report have failed test-cases. + * Checks whether every test report has zero failed test cases. * @param testsReport Provides "failed" test-cases data. - * @returns True, if one or more failed test-cases found. - * False, if all test-cases passed. + * @returns True, if all test-cases passed. False, otherwise. */ -export const hasFailedTestCases = (testsReport: TestReport[]) => +export const hasAllTestsPassed = (testsReport: TestReport[]) => pipe( testsReport, A.every(({ failed }) => failed === 0) diff --git a/packages/hoppscotch-cli/src/utils/workspace-access.ts b/packages/hoppscotch-cli/src/utils/workspace-access.ts index 6c47ba83ee3..2c9a947fd09 100644 --- a/packages/hoppscotch-cli/src/utils/workspace-access.ts +++ b/packages/hoppscotch-cli/src/utils/workspace-access.ts @@ -179,6 +179,8 @@ export const transformWorkspaceCollections = ( headers?: HoppRESTHeaders; variables: HoppCollectionVariable[]; description: string | null; + preRequestScript?: string; + testScript?: string; } = data ? JSON.parse(data) : {}; const { @@ -186,6 +188,8 @@ export const transformWorkspaceCollections = ( headers = [], variables = [], description = null, + preRequestScript = "", + testScript = "", } = parsedData; const transformedAuth = transformAuth(auth); @@ -211,6 +215,8 @@ export const transformWorkspaceCollections = ( headers: transformedHeaders, variables: filteredCollectionVariables, description, + preRequestScript, + testScript, }; }); }; diff --git a/packages/hoppscotch-common/assets/scss/styles.scss b/packages/hoppscotch-common/assets/scss/styles.scss index 37594450c7e..5c0541a11bd 100644 --- a/packages/hoppscotch-common/assets/scss/styles.scss +++ b/packages/hoppscotch-common/assets/scss/styles.scss @@ -561,3 +561,19 @@ details[open] summary .indicator { .gql-operation-highlight { @apply opacity-100; } + +/* + * Standardizes interactive tooltip behavior by extending the hover area. + * This prevents tooltips from hiding when the cursor moves across small + * gaps between the trigger text and the tooltip box. + */ +.hopp-tooltip-interactive-wrapper { + @apply relative; + + &::before { + content: ""; + @apply absolute; + @apply -inset-2; + @apply pointer-events-auto; + } +} diff --git a/packages/hoppscotch-common/locales/cn.json b/packages/hoppscotch-common/locales/cn.json index b530e7d9a2c..4c69405d455 100644 --- a/packages/hoppscotch-common/locales/cn.json +++ b/packages/hoppscotch-common/locales/cn.json @@ -109,10 +109,10 @@ "processing": "正在处理您的请求...", "not_running_title": "未检测到Agent", "registration_title": "注册Agent", - "verify_ssl_certs": "验证SSL证书", + "verify_ssl_certs": "验证 SSL 证书", "ca_certs": "CA 证书", "client_certs": "客户端证书", - "use_http_proxy": "使用HTTP代理", + "use_http_proxy": "使用 HTTP 代理", "proxy_capabilities": "Hoppscotch Agent 支持 HTTP/HTTPS/SOCKS 代理,以及 NTLM 和 Basic 认证。请在代理 URL 中包含用于认证的用户名和密码。", "add_cert_file": "添加证书文件", "add_client_cert": "添加客户端证书", @@ -132,6 +132,7 @@ "web_app": "Web App", "cli": "CLI" }, + "downloads": "下载", "chat_with_us": "与我们交谈", "contact_us": "联系我们", "cookies": "Cookies", @@ -624,11 +625,11 @@ "environment": { "heading": "环境", "add_to_global": "添加到全局环境", - "added": "环境已添加", + "added": "环境变量已添加", "create_new": "创建新环境", "created": "环境已创建", "current_value": "当前值", - "deleted": "环境已删除", + "deleted": "环境变量已删除", "duplicated": "环境已复制", "edit": "编辑环境", "empty_variables": "没有变量", @@ -902,8 +903,8 @@ "postman_environment": "Postman 环境", "postman_environment_description": "从一个 JSON 文件中导入 Postman 环境", "title": "导入", - "file_size_limit_exceeded_warning_multiple_files": "当前选择的文件大小超过了推荐的 10MB,只导入第一个被选择的 {files}。", - "file_size_limit_exceeded_warning_single_file": "当前选择的文件大小超过了推荐的 10MB,请选择其他文件", + "file_size_limit_exceeded_warning_multiple_files": "当前选择的文件大小超过了推荐的 {sizeLimit}MB,只导入第一个被选择的 {files}。", + "file_size_limit_exceeded_warning_single_file": "当前选择的文件大小超过了推荐的 {sizeLimit}MB,请选择其他文件", "success": "成功导入", "import_summary_collections_title": "集合", "import_summary_requests_title": "请求", @@ -992,29 +993,29 @@ "pre_request": "预请求脚本", "post_request": "请求后脚本", "both_scripts": "预请求和请求后脚本", - "unsupported_interceptor": "您的 {scriptType} 使用了 {apiUsed}。为确保脚本可靠执行,请切换到代理拦截器(网页应用)或原生拦截器(桌面应用)。{interceptor} 拦截器对脚本化请求的支持有限,可能无法按预期工作。", - "same_origin_csrf_warning": "安全警告:您的 {scriptType} 使用 {apiUsed} 进行了同源请求。由于本平台使用基于 Cookie 的身份验证,这些请求会自动包含您的会话 Cookie,可能导致恶意脚本执行未授权操作。请使用代理拦截器处理同源请求,或仅运行您信任的脚本。" + "unsupported_interceptor": "您的 {scriptType} 使用了 {apiUsed}。为确保脚本可靠执行,请切换到代理程序拦截器(网页应用)或原生拦截器(桌面应用)。{interceptor} 拦截器对脚本化请求的支持有限,可能无法按预期工作。", + "same_origin_csrf_warning": "安全警告:您的 {scriptType} 使用 {apiUsed} 进行了同源请求。由于本平台使用基于 Cookie 的身份验证,这些请求会自动包含您的会话 Cookie,可能导致恶意脚本执行未授权操作。请使用代理程序拦截器处理同源请求,或仅运行您信任的脚本。" } }, "interceptor": { "native": { - "name": "原生", + "name": "原生(Native)", "settings_title": "原生" }, "agent": { - "name": "代理程序", - "settings_title": "代理程序(Agent)" + "name": "代理程序(Agent)", + "settings_title": "代理程序" }, "proxy": { - "name": "网络代理", - "settings_title": "网络代理(Proxy)" + "name": "网络代理(Proxy)", + "settings_title": "网络代理" }, "browser": { - "name": "浏览器", + "name": "浏览器(Browser)", "settings_title": "浏览器" }, "extension": { - "name": "扩展", + "name": "扩展(Extension)", "settings_title": "扩展" } }, @@ -1088,9 +1089,9 @@ "start_server": "启动服务", "stop_server": "停止服务", "mock_server_created": "Mock 服务创建成功", - "mock_server_started": "mock启动成功", - "mock_server_stopped": "mock停止成功", - "active": "Mock正在运行", + "mock_server_started": "Mock 服务启动成功", + "mock_server_stopped": "Mock 服务停止成功", + "active": "Mock 服务正在运行", "inactive": "Mock 服务未运行", "edit_mock_server": "编辑 Mock 服务", "path_based_url": "基于路径的 URL", @@ -2248,7 +2249,7 @@ "organization_sidebar": { "hoppscotch_cloud": "Hoppscotch 云", "cloud_locked": "默认实例无法移除", - "admin": "管理", + "admin": "管理员", "error_loading": "加载组织失败", "inactive_orgs": "未激活的组织", "no_orgs_found": "未找到组织", diff --git a/packages/hoppscotch-common/locales/en.json b/packages/hoppscotch-common/locales/en.json index a4c26cbab09..2a73e6e4752 100644 --- a/packages/hoppscotch-common/locales/en.json +++ b/packages/hoppscotch-common/locales/en.json @@ -538,7 +538,6 @@ "versions": "Versions", "create_new_version": "Create New Version", "invalid_version": "Version must only contain alphanumeric characters, dots, and hyphens", - "snapshot_description": "This will snapshot the current documentation as this version", "live": "Live", "snapshot": "Snapshot", "version_immutable": "Published versions are read-only snapshots", @@ -556,8 +555,9 @@ "snapshot_empty": "No requests or folders in this snapshot", "snapshot_item_count": "{count} items", "auto_sync_live_notice": "This version auto-syncs with the live collection", + "snapshot_promote_warning": "Enabling auto-sync will replace this frozen snapshot with the live collection tree. This cannot be undone.", + "live_freeze_notice": "Auto-sync will be turned off and this version will be frozen at the current collection state.", "untitled_project": "Untitled Project", - "first_publish_hint": "Your documentation will be published as a live version that automatically stays in sync with your collection", "environment": "Environment", "no_environment": "No environment", "environment_description": "Attach an environment to resolve variables in the published documentation" @@ -625,23 +625,23 @@ "environment": { "heading": "Environment", "add_to_global": "Add to Global", - "added": "Environment addition", + "added": "Environment variable added", "create_new": "Create new environment", "created": "Environment created", "current_value": "Current value", - "deleted": "Environment deletion", + "deleted": "Environment variable deleted", "duplicated": "Environment duplicated", "edit": "Edit Environment", "empty_variables": "No variables", "global": "Global", "global_variables": "Global variables", - "import_or_create": "Import or create a environment", + "import_or_create": "Import or create an environment", "initial_value": "Initial value", "invalid_name": "Please provide a name for the environment", "list": "Environment variables", "my_environments": "Personal Environments", "name": "Name", - "nested_overflow": "nested environment variables are limited to 10 levels", + "nested_overflow": "Nested environment variables are limited to 10 levels", "new": "New Environment", "no_active_environment": "No active environment", "no_environment": "No environment", @@ -841,6 +841,7 @@ "authorization": "The authorization header will be automatically generated when you send the request.", "collection_properties_authorization": " This authorization will be set for every request in this collection.", "collection_properties_header": "This header will be set for every request in this collection.", + "collection_properties_scripts": "These scripts will run for every request in this collection. Pre-request scripts run before the request, test scripts run after the response.", "generate_documentation_first": "Generate documentation first", "network_fail": "Unable to reach the API endpoint. Check your network connection or select a different Interceptor and try again.", "offline": "You're using Hoppscotch offline. Updates will sync when you're online, based on workspace settings.", @@ -1256,6 +1257,12 @@ "saved": "Response saved", "invalid_name": "Please provide a name for the response" }, + "script": { + "inheriting": "Inheriting scripts from", + "inheriting_from_count": "Inheriting from {count} collection | Inheriting from {count} collections", + "inherited_scripts": "Inherited Scripts", + "view_inherited": "View inherited scripts" + }, "settings": { "accent_color": "Accent color", "account": "Account", @@ -1281,7 +1288,12 @@ "dark_mode": "Dark", "delete_account": "Delete account", "delete_account_description": "Once you delete your account, all your data will be permanently deleted. This action cannot be undone.", + "desktop": "Desktop", + "desktop_description": "Preferences that apply only to the Hoppscotch desktop app.", + "desktop_updates": "Updates", "disable_encode_mode_tooltip": "Never encode the parameters in the request", + "disable_update_checks": "Disable automatic update checks", + "disable_update_checks_description": "Skip the update check at app startup. Use the button above to check on demand.", "enable_encode_mode_tooltip": "Always encode the parameters in the request", "enter_otp": "Enter Agent's code", "expand_navigation": "Expand navigation", @@ -1339,6 +1351,15 @@ "telemetry_helps_us": "Telemetry helps us to personalize our operations and deliver the best experience to you.", "theme": "Theme", "theme_description": "Customize your application theme.", + "update_check_description": "Manually check for a new version and install it. Works regardless of the toggle below.", + "update_check_now": "Check for updates", + "update_checking": "Checking\u2026", + "update_download_version": "Download v{version}", + "update_downloading": "Downloading\u2026", + "update_downloading_percent": "Downloading {percent}%", + "update_installing": "Installing\u2026", + "update_restart_now": "Restart to apply update", + "update_up_to_date": "Up to date", "use_experimental_url_bar": "Use experimental URL bar with environment highlighting", "user": "User", "verified_email": "Verified email", @@ -1781,6 +1802,7 @@ "parameters": "Parameters", "post_request_script": "Post-request Script", "pre_request_script": "Pre-request Script", + "scripts": "Scripts", "queries": "Queries", "query": "Query", "schema": "Schema", diff --git a/packages/hoppscotch-common/locales/es.json b/packages/hoppscotch-common/locales/es.json index 65dae92614b..47e713412ab 100644 --- a/packages/hoppscotch-common/locales/es.json +++ b/packages/hoppscotch-common/locales/es.json @@ -4,10 +4,17 @@ "autoscroll": "Desplazamiento automático", "cancel": "Cancelar", "choose_file": "Seleccionar archivo", + "choose_workspace": "Elegir un espacio de trabajo", + "choose_collection": "Elegir una colección", + "select_workspace": "Seleccionar un espacio de trabajo", "clear": "Limpiar", "clear_all": "Limpiar todo", + "clear_cache": "Limpiar caché", "clear_history": "Borrar todo el historial", + "clear_unpinned": "Limpiar no fijados", + "clear_response": "Limpiar respuesta", "close": "Cerrar", + "confirm": "Confirmar", "connect": "Conectar", "connecting": "Conectando", "copy": "Copiar", @@ -15,8 +22,10 @@ "delete": "Borrar", "disconnect": "Desconectar", "dismiss": "Descartar", + "done": "Listo", "dont_save": "No guardar", "download_file": "Descargar archivo", + "download_test_report": "Descargar reporte de pruebas", "drag_to_reorder": "Arrastrar para reordenar", "duplicate": "Duplicar", "edit": "Editar", @@ -32,20 +41,28 @@ "more": "Más", "new": "Nuevo", "no": "No", + "open": "Abrir", "open_workspace": "Abrir espacio de trabajo", "paste": "Pegar", "prettify": "Formatear", "properties": "Propiedades", + "register": "Registrar", "remove": "Eliminar", + "remove_instance": "Eliminar instancia", "rename": "Renombrar", "restore": "Restaurar", + "retry": "Reintentar", "save": "Guardar", + "save_as_example": "Guardar como ejemplo", + "add_example": "Agregar ejemplo", + "invalid_request": "Datos de solicitud no válidos", "scroll_to_bottom": "Desplazar hacia abajo", "scroll_to_top": "Desplazar hacia arriba", "search": "Buscar", "send": "Enviar", "share": "Compartir", "show_secret": "Mostrar secreto", + "sort": "Ordenar", "start": "Comenzar", "starting": "Iniciando", "stop": "Detener", @@ -55,13 +72,67 @@ "turn_off": "Desactivar", "turn_on": "Activar", "undo": "Deshacer", - "yes": "Sí" + "unpublish": "Despublicar", + "yes": "Sí", + "verify": "Verificar", + "enable": "Habilitar", + "disable": "Deshabilitar", + "assign": "Asignar" + }, + "activity_logs": { + "ACTIVITY_LOG_DELETE": "El registro de actividad ha sido eliminado", + "WORKSPACE_CREATE": "Se creó el nuevo espacio de trabajo {name}", + "WORKSPACE_RENAME": "Se renombró el espacio de trabajo de {old_name} a {new_name}", + "WORKSPACE_USER_ADD": "{user} fue agregado al espacio de trabajo como {role}", + "WORKSPACE_USER_INVITE": "{user} fue invitado por {inviteeEmail} como {role}", + "WORKSPACE_USER_INVITE_REVOKE": "Se revocó la invitación de {inviteeEmail} como {inviteeRole}", + "WORKSPACE_USER_INVITE_ACCEPT": "{inviteeEmail} aceptó la invitación como {inviteeRole}", + "WORKSPACE_USER_REMOVE": "{user} fue eliminado del espacio de trabajo", + "WORKSPACE_USER_ROLE_UPDATE": "El rol de {user} fue actualizado de {old_role} a {new_role}", + "COLLECTION_CREATE": "Se creó la nueva colección {title}", + "COLLECTION_RENAME": "Se renombró la colección de {old_title} a {new_title}", + "COLLECTION_IMPORT": "Se importaron {count} colección(es)", + "COLLECTION_DELETE": "Se eliminó la colección {title}", + "COLLECTION_DUPLICATE": "Se duplicó la colección {parentTitle}", + "REQUEST_CREATE": "Se creó la nueva solicitud {title}", + "REQUEST_RENAME": "Se renombró la solicitud de {old_title} a {new_title}", + "REQUEST_DELETE": "Se eliminó la solicitud {title}" }, "add": { "new": "Agregar nuevo", "star": "Agregar estrella" }, + "agent": { + "registration_instruction": "Por favor registra Hoppscotch Agent con tu cliente web para continuar.", + "enter_otp_instruction": "Por favor ingresa el código de verificación generado por Hoppscotch Agent y completa el registro", + "otp_label": "Código de verificación", + "processing": "Procesando tu solicitud...", + "not_running_title": "Agente no detectado", + "registration_title": "Registro del agente", + "verify_ssl_certs": "Verificar certificados SSL", + "ca_certs": "Certificados CA", + "client_certs": "Certificados de cliente", + "use_http_proxy": "Usar proxy HTTP", + "proxy_capabilities": "Hoppscotch Agent soporta proxies HTTP/HTTPS/SOCKS junto con autenticación NTLM y Basic Auth en esos proxies. Incluye el nombre de usuario y la contraseña para la autenticación del proxy en la URL misma.", + "add_cert_file": "Agregar archivo de certificado", + "add_client_cert": "Agregar certificado de cliente", + "add_key_file": "Agregar archivo de clave", + "domain": "Dominio", + "cert": "Certificado", + "key": "Clave", + "pfx_or_pkcs": "PFX/PKCS12", + "pfx_or_pkcs_file": "Archivo PFX/PKCS12", + "add_pfx_or_pkcs_file": "Agregar archivo PFX/PKCS12" + }, "app": { + "additional_links": { + "macOS": "macOS", + "windows": "Windows", + "linux": "Linux", + "web_app": "App Web", + "cli": "CLI" + }, + "downloads": "Descargas", "chat_with_us": "Habla con nosotros", "contact_us": "Contáctanos", "cookies": "Cookies", @@ -84,6 +155,7 @@ "new_version_found": "Se ha encontrado una nueva versión. Recarga la página para usarla.", "open_in_hoppscotch": "Abrir en Hoppscotch", "options": "Opciones", + "powered_by": "Desarrollado con Hoppscotch", "proxy_privacy_policy": "Política de privacidad de proxy", "reload": "Recargar", "search": "Buscar", @@ -101,9 +173,17 @@ "updated_text": "Hoppscotch se ha actualizado a v{version} 🎉", "whats_new": "¿Qué hay de nuevo?", "see_whats_new": "Novedades", - "wiki": "Wiki" + "wiki": "Wiki", + "collapse_sidebar": "Contraer barra lateral", + "continue_to_dashboard": "Continuar al panel", + "expand_sidebar": "Expandir barra lateral", + "no_name": "Sin nombre", + "open_navigation": "Abrir navegación", + "read_documentation": "Leer documentación", + "default": "predeterminado: {value}" }, "auth": { + "account_deactivated": "Tu cuenta ha sido desactivada. Contacta al administrador para obtener acceso.", "account_exists": "La cuenta existe con una credencial diferente - Inicia sesión para vincular ambas cuentas", "all_sign_in_options": "Todas las opciones de inicio de sesión", "continue_with_auth_provider": "Continuar con {provider}", @@ -126,6 +206,7 @@ }, "authorization": { "generate_token": "Generar token", + "refresh_token": "Refresh Token", "graphql_headers": "Las cabeceras de autorización se envían como parte de la carga útil de connection_init", "include_in_url": "Incluir en la URL", "inherited_from": "Heredado {auth} de colección padre {collection} ", @@ -145,9 +226,12 @@ "token_generation_oidc_discovery_failed": "Fallo en la generación del token: Error en el descubrimiento de OpenID Connect", "grant_type": "Tipo de autorización", "grant_type_auth_code": "Código de autorización", - "token_fetched_successfully": "Token recuperado correctamente", + "token_fetched_successfully": "Token recuperado exitosamente", "token_fetch_failed": "Fallo al recuperar el token", "validation_failed": "Fallo de validación, comprueba los campos del formulario", + "no_refresh_token_present": "No hay Refresh Token presente. Por favor ejecuta el flujo de generación de token nuevamente", + "refresh_token_request_failed": "La solicitud de Refresh Token falló", + "token_refreshed_successfully": "Token actualizado correctamente", "label_authorization_endpoint": "Punto final de autorización", "label_client_id": "ID de cliente", "label_client_secret": "Secreto de cliente", @@ -161,7 +245,15 @@ "label_password": "Contraseña", "label_username": "Nombre de usuario", "label_auth_code": "Código de autorización", - "label_client_credentials": "Credenciales del cliente" + "label_client_credentials": "Credenciales del cliente", + "label_send_as": "Autenticación del cliente", + "label_send_in_body": "Enviar credenciales en el cuerpo", + "label_send_as_basic_auth": "Enviar credenciales como Basic Auth", + "enter_value": "Ingresa un valor", + "auth_request": "Solicitud de autenticación", + "token_request": "Solicitud de token", + "refresh_request": "Solicitud de actualización", + "send_in": "Enviar en" }, "pass_key_by": "Pasar por", "pass_by_query_params_label": "Parámetros de consulta", @@ -169,10 +261,76 @@ "password": "Contraseña", "save_to_inherit": "Por favor, guarda esta solicitud en cualquier colección para heredar la autorización", "token": "Token", + "access_token": "Access Token", + "client_token": "Client Token", + "client_secret": "Client Secret", + "timestamp": "Marca de tiempo", + "host": "Host", "type": "Tipo de autorización", - "username": "Nombre de usuario" + "username": "Nombre de usuario", + "advance_config": "Configuración avanzada", + "advance_config_description": "Hoppscotch asigna automáticamente valores predeterminados a ciertos campos si no se proporciona un valor explícito", + "algorithm": "Algoritmo", + "payload": "Payload", + "secret": "Secreto", + "aws_signature": { + "access_key": "Access Key", + "secret_key": "Secret Key", + "service_name": "Nombre del servicio", + "aws_region": "Región de AWS", + "service_token": "Service Token" + }, + "digest": { + "realm": "Realm", + "nonce": "Nonce", + "algorithm": "Algoritmo", + "qop": "qop", + "nonce_count": "Nonce Count", + "client_nonce": "Client Nonce", + "opaque": "Opaque", + "disable_retry": "Deshabilitar reintento de solicitud" + }, + "akamai": { + "headers_to_sign": "Headers a firmar", + "max_body_size": "Tamaño máximo del cuerpo" + }, + "hawk": { + "id": "HAWK Auth ID", + "key": "HAWK Auth Key", + "ext": "ext", + "app": "app", + "dlg": "dlg", + "include": "Incluir hash del payload" + }, + "jwt": { + "params_name": "Nombre de parámetros", + "param_name": "Nombre del parámetro", + "header_prefix": "Prefijo del header", + "placeholder_request_header": "Prefijo del header de solicitud", + "placeholder_request_param": "Nombre de parámetros de solicitud", + "secret_base64_encoded": "Secreto codificado en Base64", + "headers": "Headers JWT", + "private_key": "Clave privada", + "placeholder_headers": "Headers JWT" + }, + "ntlm": { + "domain": "Dominio", + "workstation": "Estación de trabajo", + "disable_retrying_request": "Deshabilitar reintento de solicitud" + }, + "asap": { + "issuer": "Emisor", + "audience": "Audiencia", + "expires_in": "Expira en", + "key_id": "Key ID", + "optional_config": "Configuración opcional", + "subject": "Sujeto", + "additional_claims": "Claims adicionales" + } }, "collection": { + "title": "Colección", + "run": "Ejecutar colección", "created": "Colección creada", "different_parent": "No se puede reordenar la colección con un padre diferente", "edit": "Editar colección", @@ -194,13 +352,14 @@ "save_to_collection": "Guardar en la colección", "select": "Seleccionar colección", "select_location": "Seleccionar ubicación", + "sorted": "Colección ordenada", "details": "Detalles", - "select_team": "Seleccionar equipo", - "team_collections": "Colecciones de equipos" + "duplicated": "Colección duplicada" }, "confirm": { "close_unsaved_tab": "¿Seguro que quieres cerrar esta pestaña?", "close_unsaved_tabs": "¿Estás seguro de que quieres cerrar todas las pestañas? {count} pestañas no guardadas se perderán.", + "delete_all_activity_logs": "¿Estás seguro de que deseas eliminar todos los registros de actividad?", "exit_team": "¿Estás seguro de que quieres dejar este equipo?", "logout": "¿Estás seguro de que deseas cerrar la sesión?", "remove_collection": "¿Estás seguro de que deseas eliminar esta colección de forma permanente?", @@ -208,18 +367,22 @@ "remove_folder": "¿Estás seguro de que deseas eliminar esta carpeta de forma permanente?", "remove_history": "¿Estás seguro de que deseas eliminar todo el historial de forma permanente?", "remove_request": "¿Estás seguro de que deseas eliminar esta solicitud de forma permanente?", + "remove_response": "¿Estás seguro de que deseas eliminar permanentemente esta respuesta?", "remove_shared_request": "¿Estás seguro de que quieres eliminar definitivamente esta solicitud compartida?", "remove_team": "¿Estás seguro de que deseas eliminar este equipo?", "remove_telemetry": "¿Estás seguro de que deseas darse de baja de la telemetría?", "request_change": "¿Estás seguro de que deseas descartar la solicitud actual, los cambios no guardados se perderán.", "save_unsaved_tab": "¿Deseas guardar los cambios realizados en esta pestaña?", "sync": "¿Estás seguro de que deseas sincronizar este espacio de trabajo?", - "delete_access_token": "¿Estás seguro de que deseas eliminar el token de acceso {tokenLabel}?" + "delete_access_token": "¿Estás seguro de que deseas eliminar el token de acceso {tokenLabel}?", + "delete_mock_server": "¿Estás seguro de que deseas eliminar este servidor mock?" }, "context_menu": { "add_parameters": "Añadir a parámetros", "open_request_in_new_tab": "Abrir solicitud en una nueva pestaña", - "set_environment_variable": "Establecer como variable" + "set_environment_variable": "Establecer como variable", + "encode_uri_component": "Codificar componente de URL", + "decode_uri_component": "Decodificar componente de URL" }, "cookies": { "modal": { @@ -240,25 +403,202 @@ } }, "count": { + "currentValue": "Valor actual {count}", + "description": "Descripción {count}", "header": "{count} encabezado(s)", + "initialValue": "Valor inicial {count}", + "key": "Clave {count}", "message": "{count} mensaje(s)", "parameter": "{count} parámetro(s)", "protocol": "{count} protocolo(s)", - "value": "{cuenta} valor(es)", + "value": "Valor {count}", "variable": "{count} variable(es)" }, "documentation": { + "add_description": "Agregar descripción para esta colección aquí...", + "add_description_placeholder": "Agregar descripción aquí...", + "add_request_description": "Agregar descripción para la solicitud aquí...", + "auth": { + "access_key": "Clave de acceso", + "access_token": "Token de acceso", + "add_to": "Agregar a", + "akamai_edgegrid": "Akamai EdgeGrid", + "algorithm": "Algoritmo", + "api_key": "API Key", + "app_id": "App ID", + "auth_id": "Auth ID", + "auth_key": "Auth Key", + "auth_url": "Auth URL", + "aws_signature": "AWS Signature", + "basic_auth": "Basic Auth", + "bearer_token": "Bearer Token", + "client_id": "Client ID", + "client_nonce": "Client Nonce", + "client_secret": "Client Secret", + "client_token": "Client Token", + "delegation": "Delegación", + "digest_auth": "Digest Auth", + "extra_data": "Datos adicionales", + "grant_type": "Tipo de concesión", + "hawk_auth": "HAWK Auth", + "headers_to_sign": "Headers a firmar", + "host": "Host", + "include_payload_hash": "Incluir hash del payload", + "jwt_auth": "JWT Auth", + "max_body_size": "Tamaño máximo del cuerpo", + "no_auth": "Sin autenticación", + "nonce": "Nonce", + "oauth_2": "OAuth 2.0", + "opaque": "Opaque", + "password": "Contraseña", + "payload": "Payload", + "qop": "QOP", + "realm": "Realm", + "region": "Región", + "scope": "Scope", + "secret_key": "Clave secreta", + "service_name": "Nombre del servicio", + "timestamp": "Marca de tiempo", + "title": "Autenticación", + "token_url": "Token URL", + "user": "Usuario", + "username": "Nombre de usuario" + }, + "body": { + "content_type": "Tipo de contenido", + "no_body": "No se definió un cuerpo", + "title": "Cuerpo" + }, + "copied_to_clipboard": "¡Copiado al portapapeles!", + "curl": { + "click_to_load": "Haz clic para cargar el comando cURL", + "copied": "¡Comando cURL copiado al portapapeles!", + "copy_to_clipboard": "Copiar al portapapeles", + "generating": "Generando comando cURL...", + "load": "Cargar cURL", + "title": "cURL" + }, + "description": "Descripción", + "error_rendering_markdown": "Error al renderizar markdown:", + "fetching_documentation": "Obteniendo documentación...", "generate": "Generar documentación", - "generate_message": "Importar cualquier colección de Hoppscotch para generar documentación de la API sobre la marcha." + "generate_message": "Importar cualquier colección de Hoppscotch para generar documentación de la API sobre la marcha.", + "headers": { + "no_headers": "No se definieron encabezados", + "title": "Encabezados" + }, + "hide_all_documentation": "Ocultar toda la documentación", + "inherited_from": "Heredado de {name}", + "inherited_with_type": "{type} heredado de {name}", + "key": "Clave", + "loading": "Cargando...", + "loading_collection_data": "Cargando datos de la colección...", + "no": "No", + "no_collection_data": "No hay datos de colección disponibles", + "no_documentation_found": "No se encontró documentación para carpetas o solicitudes", + "no_request_data": "No hay datos de solicitud disponibles", + "no_requests_or_folders": "No hay solicitudes ni carpetas", + "not_set": "No configurado", + "open_request_in_new_tab": "Abrir solicitud en una nueva pestaña", + "parameters": { + "no_params": "No se definieron parámetros", + "title": "Parámetros" + }, + "percent_complete": "% completado", + "processing_documentation": "Procesando documentación", + "publish": { + "already_published": "Esta colección ya está publicada", + "auto_sync": "Sincronización automática con la colección", + "auto_sync_description": "Actualizar automáticamente la documentación publicada cuando cambie la colección", + "button": "Publicar", + "copy_url": "Copiar URL", + "delete": "Eliminar documentación", + "unpublish_doc": "¿Estás seguro de que deseas despublicar la documentación?", + "delete_success": "Documentación publicada eliminada correctamente", + "doc_title": "Título", + "doc_version": "Versión", + "edit_published_doc": "Editar documento publicado", + "last_updated": "Última actualización", + "metadata": "Metadatos (JSON)", + "open_published_doc": "Abrir documentación publicada en una nueva pestaña", + "publish_error": "Error al publicar la documentación", + "publish_success": "¡Documentación publicada exitosamente!", + "published": "Publicada", + "published_url": "URL publicada", + "title": "Publicar documentación", + "update_button": "Actualizar", + "update_error": "Error al actualizar la documentación", + "update_published_docs": "Actualizar documentación publicada", + "update_success": "¡Documentación actualizada correctamente!", + "unpublish": "Despublicar", + "update_title": "Actualizar documentación publicada", + "url_copied": "¡URL copiada al portapapeles!", + "view_published": "Ver documentación publicada", + "view_title": "Instantánea de documentación publicada", + "versions": "Versiones", + "create_new_version": "Crear nueva versión", + "invalid_version": "La versión solo debe contener caracteres alfanuméricos, puntos y guiones", + "snapshot_description": "Esto creará una instantánea de la documentación actual como esta versión", + "live": "En vivo", + "snapshot": "Instantánea", + "version_immutable": "Las versiones publicadas son instantáneas de solo lectura", + "view_snapshot": "Ver instantánea", + "current_version": "ACTUAL", + "not_found": "No se encontró la documentación publicada", + "no_doc_id": "No se proporcionó un ID de documento", + "version_label": "v{version}", + "unpublish_version": "Despublicar esta versión", + "loading_snapshot": "Cargando instantánea...", + "retry_snapshot": "Reintentar", + "sensitive_data_warning": "Asegúrate de que no se expongan datos sensibles en la documentación publicada.", + "snapshot_preview": "Vista previa de la instantánea", + "snapshot_load_error": "Error al cargar la vista previa de la instantánea", + "snapshot_empty": "No hay solicitudes ni carpetas en esta instantánea", + "snapshot_item_count": "{count} elementos", + "auto_sync_live_notice": "Esta versión se sincroniza automáticamente con la colección en vivo", + "untitled_project": "Proyecto sin título", + "first_publish_hint": "Tu documentación se publicará como una versión en vivo que se sincroniza automáticamente con tu colección", + "environment": "Entorno", + "no_environment": "Sin entorno", + "environment_description": "Adjuntar un entorno para resolver variables en la documentación publicada" + }, + "request_opened_in_new_tab": "¡Solicitud abierta en una nueva pestaña!", + "response": { + "body": "Cuerpo de la respuesta", + "copy": "Copiar respuesta", + "example_copied": "¡Ejemplo de respuesta copiado al portapapeles!", + "example_copy_failed": "Error al copiar el ejemplo de respuesta", + "headers": "Encabezados de la respuesta", + "no_examples": "No hay ejemplos de respuesta disponibles", + "title": "Ejemplos de respuesta" + }, + "save_error": "Error al guardar la documentación", + "save_success": "Documentación guardada correctamente", + "saved_items_status": "Se guardaron {success} elementos. Error al guardar {failure} elementos.", + "show_all_documentation": "Mostrar toda la documentación", + "source": "Fuente", + "title": "Documentación", + "unsaved_changes": "Tienes {count} cambios sin guardar. Guarda antes de cerrar.", + "untitled_collection": "Colección sin título", + "untitled_request": "Solicitud sin título", + "value": "Valor", + "variables": { + "no_vars": "No se definieron variables", + "title": "Variables" + }, + "yes": "Sí" }, "empty": { + "activity_logs": "No se encontraron registros de actividad", "authorization": "Esta solicitud no utiliza ninguna autorización", "body": "Esta solicitud no tiene cuerpo", "collection": "Colección vacía", "collections": "No hay colecciones", "documentation": "Es necesario conectarse a un punto final de GraphQL para ver la documentación", + "empty_schema": "No se encontró esquema", "endpoint": "El punto final no puede estar vacío", "environments": "No hay entornos", + "collection_variables": "Las variables de colección están vacías", "folder": "Carpeta vacía", "headers": "Esta solicitud no tiene encabezados", "history": "No hay historial", @@ -270,6 +610,7 @@ "protocols": "No hay protocolos", "request_variables": "Esta solicitud no tiene variables de solicitud", "schema": "Conectarse a un punto final de GraphQL", + "search_environment": "No se encontró un entorno que coincida con", "secret_environments": "Los secretos no están sincronizados con Hoppscotch", "shared_requests": "No hay solicitudes compartidas", "shared_requests_logout": "Iniciar sesión para ver sus solicitudes compartidas o crear una nueva", @@ -278,13 +619,16 @@ "teams": "No hay equipos", "tests": "No hay pruebas para esta solicitud", "access_tokens": "No hay tokens de acceso disponibles", - "shortcodes": "Aún no se han creado Shortcodes" + "response": "No se recibió respuesta", + "mock_servers": "No se encontraron servidores mock" }, "environment": { + "heading": "Entorno", "add_to_global": "Añadir a Global", "added": "Adición al entorno", "create_new": "Crear un nuevo entorno", "created": "Entorno creado", + "current_value": "Valor actual", "deleted": "Eliminar el entorno", "duplicated": "Entorno duplicado", "edit": "Editar entorno", @@ -292,6 +636,7 @@ "global": "Global", "global_variables": "Variables globales", "import_or_create": "Importar o crear un entorno", + "initial_value": "Valor inicial", "invalid_name": "Proporciona un nombre válido para el entorno.", "list": "Variables de entorno", "my_environments": "Mis entornos", @@ -302,6 +647,10 @@ "no_environment": "Sin entorno", "no_environment_description": "No se ha seleccionado ningún entorno. Elije qué hacer con las siguientes variables.", "quick_peek": "Vistazo rápido al entorno", + "replace_all_current_with_initial": "Reemplazar todos los actuales con los iniciales", + "replace_all_initial_with_current": "Reemplazar todos los iniciales con los actuales", + "replace_current_with_initial": "Reemplazar con el inicial", + "replace_initial_with_current": "Reemplazar con el actual", "replace_with_variable": "Sustituir por variable", "scope": "Ámbito", "secrets": "Secretos", @@ -309,6 +658,7 @@ "select": "Seleccionar entorno", "set": "Establecer entorno", "set_as_environment": "Establecer como entorno", + "short_name": "El entorno necesita tener al menos 1 carácter en su nombre", "team_environments": "Entornos de trabajo en equipo", "title": "Entornos", "updated": "Entorno actualizado", @@ -320,6 +670,47 @@ "details": "Detalles" }, "error": { + "network": { + "heading": "Error de red", + "description": "La conexión de red falló. {message}: {cause}" + }, + "timeout": { + "heading": "Error de tiempo de espera", + "description": "La solicitud expiró durante {phase}. {message}" + }, + "certificate": { + "heading": "Error de certificado", + "description": "Certificado inválido. {message}: {cause}" + }, + "auth": { + "heading": "Error de autenticación", + "description": "Acceso denegado. {message}: {cause}" + }, + "proxy": { + "heading": "Error de proxy", + "description": "La conexión del proxy falló. {message}: {cause}" + }, + "parse": { + "heading": "Error de análisis", + "description": "Error al analizar la respuesta. {message}: {cause}" + }, + "version": { + "heading": "Error de versión", + "description": "Versiones incompatibles. {message}: {cause}" + }, + "abort": { + "heading": "Solicitud cancelada", + "description": "Operación cancelada. {message}: {cause}" + }, + "unknown": { + "heading": "Error desconocido", + "description": "Ocurrió un error desconocido.", + "cause": "Causa desconocida" + }, + "extension": { + "heading": "Error de extensión", + "description": "Error al ejecutar la solicitud en la extensión" + }, "authproviders_load_error": "No se han podido cargar los proveedores de autenticación", "browser_support_sse": "Este navegador no parece ser compatible con los eventos enviados por el servidor.", "check_console_details": "Consulta el registro de la consola para obtener más detalles.", @@ -328,13 +719,18 @@ "danger_zone": "Zona de peligro", "delete_account": "Tu cuenta es actualmente propietaria en estos equipos:", "delete_account_description": "Para poder eliminar tu cuenta, debes darte de baja, transferir la propiedad o eliminar estos equipos.", + "delete_activity_log": "Error al eliminar el registro de actividad", + "delete_all_activity_logs": "Error al eliminar todos los registros de actividad", + "email_already_exists": "Este correo electrónico ya existe con una cuenta diferente. Establece una dirección de correo electrónico diferente.", "empty_email_address": "La dirección de correo electrónico no puede estar vacía.", "empty_profile_name": "El nombre del perfil no puede estar vacío", "empty_req_name": "Nombre de solicitud vacío", + "fetch_activity_logs": "Error al obtener los registros de actividad", "f12_details": "(F12 para más detalles)", "gql_prettify_invalid_query": "No se puede aplicar embellecedor a una consulta no válida, resuelve los errores de sintaxis de la consulta y vuelve a intentarlo", "incomplete_config_urls": "URLs de configuración incompletas", "incorrect_email": "Correo electrónico incorrecto", + "invalid_file_type": "Tipo de archivo inválido para `{filename}`.", "invalid_link": "Enlace no válido", "invalid_link_description": "El enlace que has pulsado no es válido o ha caducado.", "invalid_embed_link": "La inserción no existe o no es válida.", @@ -353,11 +749,14 @@ "same_profile_name": "El nombre del perfil actualizado es el mismo que el nombre del perfil actual", "script_fail": "No se pudo ejecutar el script de solicitud previa", "something_went_wrong": "Algo salió mal", + "subscription_error": "Error al suscribirse al tema: {error}", "post_request_script_fail": "No se ha podido ejecutar la secuencia de comandos posterior a la solicitud", "reading_files": "Error al leer uno o más archivos.", "fetching_access_tokens_list": "Algo ha ido mal al obtener la lista de tokens", "generate_access_token": "Algo ha ido mal al generar el token de acceso", - "delete_access_token": "Algo ha ido mal al borrar el token de acceso" + "delete_access_token": "Algo ha ido mal al borrar el token de acceso", + "extension_not_found": "Extensión no encontrada", + "invalid_request": "Datos de solicitud no válidos" }, "export": { "as_json": "Exportar como JSON", @@ -367,8 +766,31 @@ "secret_gist_success": "Exportado con éxito como Gist secreto", "require_github": "Iniciar sesión con GitHub para crear un Gist secreto", "title": "Exportar", - "success": "Exportado con éxito", - "gist_created": "Gist creado" + "success": "Exportado con éxito" + }, + "file_upload": { + "choose_file": "Elegir archivo", + "max_size_format": "Máximo 5MB. Compatible con JPEG, PNG, GIF, WebP", + "profile_photo_updated": "Foto de perfil actualizada correctamente", + "profile_photo_removed": "Foto de perfil eliminada correctamente", + "org_logo_updated": "Logo de la organización actualizado correctamente", + "error_size_limit": "El tamaño del archivo debe ser menor a 5MB", + "error_invalid_format": "El archivo debe ser una imagen (JPEG, PNG, GIF o WebP)", + "error_invalid_upload_type": "Tipo de carga inválido", + "error_invalid_org_id": "Formato de ID de organización inválido", + "error_upload_failed": "Error en la carga. Inténtalo de nuevo", + "error_network_failed": "Error de red. Verifica tu conexión", + "error_timeout": "La carga expiró después de 30 segundos. Inténtalo de nuevo", + "error_missing_backend_url": "La URL del backend no está configurada. Establece la variable de entorno VITE_BACKEND_API_URL en la configuración de tu entorno", + "error_invalid_backend_url": "Configuración de URL del backend inválida" + }, + "filename": { + "cookie_key_value_pairs": "Cookie", + "codegen": "{request_name} - código", + "graphql_response": "GraphQL-Respuesta", + "lens": "{request_name} - respuesta", + "realtime_response": "Respuesta-en-tiempo-real", + "response_interface": "Interfaz-de-respuesta" }, "filter": { "all": "Todos", @@ -381,17 +803,27 @@ "invalid_name": "Proporciona un nombre para la carpeta.", "name_length_insufficient": "El nombre de la carpeta debe tener al menos 3 caracteres", "new": "Nueva carpeta", - "renamed": "Carpeta renombrada" + "run": "Ejecutar carpeta", + "renamed": "Carpeta renombrada", + "sorted": "Carpeta ordenada" }, "graphql": { + "arguments": "Argumentos", "connection_switch_confirm": "¿Deseas conectarte con el punto final de GraphQL más reciente?", + "connection_error_http": "Error al obtener el esquema GraphQL debido a un error de red.", "connection_switch_new_url": "Al cambiar a una pestaña se desconectará de la conexión GraphQL activa. La nueva URL de conexión es", "connection_switch_url": "Estás conectado a un punto final de GraphQL cuya URL de conexión es", + "deprecated": "Obsoleto", + "fields": "Campos", + "mutation": "Mutation", "mutations": "Mutaciones", "schema": "Esquema", + "show_depricated_values": "Mostrar valores obsoletos", + "subscription": "Subscription", "subscriptions": "Suscripciones", "switch_connection": "Cambiar conexión", - "url_placeholder": "Introduce una URL de punto final de GraphQL" + "url_placeholder": "Introduce una URL de punto final de GraphQL", + "query": "Query" }, "graphql_collections": { "title": "Colecciones de GraphQL" @@ -423,7 +855,8 @@ "collection": "Colapsar el panel de colecciones", "more": "Ocultar más", "preview": "Ocultar vista previa", - "sidebar": "Ocultar barra lateral" + "sidebar": "Ocultar barra lateral", + "password": "Ocultar contraseña" }, "import": { "collections": "Importar colecciones", @@ -434,18 +867,30 @@ "from_file": "Importar desde archivo", "from_gist": "Importar desde GitHub Gist", "from_gist_description": "Importar desde URL de GitHub Gist", + "from_gist_import_summary": "Se importarán todas las funcionalidades de Hoppscotch.", + "from_hoppscotch_importer_summary": "Se importarán todas las funcionalidades de Hoppscotch.", "from_insomnia": "Importar desde Insomnia", "from_insomnia_description": "Importar desde una colección de Insomnia", + "from_insomnia_import_summary": "Se importarán colecciones y solicitudes.", "from_json": "Importar de Hoppscotch", "from_json_description": "Importar desde el archivo de colección de Hoppscotch", "from_my_collections": "Importar desde Mis colecciones", "from_my_collections_description": "Importar desde el archivo de Mis colecciones", + "from_all_collections": "Importar desde otro espacio de trabajo", + "from_all_collections_description": "Importar cualquier colección de otro espacio de trabajo al espacio de trabajo actual", "from_openapi": "Importar desde OpenAPI", "from_openapi_description": "Importar desde un archivo de especificación OpenAPI (YML/JSON)", + "from_openapi_import_summary": "Se importarán colecciones (se crearán a partir de tags), solicitudes y ejemplos de respuesta.", "from_postman": "Importar desde Postman", "from_postman_description": "Importar desde una colección de Postman", + "from_postman_import_summary": "Se importarán colecciones, solicitudes y ejemplos de respuesta.", + "import_scripts": "Importar scripts", + "import_scripts_description": "Compatible con Postman Collection v2.0/v2.1.", "from_url": "Importar desde una URL", "gist_url": "Introduce la URL del GitHub Gist", + "from_har": "Importar desde HAR", + "from_har_description": "Importar desde archivo HAR", + "from_har_import_summary": "Las solicitudes se importarán a una colección predeterminada.", "gql_collections_from_gist_description": "Importar colecciones GraphQL desde GitHub Gist", "hoppscotch_environment": "Entorno de Hoppscotch", "hoppscotch_environment_description": "Importar archivo JSON del entorno de Hoppscotch", @@ -458,9 +903,58 @@ "postman_environment": "Entorno de Postman", "postman_environment_description": "Importar entorno de Postman desde un archivo JSON", "title": "Importar", - "file_size_limit_exceeded_warning_multiple_files": "Los archivos seleccionados exceden el límite recomendado de 10MB. Sólo se importarán los primeros {files} seleccionados.", - "file_size_limit_exceeded_warning_single_file": "El archivo seleccionado supera el límite recomendado de 10 MB. Por favor, selecciona otro archivo.", - "success": "Importado con éxito" + "file_size_limit_exceeded_warning_multiple_files": "Los archivos seleccionados exceden el límite recomendado de {sizeLimit}MB. Sólo se importarán los primeros {files} seleccionados.", + "file_size_limit_exceeded_warning_single_file": "El archivo seleccionado supera el límite recomendado de {sizeLimit}MB. Por favor, selecciona otro archivo.", + "success": "Importado con éxito", + "import_summary_collections_title": "Colecciones", + "import_summary_requests_title": "Solicitudes", + "import_summary_responses_title": "Respuestas", + "import_summary_pre_request_scripts_title": "Scripts de pre-solicitud", + "import_summary_post_request_scripts_title": "Scripts de post-solicitud", + "import_summary_not_supported_by_hoppscotch_import": "Actualmente no soportamos la importación de {featureLabel} desde esta fuente.", + "import_summary_script_found": "script encontrado pero no importado", + "import_summary_scripts_found": "scripts encontrados pero no importados", + "import_summary_enable_experimental_sandbox": "Para importar scripts de Postman, habilita 'Sandbox de scripting experimental' en la configuración. Nota: Esta función es experimental.", + "cors_error_modal": { + "title": "Error de CORS detectado", + "description": "La importación falló debido a restricciones de CORS (Cross-Origin Resource Sharing) impuestas por el servidor.", + "explanation": "Esta es una función de seguridad que impide que las páginas web realicen solicitudes a dominios diferentes. Puedes reintentar usando nuestro servicio de proxy para evitar esta restricción.", + "url_label": "URL intentada", + "retry_with_proxy": "Reintentar con proxy" + } + }, + "instances": { + "switch": "Cambiar instancia de Hoppscotch", + "enter_server_url": "Conectar a una instancia autoalojada", + "already_connected": "Ya estás conectado a esta instancia", + "recent_connections": "Conexiones recientes", + "add_instance": "Agregar una instancia", + "add_new": "Agregar una nueva instancia", + "confirm_remove": "Confirmar eliminación", + "remove_warning": "¿Estás seguro de que deseas eliminar esta instancia?", + "clear_cached_bundles": "Limpiar paquetes en caché", + "opening_add_modal": "Abriendo diálogo para agregar instancia", + "closed_add_modal": "Diálogo para agregar instancia cerrado", + "cancelled_removal": "Eliminación de instancia cancelada", + "connection_cancelled": "Conexión cancelada por la validación previa", + "post_connect_completed": "Configuración posterior a la conexión completada", + "connecting": "Conectando a la instancia...", + "confirm_removal": "Confirmar eliminación de la instancia", + "removal_cancelled": "Eliminación de instancia cancelada por la validación previa", + "post_remove_completed": "Limpieza posterior a la eliminación completada", + "removing": "Eliminando instancia...", + "clearing_cache": "Limpiando caché...", + "initialized": "Selector de instancias inicializado", + "connecting_state": "Estableciendo conexión...", + "connected_state": "Conectado exitosamente a la instancia", + "disconnected_state": "Desconectado de la instancia", + "stream_error": "Error al monitorear el estado de la conexión", + "recent_instances_error": "Error al cargar las instancias recientes", + "instance_changed": "Se cambió a la instancia", + "current_instance_error": "Error al rastrear la instancia actual", + "not_available": "El cambio de instancia no está disponible", + "cleanup_completed": "Limpieza del selector de instancias completada", + "self_hosted": "Instancias autoalojadas" }, "inspections": { "description": "Inspeccionar posibles errores", @@ -485,7 +979,44 @@ "extension_not_installed": "Extensión no instalada.", "extension_unknown_origin": "Asegúrate de haber agregado el origen del punto final de la API a la lista de Extensiones del Navegador Hoppscotch.", "extention_enable_action": "Activar la extensión del navegador", - "extention_not_enabled": "Extensión no habilitada." + "extention_not_enabled": "Extensión no habilitada.", + "localaccess_unsupported": "El interceptor actual no soporta acceso local, considera usar los interceptores Agent, Extension o la aplicación de escritorio" + }, + "auth": { + "digest": "Se recomienda el interceptor Agent en la aplicación web o el interceptor Native en la aplicación de escritorio al usar autorización Digest.", + "hawk": "Se recomienda el interceptor Agent en la aplicación web o el interceptor Native en la aplicación de escritorio al usar autorización Hawk." + }, + "body": { + "binary": "El envío de datos binarios a través del interceptor actual aún no es compatible." + }, + "scripting_interceptor": { + "pre_request": "script de pre-solicitud", + "post_request": "script de post-solicitud", + "both_scripts": "scripts de pre-solicitud y post-solicitud", + "unsupported_interceptor": "Tu {scriptType} usa {apiUsed}. Para una ejecución confiable de scripts, cambia al interceptor Agent (aplicación web) o al interceptor Native (aplicación de escritorio). El interceptor {interceptor} tiene soporte limitado para solicitudes de scripting y puede no funcionar como se espera.", + "same_origin_csrf_warning": "Advertencia de seguridad: Tu {scriptType} realiza solicitudes del mismo origen usando {apiUsed}. Dado que esta plataforma usa autenticación basada en cookies, estas solicitudes incluyen automáticamente tus cookies de sesión, lo que podría permitir que scripts maliciosos realicen acciones no autorizadas. Usa el interceptor Agent para solicitudes del mismo origen, o solo ejecuta scripts en los que confíes." + } + }, + "interceptor": { + "native": { + "name": "Native", + "settings_title": "Native" + }, + "agent": { + "name": "Agent", + "settings_title": "Agent" + }, + "proxy": { + "name": "Proxy", + "settings_title": "Proxy" + }, + "browser": { + "name": "Navegador", + "settings_title": "Navegador" + }, + "extension": { + "name": "Extensión", + "settings_title": "Extensión" } }, "layout": { @@ -501,7 +1032,9 @@ "confirm": "Confirmar", "customize_request": "Personalizar solicitud", "edit_request": "Editar solicitud", + "edit_response": "Editar respuesta", "import_export": "Importación y exportación", + "response_name": "Nombre de la respuesta", "share_request": "Compartir solicitud" }, "mqtt": { @@ -535,12 +1068,81 @@ "url": "URL" }, "navigation": { + "admin_dashboard": "Panel de control", "doc": "Documentación", "graphql": "GraphQL", "profile": "Perfil", "realtime": "Tiempo real", "rest": "REST", - "settings": "Ajustes" + "mock_servers": "Servidores mock", + "settings": "Ajustes", + "goto_app": "Ir a la aplicación", + "authentication": "Autenticación" + }, + "mock_server": { + "confirm_delete_log": "¿Estás seguro de que deseas eliminar este registro?", + "create_mock_server": "Configurar servidor mock", + "mock_server_configuration": "Configuración del servidor mock", + "mock_server_name": "Nombre del servidor mock", + "mock_server_name_placeholder": "Ingresa el nombre del servidor mock", + "base_url": "URL base", + "start_server": "Iniciar servidor", + "stop_server": "Detener servidor", + "mock_server_created": "Servidor mock creado exitosamente", + "mock_server_started": "Servidor mock iniciado exitosamente", + "mock_server_stopped": "Servidor mock detenido exitosamente", + "active": "El servidor mock está activo", + "inactive": "El servidor mock está inactivo", + "edit_mock_server": "Editar servidor mock", + "path_based_url": "URL basada en ruta", + "subdomain_based_url": "URL basada en subdominio", + "mock_server_updated": "Servidor mock actualizado exitosamente", + "no_collection": "Sin colección", + "collection_deleted": "colección asociada eliminada.", + "private_access_hint": "Para servidores mock privados, incluye el encabezado 'x-api-key' con tu token de acceso personal (crea uno desde tu perfil).", + "private_access_instruction": "Para acceder a este servidor mock privado, incluye el encabezado 'x-api-key' con tu token de acceso personal.", + "create_token_here": "Crear aquí", + "status": "Estado", + "server_running": "El servidor está en ejecución", + "server_stopped": "El servidor está detenido", + "delay_ms": "Retraso de respuesta (ms)", + "delay_placeholder": "Ingresa el retraso en milisegundos", + "delay_description": "Agregar retraso artificial a las respuestas mock", + "public_access": "Acceso público", + "public": "Público", + "private": "Privado", + "public_description": "Cualquier persona con la URL puede acceder a este servidor mock", + "private_description": "Solo los usuarios autenticados pueden acceder a este servidor mock", + "select_collection": "Seleccionar una colección", + "select_collection_error": "Por favor selecciona una colección", + "invalid_collection_error": "Error al crear un servidor mock para la colección.", + "url_copied": "URL copiada al portapapeles", + "make_public": "Hacer público", + "view_logs": "Ver registros", + "logs_title": "Registros del servidor mock", + "no_logs": "No hay registros disponibles", + "request_headers": "Encabezados de la solicitud", + "request_body": "Cuerpo de la solicitud", + "response_status": "Estado de la respuesta", + "response_headers": "Encabezados de la respuesta", + "response_body": "Cuerpo de la respuesta", + "log_deleted": "Registro eliminado exitosamente", + "description": "Los servidores mock te permiten simular respuestas de API basadas en las respuestas de ejemplo de tu colección.", + "set_in_environment": "Establecer en el entorno", + "set_in_environment_hint": "La URL del servidor mock se agregará automáticamente como variable 'mockUrl' en el entorno de la colección", + "environment_variable_added": "URL mock agregada al entorno", + "environment_variable_updated": "URL mock actualizada en el entorno", + "environment_created_with_variable": "Entorno creado con URL mock", + "add_example_request": "Agregar solicitud de ejemplo", + "add_example_request_hint": "La colección se creará con una solicitud de ejemplo que demuestra cómo usar el servidor mock", + "create_example_collection": "Crear colección de ejemplo", + "create_example_collection_hint": "Crear una colección de ejemplo de tienda de mascotas con solicitudes de ejemplo (GET, POST, PUT, DELETE)", + "creating_example_collection": "Creando colección de ejemplo...", + "failed_to_create_collection": "Error al crear la colección de ejemplo", + "enable_example_collection_hint": "Por favor habilita la opción 'Crear colección de ejemplo' para el modo de nueva colección", + "new_collection_name_hint": "La colección se creará con el mismo nombre que tu servidor mock", + "existing_collection": "Colección existente", + "new_collection": "Nueva colección" }, "preRequest": { "javascript_code": "Código JavaScript", @@ -561,13 +1163,15 @@ "roles_description": "Los roles se utilizan para controlar el acceso a las colecciones compartidas.", "updated": "Perfil actualizado", "viewer": "Espectador", - "viewer_description": "Los espectadores sólo pueden ver y utilizar las solicitudes." + "viewer_description": "Los espectadores sólo pueden ver y utilizar las solicitudes.", + "verified_email_sent": "Se ha enviado un correo de verificación a tu dirección de correo electrónico. Por favor actualiza la página después de verificar tu correo electrónico. Recibirás un correo si esta dirección no está asociada con otra cuenta." }, "remove": { "star": "Eliminar estrella" }, "request": { "added": "Solicitud agregada", + "add": "Agregar solicitud", "authorization": "Autorización", "body": "Cuerpo de la solicitud", "choose_language": "Seleccionar lenguaje", @@ -575,8 +1179,10 @@ "content_type_titles": { "others": "Otros", "structured": "Estructurado", - "text": "Texto" + "text": "Texto", + "binary": "Binario" }, + "show_content_type": "Mostrar tipo de contenido", "different_collection": "No se pueden reordenar solicitudes de diferentes colecciones", "duplicated": "Solicitud duplicada", "duration": "Duración", @@ -604,6 +1210,7 @@ "rename": "Renombrar solicitud", "renamed": "Solicitud renombrada", "request_variables": "Variables de solicitud", + "response_name_exists": "El nombre de la respuesta ya existe", "run": "Ejecutar", "save": "Guardar", "save_as": "Guardar como", @@ -618,26 +1225,36 @@ "url_placeholder": "Introduce una URL o pega un comando cURL", "variables": "Variables", "view_my_links": "Ver mis enlaces", - "copy_link": "Copiar enlace" + "generate_name_error": "Error al generar el nombre de la solicitud." }, "response": { "audio": "Audio", "body": "Cuerpo de respuesta", + "duplicated": "Respuesta duplicada", + "duplicate_name_error": "Ya existe una respuesta con el mismo nombre", "filter_response_body": "Filtrar el cuerpo de la respuesta JSON (utiliza la sintaxis jq)", "headers": "Encabezados", + "request_headers": "Encabezados de la solicitud", "html": "HTML", "image": "Imagen", "json": "JSON", "pdf": "PDF", + "please_save_request": "Guarda la solicitud para crear un ejemplo", "preview_html": "Vista previa de HTML", "raw": "Sin procesar", + "renamed": "Respuesta renombrada", + "same_name_inspector_warning": "Ya existe una respuesta con este nombre para esta solicitud, si se guarda se sobrescribirá la respuesta existente", "size": "Tamaño", "status": "Estado", "time": "Tiempo", "title": "Respuesta", "video": "Video", "waiting_for_connection": "esperando la conexión", - "xml": "XML" + "xml": "XML", + "generate_data_schema": "Generar esquema de datos", + "data_schema": "Esquema de datos", + "saved": "Respuesta guardada", + "invalid_name": "Por favor proporciona un nombre para la respuesta" }, "settings": { "accent_color": "Color de acentuación", @@ -647,12 +1264,26 @@ "account_email_description": "Tu dirección de correo electrónico principal.", "account_name_description": "Este es tu nombre para mostrar.", "additional": "Configuración adicional", + "agent_not_running": "No se detectó el Agente de Hoppscotch. Por favor, verifica si el Agente está en ejecución.", + "agent_not_running_short": "Verifica el estado del Agente.", + "agent_running": "El Agente de Hoppscotch está activo.", + "agent_running_short": "El Agente de Hoppscotch está activo.", + "agent_discard_registration": "Descartar registro del Agente", + "agent_registered": "Agente registrado", + "agent_registration_successful": "Agente registrado exitosamente", + "agent_registration_fetch_failed": "No se pudo obtener la información de registro del Agente. Por favor, vuelve a registrar el Agente.", + "agent_registration_already_in_progress": "El registro del Agente ya está en progreso. Por favor, completa o cancela el registro actual e intenta de nuevo.", + "auto_encode_mode": "Automático", + "auto_encode_mode_tooltip": "Codificar los parámetros en la solicitud solo si hay caracteres especiales presentes", "background": "Fondo", "black_mode": "Negro", "choose_language": "Elegir idioma", "dark_mode": "Oscuro", "delete_account": "Eliminar cuenta", "delete_account_description": "Una vez que elimines tu cuenta, todos tus datos se borrarán permanentemente. Esta acción no se puede deshacer.", + "disable_encode_mode_tooltip": "Nunca codificar los parámetros en la solicitud", + "enable_encode_mode_tooltip": "Siempre codificar los parámetros en la solicitud", + "enter_otp": "Ingresa el código del Agente", "expand_navigation": "Expandir la navegación", "experiments": "Experimentos", "experiments_notice": "Esta es una colección de experimentos en los que estamos trabajando que podrían resultar útiles, divertidos, ambos o ninguno. No son definitivos y es posible que no sean estables, por lo que si sucede algo demasiado extraño, no se asuste. Solo apaga la maldita cosa. Fuera de bromas,", @@ -661,6 +1292,8 @@ "extensions": "Extensiones", "extensions_use_toggle": "Utilizar la extensión del navegador para enviar peticiones (si está presente)", "follow": "Síguenos", + "general": "General", + "general_description": "Configuración general utilizada en la aplicación", "interceptor": "Interceptador", "interceptor_description": "Middleware entre la aplicación y las APIs.", "kernel_interceptor": "Interceptador", @@ -668,23 +1301,39 @@ "language": "Idioma", "light_mode": "Luz", "official_proxy_hosting": "El proxy oficial está alojado en Hoppscotch.", + "query_parameters_encoding": "Codificación de parámetros de consulta", + "query_parameters_encoding_description": "Configura la codificación para los parámetros de consulta en las solicitudes", "profile": "Perfil", "profile_description": "Actualiza los datos de tu perfil", "profile_email": "Correo electrónico", "profile_name": "Nombre de perfil", + "profile_photo": "Foto de perfil", "proxy": "Proxy", "proxy_url": "URL de proxy", "proxy_use_toggle": "Utilizar el middleware de proxy para enviar peticiones", "read_the": "Leer el", + "register_agent": "Registrar Agente", "reset_default": "Restablecer a los predeterminados", "short_codes": "Shortcodes", "short_codes_description": "Shortcodes creados por ti.", "sidebar_on_left": "Barra lateral a la izquierda", + "ai_experiments": "Experimentos de AI", + "ai_request_naming_style": "Estilo de nomenclatura de solicitudes", + "ai_request_naming_style_descriptive_with_spaces": "Descriptivo con espacios", + "ai_request_naming_style_camel_case": "Camel Case ( camelCase )", + "ai_request_naming_style_snake_case": "Snake Case ( snake_case )", + "ai_request_naming_style_pascal_case": "Pascal Case ( PascalCase )", + "ai_request_naming_style_custom": "Personalizado", + "ai_request_naming_style_custom_placeholder": "Ingresa tu plantilla de estilo de nomenclatura personalizada...", + "experimental_scripting_sandbox": "Sandbox de scripting experimental", + "enable_experimental_mock_servers": "Habilitar servidores mock", + "enable_experimental_documentation": "Habilitar documentación", "sync": "Sincronizar", "sync_collections": "Colecciones", "sync_description": "Esta configuración se sincroniza con la nube.", "sync_environments": "Entornos", "sync_history": "Historial", + "history_disabled": "El historial está deshabilitado. Contacta al administrador de tu organización para habilitarlo", "system_mode": "Sistema", "telemetry": "Telemetría", "telemetry_helps_us": "La telemetría nos ayuda a personalizar nuestras operaciones y brindarte la mejor experiencia.", @@ -694,10 +1343,33 @@ "user": "Usuario", "verified_email": "Correo electrónico verificado", "verify_email": "Verificar correo electrónico", - "general": "General", - "general_description": "Configuración general utilizada en la aplicación", - "query_parameters_encoding": "Codificación de parámetros de consulta", - "query_parameters_encoding_description": "Configura la codificación para los parámetros de consulta en las solicitudes" + "validate_certificates": "Validar certificados SSL/TLS", + "verify_host": "Verificar host", + "verify_peer": "Verificar par", + "follow_redirects": "Seguir redirecciones", + "client_certificates": "Certificados de cliente", + "certificate_settings": "Configuración de certificados", + "certificate": "Certificado", + "key": "Clave privada", + "pfx_or_p12": "PFX/PKCS#12", + "password": "Contraseña", + "select_file": "Seleccionar archivo", + "domain": "Dominio", + "add_certificate": "Agregar certificado", + "add_cert_file": "Agregar archivo de certificado", + "add_key_file": "Agregar archivo de clave", + "add_pfx_file": "Agregar archivo PFX", + "global_defaults": "Valores predeterminados globales", + "add_domain_override": "Agregar anulación de dominio", + "domain_override": "Anulación de dominio", + "manage_domains_overrides": "Administrar anulaciones de dominio", + "add_domain": "Agregar dominio", + "remove_domain": "Eliminar dominio", + "ca_certificate": "Certificado CA", + "ca_certificates": "Certificados CA", + "ca_certificates_support": "Hoppscotch admite archivos .crt, .cer o .pem que contengan uno o más certificados.", + "proxy_capabilities": "El Agente de Hoppscotch y la aplicación de escritorio admiten proxies HTTP/HTTPS/SOCKS con soporte para NTLM y autenticación básica.", + "proxy_auth": "También puedes incluir el nombre de usuario y la contraseña en la URL." }, "shared_requests": { "button": "Botón", @@ -723,7 +1395,25 @@ "light": "Claro", "system": "Sistema", "title": "Tema" - } + }, + "action": "Acción", + "clear_filter": "Limpiar filtro", + "confirm_request_deletion": "¿Confirmas la eliminación de la solicitud compartida seleccionada?", + "copy": "Copiar", + "created_on": "Fecha de creación", + "delete": "Eliminar", + "email": "Correo electrónico", + "filter": "Filtrar", + "filter_by_email": "Filtrar por correo electrónico", + "id": "ID", + "load_list_error": "No se pudo cargar la lista de solicitudes compartidas", + "no_requests": "No se encontraron solicitudes compartidas", + "open_request": "Abrir solicitud", + "properties": "Propiedades", + "request": "Solicitud", + "show_more": "Mostrar más", + "title": "Solicitudes compartidas", + "url": "URL" }, "shortcut": { "general": { @@ -731,7 +1421,11 @@ "command_menu": "Menú de búsqueda y comandos", "help_menu": "Menú de ayuda", "show_all": "Atajos de teclado", - "title": "General" + "title": "General", + "comment_uncomment": "Comentar/Descomentar", + "close_tab": "Cerrar pestaña", + "undo": "Deshacer", + "redo": "Rehacer" }, "miscellaneous": { "invite": "Invita a tus amigos a Hoppscotch", @@ -770,13 +1464,25 @@ "share_request": "Compartir solicitud", "show_code": "Generar fragmento de código", "title": "Solicitud", - "copy_request_link": "Copiar enlace de solicitud" + "focus_url": "Enfocar barra de URL" }, "response": { "copy": "Copiar la respuesta al portapapeles", "download": "Descargar la respuesta como archivo", "title": "Respuesta" }, + "tabs": { + "title": "Pestañas", + "new_tab": "Nueva pestaña", + "close_tab": "Cerrar pestaña", + "reopen_tab": "Reabrir pestaña cerrada", + "next_tab": "Siguiente pestaña", + "previous_tab": "Pestaña anterior", + "first_tab": "Cambiar a la primera pestaña", + "last_tab": "Cambiar a la última pestaña", + "mru_switch": "Cambiar a pestaña reciente (MRU)", + "mru_switch_reverse": "Cambiar a pestaña reciente anterior (MRU)" + }, "theme": { "black": "Cambiar el tema al modo negro", "dark": "Cambiar el tema al modo oscuro", @@ -789,7 +1495,8 @@ "code": "Mostrar código", "collection": "Ampliar el panel de colecciones", "more": "Mostrar más", - "sidebar": "Mostrar barra lateral" + "sidebar": "Mostrar barra lateral", + "password": "Mostrar contraseña" }, "socketio": { "communication": "Comunicación", @@ -867,6 +1574,12 @@ "close_others": "Cerrar todas las demás pestañas", "duplicate": "Duplicar pestaña actual", "new_tab": "Abrir una nueva pestaña", + "next": "Cambiar a la siguiente pestaña", + "previous": "Cambiar a la pestaña anterior", + "switch_to_first": "Cambiar a la primera pestaña", + "switch_to_last": "Cambiar a la última pestaña", + "mru_switch": "Cambiar a pestaña reciente", + "mru_switch_reverse": "Cambiar a pestaña reciente anterior", "title": "Pestañas" }, "workspace": { @@ -874,7 +1587,7 @@ "edit": "Editar el espacio de trabajo actual", "invite": "Invitar al espacio de trabajo", "new": "Crear un nuevo espacio de trabajo", - "switch_to_personal": "Cambia a tu espacio de trabajo personal", + "switch_to_personal": "Cambiar a tu espacio de trabajo personal", "title": "Espacio de trabajo" }, "phrases": { @@ -911,6 +1624,7 @@ "download_failed": "Descarga fallida", "download_started": "Descarga iniciada", "enabled": "Activado", + "experimental": "Experimental", "file_imported": "Archivo importado", "finished_in": "Terminado en {duration}ms", "hide": "Ocultar", @@ -919,17 +1633,127 @@ "loading": "Cargando...", "message_received": "Mensaje: llegó {message} al: {topic}", "mqtt_subscription_failed": "Algo ha ido mal al suscribirse al tema: {topic}", + "no_content_found": "No se encontró contenido", "none": "Ninguno", "nothing_found": "Nada encontrado para", "published_error": "Algo ha ido mal al publicar el mensaje: {message} al tema: {topic}", "published_message": "Mensaje publicado: {message} al tema: {topic}", "reconnection_error": "Fallo en la reconexión", + "saved": "Guardado", "show": "Mostrar", "subscribed_failed": "Error al suscribirse al tema: {topic}", "subscribed_success": "Suscrito con éxito al tema: {topic}", "unsubscribed_failed": "Error al darse de baja del tema: {topic}", "unsubscribed_success": "Se ha cancelado la suscripción al tema: {topic}", - "waiting_send_request": "Esperando para enviar solicitud" + "waiting_send_request": "Esperando para enviar solicitud", + "user_deactivated": "Tu cuenta está desactivada. Por favor, contacta al administrador para reactivar tu cuenta.", + "add_user_failure": "No se pudo agregar al usuario al espacio de trabajo.", + "add_user_success": "El usuario ahora es miembro del espacio de trabajo.", + "admin_failure": "No se pudo asignar el rol de administrador al usuario.", + "admin_success": "El usuario ahora es administrador.", + "and": "y", + "clear_selection": "Limpiar selección", + "configure_auth": "Por favor, configura un proveedor de autenticación desde la configuración de administrador o consulta la documentación para configurar proveedores de autenticación.", + "confirm_admin_to_user": "¿Deseas remover el estado de administrador de este usuario?", + "confirm_admins_to_users": "¿Deseas remover el estado de administrador de los usuarios seleccionados?", + "confirm_delete_infra_token": "¿Estás seguro de que deseas eliminar el token de infraestructura {tokenLabel}?", + "confirm_delete_invite": "¿Deseas revocar la invitación seleccionada?", + "confirm_delete_invites": "¿Deseas revocar las invitaciones seleccionadas?", + "confirm_user_deletion": "¿Confirmas la eliminación del usuario?", + "confirm_users_deletion": "¿Deseas eliminar los usuarios seleccionados?", + "confirm_user_to_admin": "¿Deseas convertir a este usuario en administrador?", + "confirm_users_to_admin": "¿Deseas convertir a los usuarios seleccionados en administradores?", + "confirm_user_deactivation": "¿Confirmas la desactivación del usuario?", + "confirm_logout": "Confirmar cierre de sesión", + "created_on": "Fecha de creación", + "continue_email": "Continuar con correo electrónico", + "continue_github": "Continuar con GitHub", + "continue_google": "Continuar con Google", + "continue_microsoft": "Continuar con Microsoft", + "create_team_failure": "No se pudo crear el espacio de trabajo.", + "create_team_success": "Espacio de trabajo creado exitosamente.", + "data_sharing_failure": "No se pudo actualizar la configuración de uso compartido de datos", + "delete_infra_token_failure": "Algo salió mal al eliminar el token de infraestructura", + "delete_invite_failure": "No se pudo eliminar la invitación.", + "delete_invites_failure": "No se pudieron eliminar las invitaciones seleccionadas.", + "delete_invite_success": "Invitación eliminada exitosamente.", + "delete_invites_success": "Invitaciones seleccionadas eliminadas exitosamente.", + "delete_request_failure": "No se pudo eliminar la solicitud compartida.", + "delete_request_success": "Solicitud compartida eliminada exitosamente.", + "delete_team_failure": "No se pudo eliminar el espacio de trabajo.", + "delete_team_success": "Espacio de trabajo eliminado exitosamente.", + "delete_some_users_failure": "Cantidad de usuarios no eliminados: {count}", + "delete_some_users_success": "Cantidad de usuarios eliminados: {count}", + "delete_user_failed_only_one_admin": "No se pudo eliminar al usuario. Debe haber al menos un administrador.", + "delete_user_failure": "No se pudo eliminar al usuario.", + "delete_users_failure": "No se pudieron eliminar los usuarios seleccionados.", + "delete_user_success": "Usuario eliminado exitosamente.", + "delete_users_success": "Usuarios seleccionados eliminados exitosamente.", + "email": "Correo electrónico", + "email_failure": "No se pudo enviar la invitación", + "email_signin_failure": "No se pudo iniciar sesión con correo electrónico", + "email_success": "Invitación por correo electrónico enviada exitosamente", + "emails_cannot_be_same": "No puedes invitarte a ti mismo, por favor elige una dirección de correo electrónico diferente.", + "enter_team_email": "Por favor, ingresa el correo electrónico del propietario del espacio de trabajo.", + "error": "Algo salió mal", + "error_auth_providers": "No se pudieron cargar los proveedores de autenticación", + "generate_infra_token_failure": "Algo salió mal al generar el token de infraestructura", + "github_signin_failure": "No se pudo iniciar sesión con GitHub", + "google_signin_failure": "No se pudo iniciar sesión con Google", + "infra_token_label_short": "La etiqueta del token de infraestructura es demasiado corta.", + "invalid_email": "Por favor, ingresa una dirección de correo electrónico válida", + "link_copied_to_clipboard": "Enlace copiado al portapapeles", + "logged_out": "Sesión cerrada", + "login_as_admin": "e inicia sesión con una cuenta de administrador.", + "login_using_email": "Por favor, pide al usuario que revise su correo electrónico o comparte el enlace a continuación", + "login_using_link": "Por favor, pide al usuario que inicie sesión usando el enlace a continuación", + "logout": "Cerrar sesión", + "magic_link_sign_in": "Haz clic en el enlace para iniciar sesión.", + "magic_link_success": "Enviamos un enlace mágico a", + "microsoft_signin_failure": "No se pudo iniciar sesión con Microsoft", + "newsletter_failure": "No se pudo actualizar la configuración del boletín", + "non_admin_logged_in": "Sesión iniciada como usuario no administrador.", + "non_admin_login": "Has iniciado sesión, pero no eres administrador", + "owner_not_present": "Debe haber al menos un propietario en el equipo.", + "privacy_policy": "Política de privacidad", + "reenter_email": "Vuelve a ingresar el correo electrónico", + "remove_admin_failure": "No se pudo remover el estado de administrador.", + "remove_admin_failure_only_one_admin": "No se pudo remover el estado de administrador. Debe haber al menos un administrador.", + "remove_admin_success": "Estado de administrador removido.", + "remove_admin_from_users_failure": "No se pudo remover el estado de administrador de los usuarios seleccionados.", + "remove_admin_from_users_success": "Estado de administrador removido de los usuarios seleccionados.", + "remove_admin_to_delete_user": "Remueve el privilegio de administrador para eliminar al usuario.", + "remove_owner_to_delete_user": "Remueve el estado de propietario del equipo para eliminar al usuario.", + "remove_owner_failure_only_one_owner": "No se pudo remover al miembro. Debe haber al menos un propietario en el equipo.", + "remove_admin_for_deletion": "Remueve el estado de administrador antes de intentar la eliminación.", + "remove_owner_for_deletion": "Uno o más usuarios son propietarios de equipos. Actualiza la propiedad antes de la eliminación.", + "remove_invitee_failure": "No se pudo remover al invitado.", + "remove_invitee_success": "Invitado removido exitosamente.", + "remove_member_failure": "No se pudo remover al miembro.", + "remove_member_success": "Miembro removido exitosamente.", + "rename_team_failure": "No se pudo renombrar el espacio de trabajo.", + "rename_team_success": "Espacio de trabajo renombrado exitosamente.", + "rename_user_failure": "No se pudo renombrar al usuario.", + "rename_user_success": "Usuario renombrado exitosamente.", + "require_auth_provider": "Necesitas configurar al menos un proveedor de autenticación para iniciar sesión.", + "role_update_failed": "La actualización de roles ha fallado.", + "role_update_success": "Roles actualizados exitosamente.", + "selected": "{count} seleccionados", + "self_host_docs": "Documentación de autoalojamiento", + "send_magic_link": "Enviar enlace mágico", + "setup_failure": "La configuración ha fallado.", + "setup_success": "Configuración completada exitosamente.", + "sign_in_agreement": "Al iniciar sesión, aceptas nuestros", + "sign_in_options": "Todas las opciones de inicio de sesión", + "sign_out": "Cerrar sesión", + "something_went_wrong": "Algo salió mal", + "team_name_too_short": "El nombre del espacio de trabajo debe tener al menos 6 caracteres.", + "user_already_invited": "No se pudo enviar la invitación. El usuario ya fue invitado.", + "user_not_found": "Usuario no encontrado en la infraestructura.", + "users_to_admin_success": "Los usuarios seleccionados fueron elevados a estado de administrador.", + "users_to_admin_failure": "No se pudo elevar a los usuarios seleccionados a estado de administrador.", + "loading_workspaces": "Cargando espacios de trabajo", + "loading_collections_in_workspace": "Cargando colecciones en el espacio de trabajo" }, "support": { "changelog": "Leer más sobre los últimos lanzamientos", @@ -937,11 +1761,10 @@ "community": "Haz preguntas y ayuda a los demás", "documentation": "Leer más sobre Hoppscotch", "forum": "Haz preguntas y obtén respuestas", - "github": "Síguenos en Github", + "github": "Síguenos en GitHub", "shortcuts": "Navega por la aplicación más rápido", "title": "Ayuda", - "twitter": "Síguenos en Twitter", - "team": "Ponte en contacto con el equipo" + "twitter": "Síguenos en Twitter" }, "tab": { "authorization": "Autorización", @@ -956,6 +1779,7 @@ "history": "Historial", "mqtt": "MQTT", "parameters": "Parámetros", + "post_request_script": "Script post-solicitud", "pre_request_script": "Script previo a la solicitud", "queries": "Consultas", "query": "Consulta", @@ -963,18 +1787,27 @@ "shared_requests": "Solicitudes compartidas", "codegen": "Generar código", "code_snippet": "Fragmento de código", + "mock_servers": "Servidores mock", "share_tab_request": "Compartir solicitud de pestaña", "socketio": "Socket.IO", "sse": "SSE", - "tests": "Pruebas", "types": "Tipos", "variables": "Variables", - "websocket": "WebSocket" + "websocket": "WebSocket", + "all_tests": "Todas las pruebas", + "passed": "Aprobadas", + "failed": "Fallidas" }, "team": { + "activity_logs": "Registros de actividad", "already_member": "Ya eres miembro de este espacio de trabajo. Ponte en contacto con el propietario del espacio de trabajo.", "create_new": "Crear nuevo espacio de trabajo", "deleted": "Espacio de trabajo eliminado", + "delete_all_activity_logs": "Eliminar todos los registros de actividad", + "successfully_deleted_all_activity_logs": "Todos los registros de actividad se eliminaron exitosamente", + "delete_activity_log": "Eliminar registro de actividad", + "deleted_activity_log": "Se eliminó el registro de actividad seleccionado", + "deleted_all_activity_logs": "Se eliminaron todos los registros de actividad", "edit": "Editar espacio de trabajo", "email": "Correo electrónico", "email_do_not_match": "El correo electrónico no coincide con los datos de tu cuenta. Ponte en contacto con el propietario del espacio de trabajo.", @@ -1029,7 +1862,8 @@ "invite_sent_smtp_disabled_description": "El envío de correos electrónicos de invitación está deshabilitado para esta instancia de Hoppscotch. Utiliza el botón Copiar enlace para copiar y compartir el enlace de invitación manualmente.", "copy_invite_link": "Copiar enlace de invitación", "search_title": "Solicitudes del espacio de trabajo", - "join_beta": "Únete al programa beta para acceder a los espacio de trabajos." + "user_not_found": "Usuario no encontrado en la instancia.", + "invite_members": "Invitar miembros" }, "team_environment": { "deleted": "Entorno eliminado", @@ -1037,6 +1871,8 @@ "not_found": "Entorno no encontrado." }, "test": { + "requests": "Solicitudes", + "selection": "Selección", "failed": "prueba fallida", "javascript_code": "Código JavaScript", "learn": "Leer documentación", @@ -1044,7 +1880,14 @@ "report": "Informe de pruebas", "results": "Resultados de las pruebas", "script": "Script", - "snippets": "Fragmentos" + "snippets": "Fragmentos", + "run": "Ejecutar", + "run_again": "Ejecutar de nuevo", + "stop": "Detener", + "new_run": "Nueva ejecución", + "iterations": "Iteraciones", + "duration": "Duración", + "avg_resp": "Tiempo de respuesta prom." }, "websocket": { "communication": "Comunicación", @@ -1094,19 +1937,394 @@ "cli_environment_id_description": "Este ID de entorno será utilizado por el CLI collection runner para Hoppscotch.", "include_active_environment": "Incluir un entorno activo:", "cli": "CLI", + "cli_comming_soon_for_personal_collection": "El ejecutor de colecciones para colecciones personales en CLI estará disponible próximamente.", + "delay": "Retraso", + "negative_delay": "El retraso no puede ser negativo", "ui": "Runner (próximamente)", + "running_collection": "Ejecutando colección", + "run_config": "Configuración de ejecución", + "advanced_settings": "Configuración avanzada", + "stop_on_error": "Detener la ejecución si ocurre un error", + "persist_responses": "Persistir respuestas", + "keep_variable_values": "Mantener valores de variables", + "collection_not_found": "Colección no encontrada. Puede haber sido eliminada o movida.", + "empty_collection": "La colección está vacía. Agrega solicitudes para ejecutar.", + "no_response_persist": "El ejecutor de colecciones está configurado actualmente para no persistir respuestas. Esta configuración impide mostrar los datos de respuesta. Para modificar este comportamiento, inicia una nueva configuración de ejecución.", + "select_request": "Selecciona una solicitud para ver la respuesta y los resultados de las pruebas", + "response_body_lost_rerun": "El cuerpo de la respuesta se perdió. Ejecuta la colección de nuevo para obtener el cuerpo de la respuesta.", "cli_command_generation_description_cloud": "Copia el siguiente comando y ejecútalo desde la CLI. Por favor, especifica un token de acceso personal.", "cli_command_generation_description_sh": "Copia el siguiente comando y ejecútalo desde la CLI. Por favor, especifica un token de acceso personal y verifica la URL generada del servidor de instancias SH.", "cli_command_generation_description_sh_with_server_url_placeholder": "Copia el siguiente comando y ejecútalo desde la CLI. Por favor, especifica un token de acceso personal y la URL del servidor de instancias SH.", - "run_collection": "Ejecutar colección" + "run_collection": "Ejecutar colección", + "no_passed_tests": "Ninguna prueba aprobada", + "no_failed_tests": "Ninguna prueba fallida" }, - "shortcodes": { - "actions": "Acciones", - "created_on": "Creado el", - "deleted": "Código corto eliminado", - "method": "Método", - "not_found": "Shortcode no encontrado", - "short_code": "Shortcode", - "url": "URL" + "ai_experiments": { + "generate_request_name": "Generar nombre de solicitud con AI", + "generate_or_modify_request_body": "Generar o modificar cuerpo de solicitud", + "modify_with_ai": "Modificar con AI", + "generate": "Generar", + "generate_or_modify_request_body_input_placeholder": "Ingresa tu prompt para modificar el cuerpo de la solicitud", + "accept_change": "Aceptar cambio", + "feedback_success": "Comentario enviado exitosamente", + "feedback_failure": "No se pudo enviar el comentario", + "feedback_thank_you": "¡Gracias por tu comentario!", + "feedback_cta_text_long": "Califica la generación, nos ayuda a mejorar", + "feedback_cta_request_name": "¿Te gustó el nombre generado?", + "modify_request_body_error": "No se pudo modificar el cuerpo de la solicitud", + "generate_or_modify_prerequest_input_placeholder": "Ingresa un prompt para generar o modificar el script de pre-solicitud", + "generate_or_modify_post_request_script_input_placeholder": "Ingresa un prompt para generar o modificar el script de post-solicitud", + "modify_post_request_script_error": "No se pudo modificar el script de post-solicitud", + "modify_prerequest_error": "No se pudo modificar el script de pre-solicitud" + }, + "configs": { + "auth_providers": { + "callback_url": "URL DE CALLBACK", + "client_id": "ID DE CLIENTE", + "client_secret": "SECRETO DE CLIENTE", + "description": "Configura los proveedores de autenticación para tu servidor", + "provider_not_specified": "Por favor, habilita al menos un proveedor de autenticación", + "scope": "ALCANCE", + "tenant": "TENANT", + "title": "Proveedores de autenticación", + "update_failure": "No se pudieron actualizar las configuraciones del proveedor de autenticación." + }, + "confirm_changes": "El servidor de Hoppscotch debe reiniciarse para reflejar los nuevos cambios. ¿Confirmas los cambios realizados en las configuraciones del servidor?", + "input_empty": "Por favor, completa todos los campos antes de actualizar las configuraciones", + "data_sharing": { + "title": "Uso compartido de datos", + "description": "Ayuda a mejorar Hoppscotch compartiendo datos anónimos", + "enable": "Habilitar uso compartido de datos", + "secondary_title": "Configuraciones de uso compartido de datos", + "see_shared": "Ver qué se comparte", + "toggle_description": "Compartir datos anónimos", + "update_failure": "No se pudieron actualizar las configuraciones de uso compartido de datos." + }, + "load_error": "No se pudieron cargar las configuraciones del servidor", + "mail_configs": { + "address_from": "DIRECCIÓN DE REMITENTE", + "custom_smtp_configs": "Usar configuraciones SMTP personalizadas", + "description": "Configura las configuraciones de SMTP", + "enable_email_auth": "Habilitar autenticación basada en correo electrónico", + "enable_smtp": "Habilitar SMTP", + "host": "HOST DEL SERVIDOR DE CORREO", + "password": "CONTRASEÑA DEL SERVIDOR DE CORREO", + "port": "PUERTO DEL SERVIDOR DE CORREO", + "secure": "SERVIDOR DE CORREO SEGURO", + "smtp_url": "URL SMTP DEL SERVIDOR DE CORREO", + "tls_reject_unauthorized": "TLS RECHAZAR NO AUTORIZADO", + "title": "Configuraciones SMTP", + "toggle_failure": "No se pudo activar/desactivar SMTP.", + "update_failure": "No se pudieron actualizar las configuraciones SMTP.", + "user": "USUARIO DEL SERVIDOR DE CORREO" + }, + "reset": { + "confirm_reset": "El servidor de Hoppscotch debe reiniciarse para reflejar los nuevos cambios. ¿Confirmas el restablecimiento de las configuraciones del servidor?", + "description": "Se cargarán las configuraciones predeterminadas según lo especificado en el archivo de entorno", + "failure": "No se pudieron restablecer las configuraciones.", + "title": "Restablecer configuraciones", + "info": "Restablecer configuraciones del servidor" + }, + "restart": { + "description": "Quedan {duration} segundos antes de que esta página se recargue automáticamente", + "initiate": "Iniciando reinicio del servidor...", + "title": "El servidor se está reiniciando" + }, + "save_changes": "Guardar cambios", + "title": "Configuraciones", + "update_failure": "No se pudieron actualizar las configuraciones del servidor", + "restrict_access": "Restringir acceso", + "site_protection": { + "control_access": "Controla quién puede acceder a la aplicación de Hoppscotch", + "description": "Personaliza cómo los visitantes acceden a tu aplicación de Hoppscotch usando la configuración de protección del sitio.", + "enable": "Habilitar protección del sitio", + "note": "Los usuarios que visiten la aplicación de Hoppscotch verán la página de inicio de sesión; es obligatorio iniciar sesión para acceder a la aplicación. La aprobación del administrador sigue siendo necesaria para la autorización", + "update_failure": "No se pudieron actualizar las configuraciones de protección del sitio." + }, + "domain_whitelisting": { + "add_domain": "Agregar nuevo dominio", + "description": "Los usuarios con correo electrónico registrado en dominios de la lista blanca no requieren aprobación explícita del administrador para acceder a la aplicación de Hoppscotch", + "enable": "Habilitar lista blanca de dominios", + "enter_domain": "Ingresa el dominio", + "title": "Dominios en lista blanca", + "toggle_failure": "No se pudo activar/desactivar la lista blanca de dominios", + "update_failure": "No se pudieron actualizar las configuraciones de lista blanca de dominios." + }, + "oidc_configs": { + "auth_url": "URL de autenticación", + "callback_url": "URL de callback", + "client_id": "ID de cliente", + "client_secret": "Secreto de cliente", + "description": "Configura las configuraciones de OIDC", + "enable": "Habilitar autenticación basada en OIDC", + "issuer": "Emisor", + "provider_name": "Nombre del proveedor", + "scope": "Alcance", + "title": "Configuraciones OIDC", + "token_url": "URL de token", + "update_failure": "No se pudieron actualizar las configuraciones de OIDC.", + "user_info_url": "URL de información del usuario" + }, + "saml": { + "audience": "Audiencia", + "callback_url": "URL de callback", + "certificate": "Certificado", + "description": "Configura las configuraciones de SAML", + "enable": "Habilitar autenticación basada en SAML", + "entry_point": "Punto de entrada", + "issuer": "Emisor", + "title": "Configuraciones SAML", + "update_failure": "No se pudieron actualizar las configuraciones de SAML SSO.", + "want_assertions_signed": "Firmar aserciones", + "want_response_signed": "Firmar respuesta" + } + }, + "data_sharing": { + "description": "Comparte datos de uso anónimos para mejorar Hoppscotch", + "enable": "Habilitar uso compartido de datos", + "see_shared": "Ver qué se comparte", + "toggle_description": "Comparte datos y ayuda a mejorar Hoppscotch", + "title": "Mejora Hoppscotch", + "welcome": "Bienvenido a" + }, + "infra_tokens": { + "copy_token_warning": "Asegúrate de copiar tu token de infraestructura ahora. No podrás verlo de nuevo.", + "deletion_success": "El token de infraestructura {label} ha sido eliminado", + "empty": "No hay tokens de infraestructura", + "expired": "Expirado", + "expiration_label": "Expiración", + "expires_on": "Expira el", + "generate_modal_title": "Nuevo token de infraestructura", + "generate_new_token": "Generar nuevo token", + "generate_token": "Generar token", + "invalid_label": "Por favor, proporciona una etiqueta para el token", + "last_used_on": "Último uso el", + "no_expiration": "Sin expiración", + "no_expiration_verbose": "Este token nunca expirará.", + "section_description": "Administra tus usuarios de Hoppscotch a través de API con tokens de infraestructura", + "section_title": "Tokens de infraestructura", + "tab_title": "Tokens de infraestructura", + "token_expires_on": "Este token expirará el", + "token_purpose": "Ingresa una etiqueta para identificar este token" + }, + "metrics": { + "dashboard": "Panel de control", + "no_metrics": "No se encontraron métricas", + "total_collections": "Total de colecciones", + "total_requests": "Total de solicitudes", + "total_teams": "Total de espacios de trabajo", + "total_users": "Total de usuarios" + }, + "newsletter": { + "description": "Recibe actualizaciones sobre nuestras últimas noticias", + "subscribe": "Suscribirse", + "title": "Mantente en contacto", + "toggle_description": "Recibe actualizaciones sobre las novedades de Hoppscotch", + "unsubscribe": "Cancelar suscripción" + }, + "teams": { + "add_member": "Agregar miembro", + "add_members": "Agregar miembros", + "add_new": "Agregar nuevo", + "admin": "Administrador", + "admin_Email": "Correo del administrador", + "admin_id": "ID del administrador", + "cancel": "Cancelar", + "confirm_team_deletion": "¿Confirmas la eliminación del espacio de trabajo?", + "copy": "Copiar", + "create_team": "Crear espacio de trabajo", + "date": "Fecha", + "delete_team": "Eliminar espacio de trabajo", + "details": "Detalles", + "edit": "Editar", + "editor": "EDITOR", + "editor_description": "Los editores pueden agregar, editar y eliminar solicitudes y colecciones.", + "email": "Correo del propietario del espacio de trabajo", + "email_address": "Dirección de correo electrónico", + "email_title": "Correo electrónico", + "empty_name": "El nombre del equipo no puede estar vacío.", + "error": "Algo salió mal. Por favor, intenta de nuevo más tarde.", + "id": "ID del espacio de trabajo", + "invited_email": "Correo del invitado", + "invited_on": "Fecha de invitación", + "invites": "Invitaciones", + "load_info_error": "No se pudo cargar la información del espacio de trabajo", + "load_list_error": "No se pudo cargar la lista de espacios de trabajo", + "members": "Cantidad de miembros", + "no_invite": "Sin invitaciones", + "no_invite_description": "Invita a tu equipo para comenzar a colaborar", + "owner": "PROPIETARIO", + "owner_description": "Los propietarios pueden agregar, editar y eliminar solicitudes, colecciones y miembros del espacio de trabajo.", + "permissions": "Permisos", + "name": "Nombre del espacio de trabajo", + "no_members": "No hay miembros en este espacio de trabajo. Agrega miembros a este espacio de trabajo para colaborar", + "no_pending_invites": "No hay invitaciones pendientes", + "no_teams": "No se encontraron espacios de trabajo.", + "no_teams_description": "Crea un espacio de trabajo para colaborar con tu equipo", + "pending_invites": "Invitaciones pendientes", + "roles": "Roles", + "roles_description": "Los roles se usan para controlar el acceso a las colecciones compartidas.", + "remove": "Eliminar", + "rename": "Renombrar", + "save": "Guardar", + "save_changes": "Guardar cambios", + "send_invite": "Enviar invitación", + "show_more": "Mostrar más", + "team_details": "Detalles del espacio de trabajo", + "team_members": "Miembros", + "team_members_tab": "Miembros del espacio de trabajo", + "teams": "Espacio de trabajo", + "uid": "UID", + "unnamed": "(Espacio de trabajo sin nombre)", + "viewer": "VISOR", + "viewer_description": "Los visores solo pueden ver y usar solicitudes", + "valid_name": "Por favor, ingresa un nombre de espacio de trabajo válido", + "valid_owner_email": "Por favor, ingresa un correo electrónico de propietario válido" + }, + "users": { + "add_user": "Agregar usuario", + "admin": "Administrador", + "admin_id": "ID del administrador", + "cancel": "Cancelar", + "created_on": "Fecha de creación", + "copy_invite_link": "Copiar enlace de invitación", + "copy_link": "Copiar enlace", + "date": "Fecha", + "delete": "Eliminar", + "delete_user": "Eliminar usuario", + "delete_users": "Eliminar usuarios", + "details": "Detalles", + "edit": "Editar", + "email": "Correo electrónico", + "email_address": "Dirección de correo electrónico", + "empty_name": "El nombre no puede estar vacío.", + "id": "ID de usuario", + "invalid_user": "Usuario no válido", + "invite_load_list_error": "No se pudo cargar la lista de usuarios invitados", + "invite_user": "Invitar usuario", + "invited_by": "Invitado por", + "invited_on": "Fecha de invitación", + "invited_users": "Usuarios invitados", + "invitee_email": "Correo del invitado", + "last_active_on": "Última actividad", + "load_info_error": "No se pudo cargar la información del usuario", + "load_list_error": "No se pudo cargar la lista de usuarios", + "make_admin": "Convertir en administrador", + "name": "Nombre", + "new_user_added": "Nuevo usuario agregado", + "no_invite": "No se encontraron invitaciones pendientes", + "no_invite_description": "No hay invitaciones pendientes. Comienza a invitar a tus compañeros de equipo a Hoppscotch", + "no_shared_requests": "No hay solicitudes compartidas creadas por el usuario", + "no_users": "No se encontraron usuarios", + "not_available": "No disponible", + "not_found": "Usuario no encontrado", + "pending_invites": "Invitaciones pendientes", + "remove_admin_privilege": "Remover privilegio de administrador", + "remove_admin_status": "Remover estado de administrador", + "rename": "Renombrar", + "revoke_invitation": "Revocar invitación", + "searchbar_placeholder": "Buscar por nombre o correo electrónico...", + "send_invite": "Enviar invitación", + "show_more": "Mostrar más", + "uid": "UID", + "unnamed": "(Usuario sin nombre)", + "user_not_found": "Usuario no encontrado en la infraestructura.", + "users": "Usuarios", + "valid_email": "Por favor, ingresa una dirección de correo electrónico válida", + "deactivate": "Desactivar", + "deactivate_user": "Desactivar usuario" + }, + "organization": { + "login_to_continue_description": "Necesitas iniciar sesión para unirte a una instancia de organización.", + "create_an_organization": "Crear una organización", + "deactivate_user_failure": "No se pudo desactivar al usuario.", + "deactivate_user_success": "Usuario desactivado exitosamente.", + "delete_account_description": "Esto eliminará todos los datos asociados con tu cuenta de Hoppscotch, incluyendo esta y cualquier otra organización de la que formes parte.", + "delete_account": "Eliminar cuenta de Hoppscotch", + "user_deletion_failed_sole_admin": "El usuario es el único administrador de una o más instancias de organización. Por favor, degrada al usuario antes de intentar la eliminación.", + "user_deletion_failed_sole_team_owner": "El usuario es el único propietario de equipo en una o más instancias de organización. Por favor, transfiere la propiedad o elimina los espacios de trabajo correspondientes antes de intentar la eliminación.", + "no_organizations": "No eres miembro de ninguna organización", + "admin": "Administrador" + }, + "organization_sidebar": { + "hoppscotch_cloud": "Hoppscotch Cloud", + "cloud_locked": "La instancia predeterminada no se puede eliminar", + "admin": "Administrador", + "error_loading": "No se pudieron cargar las organizaciones", + "inactive_orgs": "Organizaciones inactivas", + "no_orgs_found": "No se encontraron organizaciones", + "no_active_orgs_found": "No hay organizaciones activas", + "organizations_for": "Organizaciones para {email}", + "multi_account_notice": "Cada organización mantiene su propio inicio de sesión, utilizando la última cuenta a la que se accedió.", + "inactive_orgs_tooltip": "Contacta a soporte para obtener asistencia." + }, + "billing": { + "confirm": { + "update_seat_count": "¿Estás seguro de que deseas actualizar la cantidad de puestos a {newSeatCount}?", + "update_billing_cycle": "¿Estás seguro de que deseas actualizar el ciclo de facturación a {newBillingCycle}?" + }, + "cancel_subscription": "Cancelar suscripción" + }, + "app_console": { + "entries": "Entradas de consola", + "no_entries": "Sin entradas" + }, + "mockServer": { + "create_modal": { + "title": "Crear servidor mock", + "name_label": "Nombre del servidor mock", + "name_placeholder": "Ingresa el nombre del servidor mock", + "name_required": "El nombre del servidor mock es obligatorio", + "collection_source_label": "Origen de la colección", + "existing_collection": "Colección existente", + "new_collection": "Nueva colección", + "select_collection_label": "Seleccionar colección", + "select_collection_placeholder": "Elige una colección", + "collection_required": "Por favor, selecciona una colección", + "collection_name_label": "Nombre de la colección", + "collection_name_placeholder": "Ingresa el nombre de la colección", + "collection_name_required": "El nombre de la colección es obligatorio", + "request_config_label": "Configuración de solicitud", + "add_request": "Agregar solicitud", + "create_button": "Crear servidor mock", + "success": "Servidor mock creado exitosamente", + "error": "No se pudo crear el servidor mock", + "no_collections": "No hay colecciones disponibles" + }, + "edit_modal": { + "title": "Editar servidor mock", + "name_label": "Nombre del servidor mock", + "name_placeholder": "Ingresa el nombre del servidor mock", + "name_required": "El nombre del servidor mock es obligatorio", + "active_label": "Activo", + "url_label": "URL del servidor mock", + "collection_label": "Colección", + "update_button": "Actualizar servidor mock", + "success": "Servidor mock actualizado exitosamente", + "error": "No se pudo actualizar el servidor mock", + "url_copied": "URL copiada al portapapeles" + }, + "dashboard": { + "title": "Servidores mock", + "subtitle": "Crea y administra tus servidores mock de API", + "create_button": "Crear servidor mock", + "create_first": "Crea tu primer servidor mock", + "empty_title": "No se encontraron servidores mock", + "empty_description": "Crea servidores mock basados en tus colecciones de API para permitir el desarrollo frontend y móvil sin dependencias del backend.", + "collection": "Colección", + "active": "Activo", + "inactive": "Inactivo", + "mock_url": "URL mock", + "endpoints": "Endpoints", + "created": "Creado", + "view_collection": "Ver colección", + "documentation": "Documentación", + "doc_description": "Usa esta URL como la URL base de tu API en tus aplicaciones:", + "url_copied": "URL del servidor mock copiada al portapapeles", + "delete_title": "Eliminar servidor mock", + "delete_description": "¿Estás seguro de que deseas eliminar este servidor mock?", + "delete_success": "Servidor mock eliminado exitosamente", + "delete_error": "No se pudo eliminar el servidor mock" + } } } diff --git a/packages/hoppscotch-common/locales/pt-br.json b/packages/hoppscotch-common/locales/pt-br.json index 6acc4693a4b..309d62b0133 100644 --- a/packages/hoppscotch-common/locales/pt-br.json +++ b/packages/hoppscotch-common/locales/pt-br.json @@ -766,7 +766,11 @@ "dark_mode": "Escuro", "delete_account": "Excluir conta", "delete_account_description": "Ao deletar sua conta, todos os seus dados serão permanentemente excluídos. Esta ação não pode ser desfeita.", + "desktop": "Desktop", + "desktop_description": "Preferências específicas do aplicativo desktop Hoppscotch.", + "desktop_updates": "Atualizações", "disable_encode_mode_tooltip": "Nunca codificar os parâmetros na requisição", + "disable_update_checks": "Desativar verificação automática de atualizações", "enable_encode_mode_tooltip": "Sempre codificar os parâmetros na requisição", "expand_navigation": "Expandir navegação", "experiments": "Experimentos", diff --git a/packages/hoppscotch-common/locales/tr.json b/packages/hoppscotch-common/locales/tr.json index b24355e0071..cb3a0b9216d 100644 --- a/packages/hoppscotch-common/locales/tr.json +++ b/packages/hoppscotch-common/locales/tr.json @@ -4,10 +4,17 @@ "autoscroll": "Oto-Kaydırma", "cancel": "İptal", "choose_file": "Bir dosya seçin", + "choose_workspace": "Bir çalışma alanı seçin", + "choose_collection": "Bir koleksiyon seçin", + "select_workspace": "Bir çalışma alanı seçin", "clear": "Temizle", "clear_all": "Hepsini temizle", + "clear_cache": "Önbelleği Temizle", "clear_history": "Tüm Geçmişi Temizle", + "clear_unpinned": "Sabitlenmemişleri Temizle", + "clear_response": "Yanıtı Temizle", "close": "Kapat", + "confirm": "Onayla", "connect": "Bağlan", "connecting": "Bağlanıyor", "copy": "Kopyala", @@ -15,8 +22,10 @@ "delete": "Sil", "disconnect": "Bağlantıyı kes", "dismiss": "Boşver", + "done": "Tamam", "dont_save": "Kaydetme", "download_file": "Dosyayı İndir", + "download_test_report": "Test raporunu indir", "drag_to_reorder": "Yeniden sıralamak için sürükleyin", "duplicate": "Klonla", "edit": "Düzenle", @@ -32,20 +41,28 @@ "more": "Daha fazla", "new": "Yeni", "no": "Hayır", - "open_workspace": "Çalışma Ortamını Aç", + "open": "Aç", + "open_workspace": "Çalışma alanını aç", "paste": "Yapıştır", "prettify": "Güzelleştir", "properties": "Özellikler", + "register": "Kayıt Ol", "remove": "Kaldır", + "remove_instance": "Sunucuyu kaldır", "rename": "Yeniden Adlandır", "restore": "Onar", + "retry": "Tekrar Dene", "save": "Kaydet", + "save_as_example": "Örnek olarak kaydet", + "add_example": "Örnek ekle", + "invalid_request": "Geçersiz istek verisi", "scroll_to_bottom": "Aşağı kaydır", "scroll_to_top": "Yukarı kaydır", "search": "Arama", "send": "Gönder", "share": "Paylaş", "show_secret": "Özel veriyi göster", + "sort": "Sırala", "start": "Başla", "starting": "Başlatılıyor", "stop": "Dur", @@ -55,13 +72,67 @@ "turn_off": "Kapat", "turn_on": "Aç", "undo": "Geri al", - "yes": "Evet" + "unpublish": "Yayından Kaldır", + "yes": "Evet", + "verify": "Doğrula", + "enable": "Etkinleştir", + "disable": "Devre Dışı Bırak", + "assign": "Ata" + }, + "activity_logs": { + "ACTIVITY_LOG_DELETE": "Etkinlik günlüğü silindi", + "WORKSPACE_CREATE": "Yeni çalışma alanı oluşturuldu: {name}", + "WORKSPACE_RENAME": "Çalışma alanı {old_name} adından {new_name} adına yeniden adlandırıldı", + "WORKSPACE_USER_ADD": "{user} çalışma alanına {role} rolüyle eklendi", + "WORKSPACE_USER_INVITE": "{user}, {inviteeEmail} adresini {role} rolüyle davet etti", + "WORKSPACE_USER_INVITE_REVOKE": "{inviteeEmail} kullanıcısının {inviteeRole} rolündeki daveti iptal edildi", + "WORKSPACE_USER_INVITE_ACCEPT": "{inviteeEmail}, {inviteeRole} rolüyle daveti kabul etti", + "WORKSPACE_USER_REMOVE": "{user} çalışma alanından kaldırıldı", + "WORKSPACE_USER_ROLE_UPDATE": "{user} kullanıcısının rolü {old_role} rolünden {new_role} rolüne güncellendi", + "COLLECTION_CREATE": "Yeni koleksiyon oluşturuldu: {title}", + "COLLECTION_RENAME": "Koleksiyon {old_title} adından {new_title} adına yeniden adlandırıldı", + "COLLECTION_IMPORT": "{count} koleksiyon içe aktarıldı", + "COLLECTION_DELETE": "Koleksiyon silindi: {title}", + "COLLECTION_DUPLICATE": "Koleksiyon çoğaltıldı: {parentTitle}", + "REQUEST_CREATE": "Yeni istek oluşturuldu: {title}", + "REQUEST_RENAME": "İstek {old_title} adından {new_title} adına yeniden adlandırıldı", + "REQUEST_DELETE": "İstek silindi: {title}" }, "add": { "new": "Yeni ekle", "star": "Yıldız ekle" }, + "agent": { + "registration_instruction": "Devam etmek için lütfen Hoppscotch Agent'ı web istemcinize kaydedin.", + "enter_otp_instruction": "Lütfen Hoppscotch Agent tarafından oluşturulan doğrulama kodunu girin ve kaydı tamamlayın", + "otp_label": "Doğrulama Kodu", + "processing": "İsteğiniz işleniyor...", + "not_running_title": "Agent algılanamadı", + "registration_title": "Agent kaydı", + "verify_ssl_certs": "SSL Sertifikalarını Doğrula", + "ca_certs": "CA Sertifikaları", + "client_certs": "İstemci Sertifikaları", + "use_http_proxy": "HTTP Proxy Kullan", + "proxy_capabilities": "Hoppscotch Agent, HTTP/HTTPS/SOCKS proxy desteğinin yanı sıra bu proxy'lerde NTLM ve Basic Auth desteği sunar. Proxy kimlik doğrulaması için kullanıcı adı ve şifreyi doğrudan URL içine ekleyin.", + "add_cert_file": "Sertifika Dosyası Ekle", + "add_client_cert": "İstemci Sertifikası Ekle", + "add_key_file": "Anahtar Dosyası Ekle", + "domain": "Alan Adı", + "cert": "Sertifika", + "key": "Anahtar", + "pfx_or_pkcs": "PFX/PKCS12", + "pfx_or_pkcs_file": "PFX/PKCS12 Dosyası", + "add_pfx_or_pkcs_file": "PFX/PKCS12 Dosyası Ekle" + }, "app": { + "additional_links": { + "macOS": "macOS", + "windows": "Windows", + "linux": "Linux", + "web_app": "Web Uygulaması", + "cli": "CLI" + }, + "downloads": "İndirmeler", "chat_with_us": "Bizimle sohbet et", "contact_us": "Bize ulaş", "cookies": "Çerezler", @@ -84,6 +155,7 @@ "new_version_found": "Yeni sürüm hazır! Güncellemek için yenileyin.", "open_in_hoppscotch": "Hoppscotch'ta Aç", "options": "Ayarlar", + "powered_by": "Hoppscotch tarafından desteklenmektedir", "proxy_privacy_policy": "Proxy Gizlilik İlkesi", "reload": "Tekrar yükle", "search": "Arama", @@ -101,9 +173,17 @@ "updated_text": "Hoppscotch v{version} sürümüne yükseltildi! 🎉", "whats_new": "Ne var ne yok?", "see_whats_new": "Yeni güncellemeleri gör", - "wiki": "Wiki" + "wiki": "Wiki", + "collapse_sidebar": "Kenar Çubuğunu Daralt", + "continue_to_dashboard": "Kontrol Paneline Devam Et", + "expand_sidebar": "Kenar Çubuğunu Genişlet", + "no_name": "İsimsiz", + "open_navigation": "Gezinmeyi Aç", + "read_documentation": "Belgeleri Oku", + "default": "varsayılan: {value}" }, "auth": { + "account_deactivated": "Hesabınız devre dışı bırakıldı. Erişim için yöneticiyle iletişime geçin.", "account_exists": "Farklı kimlik bilgilerine sahip hesap var - Her iki hesabı birbirine bağlamak için giriş yapın", "all_sign_in_options": "Tüm oturum açma seçenekleri", "continue_with_auth_provider": "{provider} ile devam et", @@ -126,6 +206,7 @@ }, "authorization": { "generate_token": "Anahtar oluştur", + "refresh_token": "Yenileme Token'ı", "graphql_headers": "Yetki Başlıkları, connection_init'e yük parçası olarak gönderilir", "include_in_url": "URL'e dahil et", "inherited_from": "{auth}, {collection} adlı üst koleksiyondan devralındı", @@ -148,6 +229,9 @@ "token_fetched_successfully": "Anahtar başarıyla alındı", "token_fetch_failed": "Anahtar alınamadı", "validation_failed": "Doğrulama başarısız oldu, lütfen form alanlarını kontrol edin", + "no_refresh_token_present": "Yenileme token'ı bulunamadı. Lütfen token oluşturma akışını tekrar çalıştırın", + "refresh_token_request_failed": "Yenileme token'ı isteği başarısız oldu", + "token_refreshed_successfully": "Token başarıyla yenilendi", "label_authorization_endpoint": "Yetkilendirme Uç Noktası", "label_client_id": "Müşteri Kimliği", "label_client_secret": "Müşteri Gizli Verisi", @@ -161,7 +245,15 @@ "label_password": "Şifre", "label_username": "Kullanıcı Adı", "label_auth_code": "Yetkilendirme Kodu", - "label_client_credentials": "Müşteri Kimlik Bilgileri" + "label_client_credentials": "Müşteri Kimlik Bilgileri", + "label_send_as": "İstemci Kimlik Doğrulaması", + "label_send_in_body": "Kimlik Bilgilerini Gövdede Gönder", + "label_send_as_basic_auth": "Kimlik Bilgilerini Basic Auth Olarak Gönder", + "enter_value": "Değer girin", + "auth_request": "Kimlik Doğrulama İsteği", + "token_request": "Token İsteği", + "refresh_request": "Yenileme İsteği", + "send_in": "Gönderim Yeri" }, "pass_key_by": "Şunla anahtar ekleyin", "pass_by_query_params_label": "Sorgu parametreleri", @@ -169,10 +261,76 @@ "password": "Şifre", "save_to_inherit": "Lütfen yetkilendirmeyi devralmak için bu isteği herhangi bir koleksiyona kaydedin", "token": "Anahtar", + "access_token": "Erişim Token'ı", + "client_token": "İstemci Token'ı", + "client_secret": "İstemci Gizli Anahtarı", + "timestamp": "Zaman Damgası", + "host": "Sunucu", "type": "Yetki Türü", - "username": "Kullanıcı adı" + "username": "Kullanıcı adı", + "advance_config": "Gelişmiş Yapılandırma", + "advance_config_description": "Hoppscotch, açık bir değer belirtilmediğinde belirli alanlara otomatik olarak varsayılan değerler atar", + "algorithm": "Algoritma", + "payload": "Yük", + "secret": "Gizli Anahtar", + "aws_signature": { + "access_key": "Erişim Anahtarı", + "secret_key": "Gizli Anahtar", + "service_name": "Hizmet Adı", + "aws_region": "AWS Bölgesi", + "service_token": "Hizmet Token'ı" + }, + "digest": { + "realm": "Realm", + "nonce": "Nonce", + "algorithm": "Algoritma", + "qop": "qop", + "nonce_count": "Nonce Sayısı", + "client_nonce": "İstemci Nonce", + "opaque": "Opaque", + "disable_retry": "İsteği Yeniden Denemeyi Devre Dışı Bırak" + }, + "akamai": { + "headers_to_sign": "İmzalanacak Başlıklar", + "max_body_size": "Maksimum Gövde Boyutu" + }, + "hawk": { + "id": "HAWK Auth Kimliği", + "key": "HAWK Auth Anahtarı", + "ext": "ext", + "app": "app", + "dlg": "dlg", + "include": "Payload Hash Dahil Et" + }, + "jwt": { + "params_name": "Parametre Adı", + "param_name": "Parametre Adı", + "header_prefix": "Başlık Ön Eki", + "placeholder_request_header": "İstek başlık ön eki", + "placeholder_request_param": "İstek parametre adı", + "secret_base64_encoded": "Base64 Kodlanmış Gizli Anahtar", + "headers": "JWT Başlıkları", + "private_key": "Özel Anahtar", + "placeholder_headers": "JWT Başlıkları" + }, + "ntlm": { + "domain": "Alan Adı", + "workstation": "İş İstasyonu", + "disable_retrying_request": "İsteği Yeniden Denemeyi Devre Dışı Bırak" + }, + "asap": { + "issuer": "Veren", + "audience": "Hedef Kitle", + "expires_in": "Süre Sonu", + "key_id": "Anahtar Kimliği", + "optional_config": "İsteğe Bağlı Yapılandırma", + "subject": "Konu", + "additional_claims": "Ek Talepler" + } }, "collection": { + "title": "Koleksiyon", + "run": "Koleksiyonu Çalıştır", "created": "Koleksiyon oluşturuldu", "different_parent": "Koleksiyonu farklı bir üst öğeyle yeniden sıralayamazsınız", "edit": "Koleksiyonu düzenle", @@ -194,11 +352,14 @@ "save_to_collection": "Koleksiyona Kaydet", "select": "Bir Koleksiyon Seçin", "select_location": "Konum seçin", - "details": "Detaylar" + "sorted": "Koleksiyon sıralandı", + "details": "Detaylar", + "duplicated": "Koleksiyon çoğaltıldı" }, "confirm": { "close_unsaved_tab": "Bu sekmeyi kapatmak istediğinizden emin misiniz?", "close_unsaved_tabs": "Tüm sekmeleri kapatmak istediğinizden emin misiniz? {count} kaydedilmemiş sekme kaybolacak.", + "delete_all_activity_logs": "Tüm etkinlik günlüklerini silmek istediğinizden emin misiniz?", "exit_team": "Bu takımdan ayrılmak istediğinizden emin misiniz?", "logout": "Oturumu kapatmak istediğinizden emin misiniz?", "remove_collection": "Bu koleksiyonu kalıcı olarak silmek istediğinizden emin misiniz?", @@ -206,18 +367,22 @@ "remove_folder": "Bu klasörü kalıcı olarak silmek istediğinizden emin misiniz?", "remove_history": "Tüm geçmişi kalıcı olarak silmek istediğinizden emin misiniz?", "remove_request": "Bu isteği kalıcı olarak silmek istediğinizden emin misiniz?", + "remove_response": "Bu yanıtı kalıcı olarak silmek istediğinizden emin misiniz?", "remove_shared_request": "Bu paylaşılan isteği kalıcı olarak silmek istediğinizden emin misiniz?", "remove_team": "Bu takımı silmek istediğinizden emin misiniz?", "remove_telemetry": "Telemetriyi devre dışı bırakmak istediğinizden emin misiniz?", "request_change": "Mevcut isteği iptal etmek istediğinizden emin misiniz? Kaydedilmemiş değişiklikler kaybolacak.", "save_unsaved_tab": "Bu sekmede yapılan değişiklikleri kaydetmek istiyor musunuz?", "sync": "Bu çalışma alanını senkronize etmek istediğinizden emin misiniz?", - "delete_access_token": "Erişim anahtarı {tokenLabel} öğesini silmek istediğinizden emin misiniz?" + "delete_access_token": "Erişim anahtarı {tokenLabel} öğesini silmek istediğinizden emin misiniz?", + "delete_mock_server": "Bu sahte sunucuyu silmek istediğinizden emin misiniz?" }, "context_menu": { "add_parameters": "Parametrelere ekle", "open_request_in_new_tab": "İsteği yeni sekmede aç", - "set_environment_variable": "Değişken olarak ata" + "set_environment_variable": "Değişken olarak ata", + "encode_uri_component": "URL bileşenini kodla", + "decode_uri_component": "URL bileşeninin kodunu çöz" }, "cookies": { "modal": { @@ -238,7 +403,11 @@ } }, "count": { + "currentValue": "Mevcut değer {count}", + "description": "Açıklama {count}", "header": "Başlık {count}", + "initialValue": "Başlangıç değeri {count}", + "key": "Anahtar {count}", "message": "Mesaj {count}", "parameter": "Parametre {count}", "protocol": "Protokol {count}", @@ -246,17 +415,190 @@ "variable": "Değişken {count}" }, "documentation": { + "add_description": "Bu koleksiyon için buraya açıklama ekleyin...", + "add_description_placeholder": "Buraya açıklama ekleyin...", + "add_request_description": "İstek için açıklama ekleyin...", + "auth": { + "access_key": "Erişim Anahtarı", + "access_token": "Erişim Token'ı", + "add_to": "Ekle", + "akamai_edgegrid": "Akamai EdgeGrid", + "algorithm": "Algoritma", + "api_key": "API Anahtarı", + "app_id": "Uygulama ID", + "auth_id": "Auth ID", + "auth_key": "Auth Anahtarı", + "auth_url": "Auth URL", + "aws_signature": "AWS İmzası", + "basic_auth": "Temel Kimlik Doğrulama", + "bearer_token": "Bearer Token", + "client_id": "İstemci ID", + "client_nonce": "İstemci Nonce", + "client_secret": "İstemci Gizli Anahtarı", + "client_token": "İstemci Token'ı", + "delegation": "Yetkilendirme", + "digest_auth": "Digest Auth", + "extra_data": "Ek Veri", + "grant_type": "Yetki Türü", + "hawk_auth": "HAWK Auth", + "headers_to_sign": "İmzalanacak Header'lar", + "host": "Sunucu", + "include_payload_hash": "Payload Hash'i Dahil Et", + "jwt_auth": "JWT Auth", + "max_body_size": "Maksimum Gövde Boyutu", + "no_auth": "Kimlik doğrulama yok", + "nonce": "Nonce", + "oauth_2": "OAuth 2.0", + "opaque": "Opaque", + "password": "Parola", + "payload": "Payload", + "qop": "QOP", + "realm": "Realm", + "region": "Bölge", + "scope": "Kapsam", + "secret_key": "Gizli Anahtar", + "service_name": "Hizmet Adı", + "timestamp": "Zaman Damgası", + "title": "Kimlik Doğrulama", + "token_url": "Token URL", + "user": "Kullanıcı", + "username": "Kullanıcı Adı" + }, + "body": { + "content_type": "İçerik Türü", + "no_body": "Gövde tanımlanmadı", + "title": "Gövde" + }, + "copied_to_clipboard": "Panoya kopyalandı!", + "curl": { + "click_to_load": "cURL komutunu yüklemek için tıklayın", + "copied": "cURL komutu panoya kopyalandı!", + "copy_to_clipboard": "Panoya kopyala", + "generating": "cURL komutu oluşturuluyor...", + "load": "cURL Yükle", + "title": "cURL" + }, + "description": "Açıklama", + "error_rendering_markdown": "Markdown oluşturma hatası:", + "fetching_documentation": "Dokümantasyon getiriliyor...", "generate": "Belge oluştur", - "generate_message": "Güncel API belgelerini oluşturmak için herhangi bir Hoppscotch koleksiyonunu içe aktarın." + "generate_message": "Güncel API belgelerini oluşturmak için herhangi bir Hoppscotch koleksiyonunu içe aktarın.", + "headers": { + "no_headers": "Header tanımlanmadı", + "title": "Header'lar" + }, + "hide_all_documentation": "Tüm Dokümantasyonu Gizle", + "inherited_from": "{name} kaynağından miras alındı", + "inherited_with_type": "{name} kaynağından {type} miras alındı", + "key": "Anahtar", + "loading": "Yükleniyor...", + "loading_collection_data": "Koleksiyon Verileri Yükleniyor...", + "no": "Hayır", + "no_collection_data": "Koleksiyon verisi mevcut değil", + "no_documentation_found": "Klasörler veya istekler için dokümantasyon bulunamadı", + "no_request_data": "İstek verisi mevcut değil", + "no_requests_or_folders": "İstek veya klasör yok", + "not_set": "Ayarlanmadı", + "open_request_in_new_tab": "İsteği yeni sekmede aç", + "parameters": { + "no_params": "Parametre tanımlanmadı", + "title": "Parametreler" + }, + "percent_complete": "% tamamlandı", + "processing_documentation": "Dokümantasyon İşleniyor", + "publish": { + "already_published": "Bu koleksiyon zaten yayımlanmış", + "auto_sync": "Koleksiyonla otomatik senkronizasyon", + "auto_sync_description": "Koleksiyon değiştiğinde yayımlanan dokümanları otomatik olarak güncelle", + "button": "Yayımla", + "copy_url": "URL Kopyala", + "delete": "Dokümantasyonu Sil", + "unpublish_doc": "Dokümantasyonu yayından kaldırmak istediğinizden emin misiniz?", + "delete_success": "Yayımlanan dokümantasyon başarıyla silindi", + "doc_title": "Başlık", + "doc_version": "Sürüm", + "edit_published_doc": "Yayımlanan Dokümanı Düzenle", + "last_updated": "Son Güncelleme", + "metadata": "Meta Veri (JSON)", + "open_published_doc": "Yayımlanan Dokümantasyonu yeni sekmede aç", + "publish_error": "Dokümantasyon yayımlanamadı", + "publish_success": "Dokümantasyon başarıyla yayımlandı!", + "published": "Yayımlandı", + "published_url": "Yayımlanan URL", + "title": "Dokümantasyonu Yayımla", + "update_button": "Güncelle", + "update_error": "Dokümantasyon güncellenemedi", + "update_published_docs": "Yayımlanan Dokümanları Güncelle", + "update_success": "Dokümantasyon başarıyla güncellendi!", + "unpublish": "Yayından Kaldır", + "update_title": "Yayımlanan Dokümantasyonu Güncelle", + "url_copied": "URL panoya kopyalandı!", + "view_published": "Yayımlanan Dokümanları Görüntüle", + "view_title": "Yayımlanan Dokümantasyon Anlık Görüntüsü", + "versions": "Sürümler", + "create_new_version": "Yeni Sürüm Oluştur", + "invalid_version": "Sürüm yalnızca alfanümerik karakterler, noktalar ve tire içerebilir", + "snapshot_description": "Bu, mevcut dokümantasyonun bu sürüm olarak anlık görüntüsünü alacak", + "live": "Canlı", + "snapshot": "Anlık Görüntü", + "version_immutable": "Yayımlanan sürümler salt okunur anlık görüntülerdir", + "view_snapshot": "Anlık Görüntüyü Görüntüle", + "current_version": "GÜNCEL", + "not_found": "Yayımlanan dokümantasyon bulunamadı", + "no_doc_id": "Doküman ID'si sağlanmadı", + "version_label": "v{version}", + "unpublish_version": "Bu sürümü yayından kaldır", + "loading_snapshot": "Anlık görüntü yükleniyor...", + "retry_snapshot": "Tekrar Dene", + "sensitive_data_warning": "Lütfen yayımlanan dokümantasyonda hassas verilerin açığa çıkmadığından emin olun.", + "snapshot_preview": "Anlık Görüntü Önizlemesi", + "snapshot_load_error": "Anlık görüntü önizlemesi yüklenemedi", + "snapshot_empty": "Bu anlık görüntüde istek veya klasör yok", + "snapshot_item_count": "{count} öğe", + "auto_sync_live_notice": "Bu sürüm canlı koleksiyonla otomatik senkronize edilir", + "untitled_project": "Başlıksız Proje", + "first_publish_hint": "Dokümantasyonunuz, koleksiyonunuzla otomatik olarak senkronize kalan canlı bir sürüm olarak yayımlanacak", + "environment": "Ortam", + "no_environment": "Ortam yok", + "environment_description": "Yayımlanan dokümantasyondaki değişkenleri çözümlemek için bir ortam ekleyin" + }, + "request_opened_in_new_tab": "İstek yeni sekmede açıldı!", + "response": { + "body": "Yanıt Gövdesi", + "copy": "Yanıtı kopyala", + "example_copied": "Yanıt örneği panoya kopyalandı!", + "example_copy_failed": "Yanıt örneği kopyalanamadı", + "headers": "Yanıt Header'ları", + "no_examples": "Yanıt örneği mevcut değil", + "title": "Yanıt Örnekleri" + }, + "save_error": "Dokümantasyon kaydedilirken hata oluştu", + "save_success": "Dokümantasyon başarıyla kaydedildi", + "saved_items_status": "{success} öğe kaydedildi. {failure} öğe kaydedilemedi.", + "show_all_documentation": "Tüm Dokümantasyonu Göster", + "source": "Kaynak", + "title": "Dokümantasyon", + "unsaved_changes": "{count} kaydedilmemiş değişikliğiniz var. Lütfen kapatmadan önce kaydedin.", + "untitled_collection": "Başlıksız Koleksiyon", + "untitled_request": "Başlıksız İstek", + "value": "Değer", + "variables": { + "no_vars": "Değişken tanımlanmadı", + "title": "Değişkenler" + }, + "yes": "Evet" }, "empty": { + "activity_logs": "Etkinlik günlüğü bulunamadı", "authorization": "Bu istek herhangi bir yetkilendirme kullanmıyor", "body": "Bu isteğin bir gövdesi yok", "collection": "Koleksiyon boş", "collections": "Koleksiyonlar boş", "documentation": "Dokümanları görmek için GraphQL uç noktasını bağlayın", + "empty_schema": "Şema bulunamadı", "endpoint": "Uç nokta boş olamaz", "environments": "Ortamlar boş", + "collection_variables": "Koleksiyon değişkenleri boş", "folder": "Klasör boş", "headers": "Bu isteğin herhangi bir başlığı yok", "history": "Geçmiş boş", @@ -268,6 +610,7 @@ "protocols": "Protokoller boş", "request_variables": "Bu isteğin herhangi bir istek değişkeni yok", "schema": "Bir GraphQL uç noktasına bağlanma", + "search_environment": "Eşleşen ortam bulunamadı", "secret_environments": "Gizli veriler Hoppscotch ile senkronize edilmiyor", "shared_requests": "Paylaşılan istekler boş", "shared_requests_logout": "Paylaşılan isteklerinizi görüntülemek veya yeni bir istek oluşturmak için giriş yapın", @@ -275,13 +618,17 @@ "team_name": "Takım adı boş", "teams": "Takımlar boş", "tests": "Bu istek için test yok", - "access_tokens": "Erişim anahtarları boş" + "access_tokens": "Erişim anahtarları boş", + "response": "Yanıt alınamadı", + "mock_servers": "Mock sunucu bulunamadı" }, "environment": { + "heading": "Ortam", "add_to_global": "Globale ekle", "added": "Ortam eklendi", "create_new": "Yeni ortam oluştur", "created": "Ortam oluşturuldu", + "current_value": "Mevcut değer", "deleted": "Ortam silindi", "duplicated": "Değişkenler klonlandı", "edit": "Ortamı düzenle", @@ -289,6 +636,7 @@ "global": "Global", "global_variables": "Global değişkenler", "import_or_create": "Değişkenleri içe aktar ya da oluştur", + "initial_value": "Başlangıç değeri", "invalid_name": "Lütfen ortam için geçerli bir ad girin", "list": "Ortam değişkenleri", "my_environments": "Ortamlarım", @@ -299,6 +647,10 @@ "no_environment": "Ortam yok", "no_environment_description": "Hiçbir ortam seçilmedi. Aşağıdaki değişkenlerle ne yapacağınızı seçin.", "quick_peek": "Ortam Değişkenlerine Hızlı Bakış", + "replace_all_current_with_initial": "Tüm mevcut değerleri başlangıç değerleriyle değiştir", + "replace_all_initial_with_current": "Tüm başlangıç değerlerini mevcut değerlerle değiştir", + "replace_current_with_initial": "Başlangıç değeriyle değiştir", + "replace_initial_with_current": "Mevcut değerle değiştir", "replace_with_variable": "Değişkenle değiştir", "scope": "Kapsam", "secrets": "Gizli Veriler", @@ -306,6 +658,7 @@ "select": "Ortam seçin", "set": "Ortama ata", "set_as_environment": "Ortam olarak ata", + "short_name": "Ortam adı en az 1 karakter içermelidir", "team_environments": "Takım Ortamları", "title": "Ortamlar", "updated": "Ortam güncellendi", @@ -317,6 +670,47 @@ "details": "Detaylar" }, "error": { + "network": { + "heading": "Ağ Hatası", + "description": "Ağ bağlantısı başarısız oldu. {message}: {cause}" + }, + "timeout": { + "heading": "Zaman Aşımı Hatası", + "description": "{phase} sırasında istek zaman aşımına uğradı. {message}" + }, + "certificate": { + "heading": "Sertifika Hatası", + "description": "Geçersiz sertifika. {message}: {cause}" + }, + "auth": { + "heading": "Kimlik Doğrulama Hatası", + "description": "Erişim reddedildi. {message}: {cause}" + }, + "proxy": { + "heading": "Proxy Hatası", + "description": "Proxy bağlantısı başarısız oldu. {message}: {cause}" + }, + "parse": { + "heading": "Ayrıştırma Hatası", + "description": "Yanıt ayrıştırılamadı. {message}: {cause}" + }, + "version": { + "heading": "Sürüm Hatası", + "description": "Uyumsuz sürümler. {message}: {cause}" + }, + "abort": { + "heading": "İstek İptal Edildi", + "description": "İşlem iptal edildi. {message}: {cause}" + }, + "unknown": { + "heading": "Bilinmeyen Hata", + "description": "Bilinmeyen bir hata oluştu.", + "cause": "Bilinmeyen neden" + }, + "extension": { + "heading": "Eklenti hatası", + "description": "İstek eklentide çalıştırılamadı" + }, "authproviders_load_error": "Kimlik sağlayıcıları yüklenemedi", "browser_support_sse": "Bu tarayıcıda SSE desteği yok gibi görünüyor.", "check_console_details": "Ayrıntılar için konsol günlüğünü kontrol edin.", @@ -325,13 +719,18 @@ "danger_zone": "Tehlike Alanı", "delete_account": "Hesabınız şu anda bu ekiplerin sahibi:", "delete_account_description": "Hesabınızı silmeden önce kendinizi kaldırmalı, sahipliği devretmeli veya bu ekipleri silmelisiniz.", + "delete_activity_log": "Etkinlik günlüğü silinemedi", + "delete_all_activity_logs": "Tüm etkinlik günlükleri silinemedi", + "email_already_exists": "Bu e-posta adresi farklı bir hesapla zaten mevcut. Lütfen farklı bir e-posta adresi belirleyin.", "empty_email_address": "E-posta Adresi boş olamaz", "empty_profile_name": "Profil adı boş olamaz", "empty_req_name": "Boş İstek Adı", + "fetch_activity_logs": "Etkinlik günlükleri getirilemedi", "f12_details": "(Ayrıntılar için F12)", "gql_prettify_invalid_query": "Geçersiz bir sorgu güzelleştirilemedi, sorgu sözdizimi hatalarını çözüp tekrar deneyin.", "incomplete_config_urls": "Eksik yapılandırma URL'leri", "incorrect_email": "Geçersiz e-posta", + "invalid_file_type": "`{filename}` için geçersiz dosya türü.", "invalid_link": "Geçersiz bağlantı", "invalid_link_description": "Tıkladığınız bağlantı süresi dolmuş veya geçersiz.", "invalid_embed_link": "Gömülü bağlantı mevcut değil veya geçersiz.", @@ -350,11 +749,14 @@ "same_profile_name": "Güncellenen profil adı mevcut profil adıyla aynı", "script_fail": "Ön istek komut dosyası çalıştırılamadı", "something_went_wrong": "Bir şeyler yanlış gitti", + "subscription_error": "Konuya abone olunamadı: {error}", "post_request_script_fail": "Sonraki istek komut dosyası çalıştırılamadı", "reading_files": "Bir veya daha fazla dosya okunurken hata oluştu.", "fetching_access_tokens_list": "Anahtar listesi alınırken bir sorun oluştu.", "generate_access_token": "Erişim anahtarı oluşturulurken bir sorun oluştu.", - "delete_access_token": "Erişim anahtarı silinirken bir sorun oluştu." + "delete_access_token": "Erişim anahtarı silinirken bir sorun oluştu.", + "extension_not_found": "Eklenti bulunamadı", + "invalid_request": "Geçersiz istek verisi" }, "export": { "as_json": "JSON olarak dışa aktar", @@ -366,6 +768,30 @@ "title": "Dışarı Aktar", "success": "Başarıyla dışa aktarıldı." }, + "file_upload": { + "choose_file": "Dosya seç", + "max_size_format": "Maks. 5MB. JPEG, PNG, GIF, WebP destekler", + "profile_photo_updated": "Profil fotoğrafı başarıyla güncellendi", + "profile_photo_removed": "Profil fotoğrafı başarıyla kaldırıldı", + "org_logo_updated": "Organizasyon logosu başarıyla güncellendi", + "error_size_limit": "Dosya boyutu 5MB'den küçük olmalıdır", + "error_invalid_format": "Dosya bir görsel olmalıdır (JPEG, PNG, GIF veya WebP)", + "error_invalid_upload_type": "Geçersiz yükleme türü", + "error_invalid_org_id": "Geçersiz organizasyon ID formatı", + "error_upload_failed": "Yükleme başarısız oldu. Lütfen tekrar deneyin", + "error_network_failed": "Ağ hatası. Lütfen bağlantınızı kontrol edin", + "error_timeout": "Yükleme 30 saniye sonra zaman aşımına uğradı. Lütfen tekrar deneyin", + "error_missing_backend_url": "Backend URL yapılandırılmamış. Lütfen ortam ayarlarınızda VITE_BACKEND_API_URL ortam değişkenini ayarlayın", + "error_invalid_backend_url": "Geçersiz backend URL yapılandırması" + }, + "filename": { + "cookie_key_value_pairs": "Cookie", + "codegen": "{request_name} - kod", + "graphql_response": "GraphQL-Yanıt", + "lens": "{request_name} - yanıt", + "realtime_response": "Gerçek-Zamanlı-Yanıt", + "response_interface": "Yanıt-Arayüzü" + }, "filter": { "all": "Tümü", "none": "Hiçbiri", @@ -377,17 +803,27 @@ "invalid_name": "Lütfen klasör için bir ad girin", "name_length_insufficient": "Klasör adı en az 3 karakterden oluşmalıdır", "new": "Yeni Klasör", - "renamed": "Klasör yeniden adlandırıldı" + "run": "Klasörü Çalıştır", + "renamed": "Klasör yeniden adlandırıldı", + "sorted": "Klasör sıralandı" }, "graphql": { + "arguments": "Argümanlar", "connection_switch_confirm": "En son GraphQL uç noktasına bağlanmak ister misiniz?", + "connection_error_http": "Ağ hatası nedeniyle GraphQL Şeması getirilemedi.", "connection_switch_new_url": "Bir sekmeye geçmek sizi etkin GraphQL bağlantısından ayıracaktır. Yeni bağlantı URL'si", "connection_switch_url": "Bir GraphQL uç noktasına bağlandınız, bağlantı URL'si şu şekildedir:", + "deprecated": "Kullanımdan kaldırıldı", + "fields": "Alanlar", + "mutation": "Mutation", "mutations": "Mutasyonlar", "schema": "Şema", + "show_depricated_values": "Kullanımdan kaldırılan değerleri göster", + "subscription": "Subscription", "subscriptions": "Abonelikler", "switch_connection": "Bağlantı değiştir", - "url_placeholder": "Bir GraphQL Uç Nokta Adresi Gir" + "url_placeholder": "Bir GraphQL Uç Nokta Adresi Gir", + "query": "Query" }, "graphql_collections": { "title": "GraphQL Koleksiyonları" @@ -419,7 +855,8 @@ "collection": "Koleksiyon Panelini Daralt", "more": "Daha fazlasını gizle", "preview": "Önizlemeyi Gizle", - "sidebar": "Kenar çubuğunu gizle" + "sidebar": "Kenar çubuğunu gizle", + "password": "Parolayı Gizle" }, "import": { "collections": "Koleksiyonları içe aktar", @@ -430,18 +867,30 @@ "from_file": "Dosyadan içe aktar", "from_gist": "Gist'ten içe aktar", "from_gist_description": "Gist ile içe aktar", + "from_gist_import_summary": "Tüm Hoppscotch özellikleri içe aktarılır.", + "from_hoppscotch_importer_summary": "Tüm Hoppscotch özellikleri içe aktarılır.", "from_insomnia": "Insomnia'dan ile içe aktar", "from_insomnia_description": "Insomnia koleksiyonunu içe aktar", + "from_insomnia_import_summary": "Koleksiyonlar ve İstekler içe aktarılacak.", "from_json": "Hoppscotch ile içe aktar", "from_json_description": "Hoppscotch koleksiyonunu içe aktar", "from_my_collections": "Koleksiyonlarımdan içe aktar", "from_my_collections_description": "Koleksiyon dosyalarımdan içe aktar", + "from_all_collections": "Başka Bir Çalışma Alanından İçe Aktar", + "from_all_collections_description": "Başka bir çalışma alanından mevcut çalışma alanına herhangi bir koleksiyonu içe aktarın", "from_openapi": "OpenAPI'den içe aktar", "from_openapi_description": "OpenAPI belirtilmiş dosyasından içe aktar (YML/JSON)", + "from_openapi_import_summary": "Koleksiyonlar (etiketlerden oluşturulacak), İstekler ve yanıt örnekleri içe aktarılacak.", "from_postman": "Postman'den içe aktar", "from_postman_description": "Postman koleksiyonunu içe aktar", + "from_postman_import_summary": "Koleksiyonlar, İstekler ve yanıt örnekleri içe aktarılacak.", + "import_scripts": "Betikleri içe aktar", + "import_scripts_description": "Postman Collection v2.0/v2.1 destekler.", "from_url": "Bağlantı'yı içe aktar", "gist_url": "Gist bağlantısını girin", + "from_har": "HAR'dan İçe Aktar", + "from_har_description": "HAR dosyasından içe aktar", + "from_har_import_summary": "İstekler varsayılan bir koleksiyona aktarılacak.", "gql_collections_from_gist_description": "Gist'ten GraphQL Koleksiyonlarını İçe Aktar", "hoppscotch_environment": "Hoppscotch Ortamları", "hoppscotch_environment_description": "Hoppscotch Ortam JSON Dosyasını İçe Aktar", @@ -454,9 +903,58 @@ "postman_environment": "Postman Ortamı", "postman_environment_description": "Postman Ortamını bir JSON dosyasından içe aktarın", "title": "İçe aktar", - "file_size_limit_exceeded_warning_multiple_files": "Seçilen dosyalar önerilen 10MB sınırını aşıyor. Sadece seçilen ilk {files} içe aktarılacak", - "file_size_limit_exceeded_warning_single_file": "Şu anda seçilen dosya önerilen 10MB sınırını aşıyor. Lütfen başka bir dosya seçin.", - "success": "Başarıyla içe aktarıldı" + "file_size_limit_exceeded_warning_multiple_files": "Seçilen dosyalar önerilen {sizeLimit}MB sınırını aşıyor. Sadece seçilen ilk {files} içe aktarılacak", + "file_size_limit_exceeded_warning_single_file": "Şu anda seçilen dosya önerilen {sizeLimit}MB sınırını aşıyor. Lütfen başka bir dosya seçin.", + "success": "Başarıyla içe aktarıldı", + "import_summary_collections_title": "Koleksiyonlar", + "import_summary_requests_title": "İstekler", + "import_summary_responses_title": "Yanıtlar", + "import_summary_pre_request_scripts_title": "İstek öncesi betikler", + "import_summary_post_request_scripts_title": "İstek sonrası betikler", + "import_summary_not_supported_by_hoppscotch_import": "Şu anda bu kaynaktan {featureLabel} içe aktarımını desteklemiyoruz.", + "import_summary_script_found": "betik bulundu ancak içe aktarılmadı", + "import_summary_scripts_found": "betik bulundu ancak içe aktarılmadı", + "import_summary_enable_experimental_sandbox": "Postman betiklerini içe aktarmak için ayarlarda 'Deneysel betik sandbox'ını etkinleştirin. Not: Bu özellik deneyseldir.", + "cors_error_modal": { + "title": "CORS Hatası Tespit Edildi", + "description": "İçe aktarma, sunucunun uyguladığı CORS (Cross-Origin Resource Sharing) kısıtlamaları nedeniyle başarısız oldu.", + "explanation": "Bu, web sayfalarının farklı alan adlarına istek göndermesini engelleyen bir güvenlik özelliğidir. Bu kısıtlamayı aşmak için proxy hizmetimizi kullanarak tekrar deneyebilirsiniz.", + "url_label": "Denenen URL", + "retry_with_proxy": "Proxy ile Tekrar Dene" + } + }, + "instances": { + "switch": "Hoppscotch Sunucusunu Değiştir", + "enter_server_url": "Kendi barındırdığınız bir sunucuya bağlanın", + "already_connected": "Bu sunucuya zaten bağlısınız", + "recent_connections": "Son Bağlantılar", + "add_instance": "Sunucu ekle", + "add_new": "Yeni bir sunucu ekle", + "confirm_remove": "Kaldırmayı Onayla", + "remove_warning": "Bu sunucuyu kaldırmak istediğinizden emin misiniz?", + "clear_cached_bundles": "Önbelleğe alınmış paketleri temizle", + "opening_add_modal": "Sunucu ekleme penceresi açılıyor", + "closed_add_modal": "Sunucu ekleme penceresi kapatıldı", + "cancelled_removal": "Sunucu kaldırma işlemi iptal edildi", + "connection_cancelled": "Bağlantı, ön bağlantı doğrulaması tarafından iptal edildi", + "post_connect_completed": "Bağlantı sonrası kurulum tamamlandı", + "connecting": "Sunucuya bağlanılıyor...", + "confirm_removal": "Sunucu kaldırmayı onayla", + "removal_cancelled": "Sunucu kaldırma, ön kaldırma doğrulaması tarafından iptal edildi", + "post_remove_completed": "Kaldırma sonrası temizlik tamamlandı", + "removing": "Sunucu kaldırılıyor...", + "clearing_cache": "Önbellek temizleniyor...", + "initialized": "Sunucu değiştirici başlatıldı", + "connecting_state": "Bağlantı kuruluyor...", + "connected_state": "Sunucuya başarıyla bağlanıldı", + "disconnected_state": "Sunucu bağlantısı kesildi", + "stream_error": "Bağlantı durumu izleme başarısız oldu", + "recent_instances_error": "Son sunucular yüklenemedi", + "instance_changed": "Sunucu değiştirildi", + "current_instance_error": "Mevcut sunucu izlenemedi", + "not_available": "Sunucu değiştirme kullanılamıyor", + "cleanup_completed": "Sunucu değiştirici temizliği tamamlandı", + "self_hosted": "Kendi barındırılan sunucular" }, "inspections": { "description": "Olası hataları inceleyin", @@ -481,7 +979,44 @@ "extension_not_installed": "Eklenti yüklenmemiş.", "extension_unknown_origin": "API uç noktasının kaynağını Hoppscotch Tarayıcı Eklentisi listesine eklediğinizden emin olun.", "extention_enable_action": "Tarayıcı Eklentisini Etkinleştir", - "extention_not_enabled": "Eklenti etkin değil." + "extention_not_enabled": "Eklenti etkin değil.", + "localaccess_unsupported": "Mevcut interceptor yerel erişimi desteklemiyor, lütfen Agent, Extension interceptor veya Masaüstü Uygulamasını kullanmayı düşünün" + }, + "auth": { + "digest": "Digest Authorization kullanırken web uygulamasında Agent interceptor veya Masaüstü uygulamasında Native interceptor önerilir.", + "hawk": "Hawk Authorization kullanırken web uygulamasında Agent interceptor veya Masaüstü uygulamasında Native interceptor önerilir." + }, + "body": { + "binary": "Mevcut interceptor üzerinden ikili veri gönderimi henüz desteklenmiyor." + }, + "scripting_interceptor": { + "pre_request": "istek öncesi betik", + "post_request": "istek sonrası betik", + "both_scripts": "istek öncesi ve istek sonrası betikler", + "unsupported_interceptor": "{scriptType} betiğiniz {apiUsed} kullanıyor. Güvenilir betik çalıştırma için Agent interceptor (web uygulaması) veya Native interceptor (Masaüstü uygulaması) kullanın. {interceptor} interceptor, betik istekleri için sınırlı desteğe sahiptir ve beklendiği gibi çalışmayabilir.", + "same_origin_csrf_warning": "Güvenlik Uyarısı: {scriptType} betiğiniz {apiUsed} kullanarak aynı kaynağa istek gönderiyor. Bu platform çerez tabanlı kimlik doğrulama kullandığından, bu istekler oturum çerezlerinizi otomatik olarak içerir ve kötü amaçlı betiklerin yetkisiz işlemler yapmasına olanak tanıyabilir. Aynı kaynağa yapılan istekler için Agent interceptor kullanın veya yalnızca güvendiğiniz betikleri çalıştırın." + } + }, + "interceptor": { + "native": { + "name": "Yerel", + "settings_title": "Yerel" + }, + "agent": { + "name": "Agent", + "settings_title": "Agent" + }, + "proxy": { + "name": "Proxy", + "settings_title": "Proxy" + }, + "browser": { + "name": "Tarayıcı", + "settings_title": "Tarayıcı" + }, + "extension": { + "name": "Uzantı", + "settings_title": "Uzantı" } }, "layout": { @@ -497,7 +1032,9 @@ "confirm": "Onayla", "customize_request": "İsteği Özelleştir", "edit_request": "İsteği Düzenle", + "edit_response": "Yanıtı Düzenle", "import_export": "İçe/Dışa Aktarma", + "response_name": "Yanıt Adı", "share_request": "İsteği Paylaş" }, "mqtt": { @@ -531,12 +1068,81 @@ "url": "Bağlantı" }, "navigation": { + "admin_dashboard": "Gösterge Paneli", "doc": "Dokümanlar", "graphql": "GraphQL", "profile": "Profil", "realtime": "Gerçek Zamanlı", "rest": "REST", - "settings": "Ayarlar" + "mock_servers": "Mock Sunucular", + "settings": "Ayarlar", + "goto_app": "Uygulamaya Git", + "authentication": "Kimlik Doğrulama" + }, + "mock_server": { + "confirm_delete_log": "Bu günlüğü silmek istediğinizden emin misiniz?", + "create_mock_server": "Mock Sunucuyu Yapılandır", + "mock_server_configuration": "Mock Sunucu Yapılandırması", + "mock_server_name": "Mock Sunucu Adı", + "mock_server_name_placeholder": "Mock sunucu adını girin", + "base_url": "Temel URL", + "start_server": "Sunucuyu Başlat", + "stop_server": "Sunucuyu Durdur", + "mock_server_created": "Mock sunucu başarıyla oluşturuldu", + "mock_server_started": "Mock sunucu başarıyla başlatıldı", + "mock_server_stopped": "Mock sunucu başarıyla durduruldu", + "active": "Mock sunucu aktif", + "inactive": "Mock sunucu pasif", + "edit_mock_server": "Mock Sunucuyu Düzenle", + "path_based_url": "Yol tabanlı URL", + "subdomain_based_url": "Alt alan adı tabanlı URL", + "mock_server_updated": "Mock sunucu başarıyla güncellendi", + "no_collection": "Koleksiyon yok", + "collection_deleted": "ilişkili koleksiyon silindi.", + "private_access_hint": "Özel mock sunucular için, Kişisel Erişim Token'ınızla birlikte 'x-api-key' header'ını ekleyin (profilinizden oluşturabilirsiniz).", + "private_access_instruction": "Bu özel mock sunucuya erişmek için, Kişisel Erişim Token'ınızla birlikte 'x-api-key' header'ını ekleyin.", + "create_token_here": "Burada oluşturun", + "status": "Durum", + "server_running": "Sunucu çalışıyor", + "server_stopped": "Sunucu durduruldu", + "delay_ms": "Yanıt Gecikmesi (ms)", + "delay_placeholder": "Gecikmeyi milisaniye cinsinden girin", + "delay_description": "Mock yanıtlara yapay gecikme ekleyin", + "public_access": "Herkese Açık Erişim", + "public": "Herkese Açık", + "private": "Özel", + "public_description": "URL'ye sahip herkes bu mock sunucuya erişebilir", + "private_description": "Bu mock sunucuya yalnızca kimliği doğrulanmış kullanıcılar erişebilir", + "select_collection": "Bir koleksiyon seçin", + "select_collection_error": "Lütfen bir koleksiyon seçin", + "invalid_collection_error": "Koleksiyon için mock sunucu oluşturulamadı.", + "url_copied": "URL panoya kopyalandı", + "make_public": "Herkese Açık Yap", + "view_logs": "Günlükleri görüntüle", + "logs_title": "Mock Sunucu Günlükleri", + "no_logs": "Kullanılabilir günlük yok", + "request_headers": "İstek Header'ları", + "request_body": "İstek Gövdesi", + "response_status": "Yanıt Durumu", + "response_headers": "Yanıt Header'ları", + "response_body": "Yanıt Gövdesi", + "log_deleted": "Günlük başarıyla silindi", + "description": "Mock sunucular, koleksiyonunuzun örnek yanıtlarına dayalı olarak API yanıtlarını simüle etmenizi sağlar.", + "set_in_environment": "Ortama ayarla", + "set_in_environment_hint": "Mock sunucu URL'si koleksiyonun ortamına otomatik olarak 'mockUrl' değişkeni olarak eklenecektir", + "environment_variable_added": "Mock URL ortama eklendi", + "environment_variable_updated": "Ortamdaki mock URL güncellendi", + "environment_created_with_variable": "Mock URL ile ortam oluşturuldu", + "add_example_request": "Örnek istek ekle", + "add_example_request_hint": "Koleksiyon, mock sunucunun nasıl kullanılacağını gösteren örnek bir istekle oluşturulacaktır", + "create_example_collection": "Örnek koleksiyon oluştur", + "create_example_collection_hint": "Örnek isteklerle (GET, POST, PUT, DELETE) bir evcil hayvan mağazası örnek koleksiyonu oluşturun", + "creating_example_collection": "Örnek koleksiyon oluşturuluyor...", + "failed_to_create_collection": "Örnek koleksiyon oluşturulamadı", + "enable_example_collection_hint": "Yeni koleksiyon modu için lütfen 'Örnek koleksiyon oluştur' düğmesini etkinleştirin", + "new_collection_name_hint": "Koleksiyon, mock sunucunuzla aynı adla oluşturulacaktır", + "existing_collection": "Mevcut Koleksiyon", + "new_collection": "Yeni Koleksiyon" }, "preRequest": { "javascript_code": "JavaScript Kodu", @@ -557,13 +1163,15 @@ "roles_description": "Roller, paylaşılan koleksiyonlara erişimi kontrol etmek için kullanılır.", "updated": "Profil güncellendi", "viewer": "Misafir", - "viewer_description": "Misafirler sadece istekleri görünteleyebilir ve kullanabilir." + "viewer_description": "Misafirler sadece istekleri görüntüleyebilir ve kullanabilir.", + "verified_email_sent": "E-posta adresinize bir doğrulama e-postası gönderildi. Lütfen e-postanızı doğruladıktan sonra sayfayı yenileyin. Bu e-posta başka bir hesapla ilişkili değilse bir e-posta alacaksınız." }, "remove": { "star": "Yıldızı kaldır" }, "request": { "added": "İstek eklendi", + "add": "İstek Ekle", "authorization": "Yetki", "body": "İstek gövdesi", "choose_language": "Dil seçiniz", @@ -571,8 +1179,10 @@ "content_type_titles": { "others": "Diğerleri", "structured": "Yapılandırılmış", - "text": "Metin" + "text": "Metin", + "binary": "İkili" }, + "show_content_type": "İçerik Türünü Göster", "different_collection": "Farklı koleksiyonlardan istek sıralanamaz", "duplicated": "İstek kopyalanmış", "duration": "Süre", @@ -600,6 +1210,7 @@ "rename": "İsteği Yeniden Adlandır", "renamed": "Yeniden adlandırılmış istek", "request_variables": "İstek değişkenleri", + "response_name_exists": "Yanıt adı zaten mevcut", "run": "Çalıştır", "save": "Kaydet", "save_as": "Farklı kaydet", @@ -613,26 +1224,37 @@ "url": "URL", "url_placeholder": "Bir URL girin veya bir cURL komutu yapıştırın", "variables": "Değişkenler", - "view_my_links": "Bağlantılarımı Görüntüle" + "view_my_links": "Bağlantılarımı Görüntüle", + "generate_name_error": "İstek adı oluşturulamadı." }, "response": { "audio": "Ses", "body": "Yanıt gövdesi", + "duplicated": "Yanıt kopyalandı", + "duplicate_name_error": "Aynı isimde yanıt zaten mevcut", "filter_response_body": "JSON yanıt gövdesini filtrele (jq sözdizimi kullanır)", "headers": "Başlıklar", + "request_headers": "İstek Header'ları", "html": "HTML", "image": "Resim", "json": "JSON", "pdf": "PDF", + "please_save_request": "Örnek oluşturmak için isteği kaydedin", "preview_html": "HTML'i önizle", "raw": "Ham", + "renamed": "Yanıt yeniden adlandırıldı", + "same_name_inspector_warning": "Bu istek için aynı adda yanıt zaten mevcut, kaydedilirse mevcut yanıtın üzerine yazılacaktır", "size": "Boyut", "status": "Durum", "time": "Süre", "title": "Yanıt", "video": "Video", "waiting_for_connection": "Bağlantı için bekleniyor", - "xml": "XML" + "xml": "XML", + "generate_data_schema": "Veri Şeması Oluştur", + "data_schema": "Veri Şeması", + "saved": "Yanıt kaydedildi", + "invalid_name": "Lütfen yanıt için bir ad girin" }, "settings": { "accent_color": "Vurgu rengi", @@ -642,12 +1264,26 @@ "account_email_description": "Birincil e-posta adresiniz.", "account_name_description": "Bu sizin görünen adınız.", "additional": "Ekstra Ayarlar", + "agent_not_running": "Hoppscotch Agent algılanamadı. Lütfen Agent'ın çalışıp çalışmadığını kontrol edin.", + "agent_not_running_short": "Agent'ın durumunu kontrol edin.", + "agent_running": "Hoppscotch Agent çalışıyor.", + "agent_running_short": "Hoppscotch Agent çalışıyor.", + "agent_discard_registration": "Agent Kaydını İptal Et", + "agent_registered": "Agent Kayıtlı", + "agent_registration_successful": "Agent Başarıyla Kaydedildi", + "agent_registration_fetch_failed": "Agent kayıt bilgileri alınamadı. Lütfen Agent'ı yeniden kaydedin.", + "agent_registration_already_in_progress": "Agent kaydı zaten devam ediyor. Lütfen mevcut kaydı tamamlayın veya iptal edin ve tekrar deneyin.", + "auto_encode_mode": "Otomatik", + "auto_encode_mode_tooltip": "İstekteki parametreleri yalnızca bazı özel karakterler varsa kodla", "background": "Arka plan", "black_mode": "Siyah", "choose_language": "Dil seçiniz", "dark_mode": "Karanlık", "delete_account": "Hesabı sil", "delete_account_description": "Hesabınızı sildiğinizde, tüm verileriniz kalıcı olarak silinecektir. Bu işlem geri alınamaz.", + "disable_encode_mode_tooltip": "İstekteki parametreleri asla kodlama", + "enable_encode_mode_tooltip": "İstekteki parametreleri her zaman kodla", + "enter_otp": "Agent kodunu girin", "expand_navigation": "Gezinmeyi genişlet", "experiments": "Deneyler", "experiments_notice": "Bu, üzerinde çalıştığımız, yararlı, eğlenceli, her ikisi de ya da hiçbiri olabilecek bir deneyler koleksiyonudur. Nihai değiller ve istikrarlı olmayabilirler, bu yüzden aşırı garip bir şey olursa panik yapmayın.", @@ -656,28 +1292,48 @@ "extensions": "Uzantılar", "extensions_use_toggle": "İstek göndermek için tarayıcı uzantısını kullanın (varsa)", "follow": "Bizi Takip Et", + "general": "Genel", + "general_description": "Uygulamada kullanılan genel ayarlar", "interceptor": "Önleyici", "interceptor_description": "Uygulama ve API'ler arasındaki ara katman yazılımı.", + "kernel_interceptor": "Interceptor", + "kernel_interceptor_description": "Uygulama ve API'ler arasındaki ara katman.", "language": "Dil", "light_mode": "Aydınlık", "official_proxy_hosting": "Resmi Proxy, Hoppscotch tarafından barındırılmaktadır.", + "query_parameters_encoding": "Sorgu Parametreleri Kodlaması", + "query_parameters_encoding_description": "İsteklerdeki sorgu parametreleri için kodlamayı yapılandırın", "profile": "Profil", "profile_description": "Profil detaylarını güncelle", "profile_email": "E-posta adresi", "profile_name": "Profil ismi", + "profile_photo": "Profil fotoğrafı", "proxy": "Proxy", "proxy_url": "Proxy URL'si", "proxy_use_toggle": "İstek göndermek için proxy ara yazılımını kullanın", "read_the": "Oku", + "register_agent": "Agent'ı Kaydet", "reset_default": "Varsayılana sıfırla", "short_codes": "Kısa kodlar", "short_codes_description": "Sizin oluşturduğunuz kısa kodlar.", "sidebar_on_left": "Soldaki kenar çubuğu", + "ai_experiments": "Yapay Zeka Deneyleri", + "ai_request_naming_style": "İstek Adlandırma Stili", + "ai_request_naming_style_descriptive_with_spaces": "Boşluklu Açıklayıcı", + "ai_request_naming_style_camel_case": "Camel Case ( camelCase )", + "ai_request_naming_style_snake_case": "Snake Case ( snake_case )", + "ai_request_naming_style_pascal_case": "Pascal Case ( PascalCase )", + "ai_request_naming_style_custom": "Özel", + "ai_request_naming_style_custom_placeholder": "Özel adlandırma stili şablonunuzu girin...", + "experimental_scripting_sandbox": "Deneysel betik sandbox'ı", + "enable_experimental_mock_servers": "Mock Sunucuları Etkinleştir", + "enable_experimental_documentation": "Dokümantasyonu Etkinleştir", "sync": "Senkronize et", "sync_collections": "Koleksiyonlar", "sync_description": "Bu ayarlar bulutla senkronize edilir.", "sync_environments": "Ortamlar", "sync_history": "Tarih", + "history_disabled": "Geçmiş devre dışı. Geçmişi etkinleştirmek için organizasyon yöneticinizle iletişime geçin", "system_mode": "Sistem", "telemetry": "Telemetri", "telemetry_helps_us": "Telemetri, operasyonlarımızı kişiselleştirmemize ve size en iyi deneyimi sunmamıza yardımcı olur.", @@ -686,7 +1342,34 @@ "use_experimental_url_bar": "Ortam vurgulamalı deneysel URL çubuğunu kullanın", "user": "Kullanıcı", "verified_email": "Doğrulanmış e-posta", - "verify_email": "E-postayı doğrula" + "verify_email": "E-postayı doğrula", + "validate_certificates": "SSL/TLS Sertifikalarını Doğrula", + "verify_host": "Ana Bilgisayarı Doğrula", + "verify_peer": "Eşi Doğrula", + "follow_redirects": "Yönlendirmeleri Takip Et", + "client_certificates": "İstemci Sertifikaları", + "certificate_settings": "Sertifika Ayarları", + "certificate": "Sertifika", + "key": "Özel Anahtar", + "pfx_or_p12": "PFX/PKCS#12", + "password": "Parola", + "select_file": "Dosya Seç", + "domain": "Alan Adı", + "add_certificate": "Sertifika Ekle", + "add_cert_file": "Sertifika Dosyası Ekle", + "add_key_file": "Anahtar Dosyası Ekle", + "add_pfx_file": "PFX Dosyası Ekle", + "global_defaults": "Genel Varsayılanlar", + "add_domain_override": "Alan Adı Geçersiz Kılma Ekle", + "domain_override": "Alan Adı Geçersiz Kılma", + "manage_domains_overrides": "Alan Adı Geçersiz Kılmalarını Yönet", + "add_domain": "Alan Adı Ekle", + "remove_domain": "Alan Adını Kaldır", + "ca_certificate": "CA Sertifikası", + "ca_certificates": "CA Sertifikaları", + "ca_certificates_support": "Hoppscotch, bir veya daha fazla sertifika içeren .crt, .cer veya .pem dosyalarını destekler.", + "proxy_capabilities": "Hoppscotch Agent ve Masaüstü Uygulaması, NTLM ve Basic Auth desteği ile HTTP/HTTPS/SOCKS proxy'lerini destekler.", + "proxy_auth": "Kullanıcı adı ve parolayı URL'ye de ekleyebilirsiniz." }, "shared_requests": { "button": "Buton", @@ -712,7 +1395,25 @@ "light": "Aydınlık", "system": "Sistem", "title": "Tema" - } + }, + "action": "İşlem", + "clear_filter": "Filtreyi Temizle", + "confirm_request_deletion": "Seçilen paylaşılan isteğin silinmesini onaylıyor musunuz?", + "copy": "Kopyala", + "created_on": "Oluşturulma Tarihi", + "delete": "Sil", + "email": "E-posta", + "filter": "Filtrele", + "filter_by_email": "E-postaya göre filtrele", + "id": "ID", + "load_list_error": "Paylaşılan istekler listesi yüklenemedi", + "no_requests": "Paylaşılan istek bulunamadı", + "open_request": "İsteği Aç", + "properties": "Özellikler", + "request": "İstek", + "show_more": "Daha fazla göster", + "title": "Paylaşılan İstekler", + "url": "URL" }, "shortcut": { "general": { @@ -720,7 +1421,11 @@ "command_menu": "Arama ve komut menüsü", "help_menu": "Yardım menüsü", "show_all": "Klavye kısayolları", - "title": "Genel" + "title": "Genel", + "comment_uncomment": "Yorum Yap/Kaldır", + "close_tab": "Sekmeyi Kapat", + "undo": "Geri Al", + "redo": "Yinele" }, "miscellaneous": { "invite": "İnsanları Hoppscotch'a davet edin", @@ -758,13 +1463,26 @@ "send_request": "İstek gönder", "share_request": "İsteği paylaş", "show_code": "Kod örneği oluştur", - "title": "İstek" + "title": "İstek", + "focus_url": "URL çubuğuna odaklan" }, "response": { "copy": "Yanıtı panoya kopyala", "download": "Yanıtı dosya olarak indir", "title": "Yanıt" }, + "tabs": { + "title": "Sekmeler", + "new_tab": "Yeni Sekme", + "close_tab": "Sekmeyi Kapat", + "reopen_tab": "Kapatılan Sekmeyi Yeniden Aç", + "next_tab": "Sonraki Sekme", + "previous_tab": "Önceki Sekme", + "first_tab": "İlk Sekmeye Geç", + "last_tab": "Son Sekmeye Geç", + "mru_switch": "Son kullanılan sekmeye geç (MRU)", + "mru_switch_reverse": "Önceki son kullanılan sekmeye geç (MRU)" + }, "theme": { "black": "Temayı siyah mod olarak ayarla", "dark": "Temayı karanlık mod olarak ayarla", @@ -777,7 +1495,8 @@ "code": "Kodu göster", "collection": "Koleksiyon Panelini Genişlet", "more": "Daha fazla göster", - "sidebar": "Kenar çubuğunu göster" + "sidebar": "Kenar çubuğunu göster", + "password": "Şifreyi Göster" }, "socketio": { "communication": "İletişim", @@ -855,6 +1574,12 @@ "close_others": "Diğer tüm sekmeleri kapat", "duplicate": "Mevcut sekmeyi kopyala", "new_tab": "Yeni sekme aç", + "next": "Sonraki sekmeye geç", + "previous": "Önceki sekmeye geç", + "switch_to_first": "İlk sekmeye geç", + "switch_to_last": "Son sekmeye geç", + "mru_switch": "Son kullanılan sekmeye geç", + "mru_switch_reverse": "Önceki son kullanılan sekmeye geç", "title": "Sekmeler" }, "workspace": { @@ -899,6 +1624,7 @@ "download_failed": "İndirme başarısız", "download_started": "İndirme başladı", "enabled": "Etkinleştirildi", + "experimental": "Deneysel", "file_imported": "Dosya içe aktarıldı", "finished_in": "{duration} ms içinde tamamlandı", "hide": "Gizle", @@ -907,17 +1633,127 @@ "loading": "Yükleniyor...", "message_received": "Mesaj: {message} konuya: {topic} ulaştı", "mqtt_subscription_failed": "Konuya abone olurken bir hata oluştu: {topic}", + "no_content_found": "İçerik bulunamadı", "none": "Hiçbiri", "nothing_found": "hiçbir şey bulunamadı", "published_error": "Mesaj yayınlanırken bir hata oluştu: {topic} konuya mesaj: {message}", "published_message": "Mesaj yayınlandı: {message} konuya: {topic}", "reconnection_error": "Yeniden bağlanılamadı", + "saved": "Kaydedildi", "show": "Göster", "subscribed_failed": "Konuya abone olamadı: {topic}", "subscribed_success": "Başarıyla abone olundu konuya: {topic}", "unsubscribed_failed": "Konu aboneliğinden çıkılamadı: {topic}", "unsubscribed_success": "Başarıyla konu aboneliğinden çıkıldı: {topic}", - "waiting_send_request": "istek göndermek için bekleniyor" + "waiting_send_request": "istek göndermek için bekleniyor", + "user_deactivated": "Hesabınız devre dışı bırakıldı. Hesabınızı yeniden etkinleştirmek için lütfen yöneticiyle iletişime geçin.", + "add_user_failure": "Kullanıcı çalışma alanına eklenemedi!!", + "add_user_success": "Kullanıcı artık çalışma alanının bir üyesi!!", + "admin_failure": "Kullanıcı yönetici yapılamadı!!", + "admin_success": "Kullanıcı artık bir yönetici!!", + "and": "ve", + "clear_selection": "Seçimi Temizle", + "configure_auth": "Lütfen yönetici ayarlarından bir kimlik doğrulama sağlayıcısı kurun veya kimlik doğrulama sağlayıcılarını yapılandırmak için belgelere göz atın.", + "confirm_admin_to_user": "Bu kullanıcının yönetici durumunu kaldırmak istiyor musunuz?", + "confirm_admins_to_users": "Seçili kullanıcıların yönetici durumunu kaldırmak istiyor musunuz?", + "confirm_delete_infra_token": "{tokenLabel} altyapı token'ını silmek istediğinizden emin misiniz?", + "confirm_delete_invite": "Seçili daveti iptal etmek istiyor musunuz?", + "confirm_delete_invites": "Seçili davetleri iptal etmek istiyor musunuz?", + "confirm_user_deletion": "Kullanıcı silme onaylansın mı?", + "confirm_users_deletion": "Seçili kullanıcıları silmek istiyor musunuz?", + "confirm_user_to_admin": "Bu kullanıcıyı yönetici yapmak istiyor musunuz?", + "confirm_users_to_admin": "Seçili kullanıcıları yönetici yapmak istiyor musunuz?", + "confirm_user_deactivation": "Kullanıcı devre dışı bırakma onaylansın mı?", + "confirm_logout": "Çıkışı Onayla", + "created_on": "Oluşturulma Tarihi", + "continue_email": "E-posta ile Devam Et", + "continue_github": "Github ile Devam Et", + "continue_google": "Google ile Devam Et", + "continue_microsoft": "Microsoft ile Devam Et", + "create_team_failure": "Çalışma alanı oluşturulamadı!!", + "create_team_success": "Çalışma alanı başarıyla oluşturuldu!!", + "data_sharing_failure": "Veri paylaşım ayarları güncellenemedi", + "delete_infra_token_failure": "Altyapı token'ı silinirken bir hata oluştu", + "delete_invite_failure": "Davet silinemedi!!", + "delete_invites_failure": "Seçili davetler silinemedi!!", + "delete_invite_success": "Davet başarıyla silindi!!", + "delete_invites_success": "Seçili davetler başarıyla silindi!!", + "delete_request_failure": "Paylaşılan istek silme başarısız oldu!!", + "delete_request_success": "Paylaşılan istek başarıyla silindi!!", + "delete_team_failure": "Çalışma alanı silme başarısız oldu!!", + "delete_team_success": "Çalışma alanı başarıyla silindi!!", + "delete_some_users_failure": "Silinemeyen Kullanıcı Sayısı: {count}", + "delete_some_users_success": "Silinen Kullanıcı Sayısı: {count}", + "delete_user_failed_only_one_admin": "Kullanıcı silinemedi. En az bir yönetici bulunmalıdır!!", + "delete_user_failure": "Kullanıcı silme başarısız oldu!!", + "delete_users_failure": "Seçili kullanıcılar silinemedi!!", + "delete_user_success": "Kullanıcı başarıyla silindi!!", + "delete_users_success": "Seçili kullanıcılar başarıyla silindi!!", + "email": "E-posta", + "email_failure": "Davet gönderilemedi", + "email_signin_failure": "E-posta ile giriş yapılamadı", + "email_success": "E-posta daveti başarıyla gönderildi", + "emails_cannot_be_same": "Kendinizi davet edemezsiniz, lütfen farklı bir e-posta adresi seçin!!", + "enter_team_email": "Lütfen çalışma alanı sahibinin e-postasını girin!!", + "error": "Bir hata oluştu", + "error_auth_providers": "Kimlik doğrulama sağlayıcıları yüklenemedi", + "generate_infra_token_failure": "Altyapı token'ı oluşturulurken bir hata oluştu", + "github_signin_failure": "Github ile giriş yapılamadı", + "google_signin_failure": "Google ile giriş yapılamadı", + "infra_token_label_short": "Altyapı Token Etiketi karakter uzunluğu çok kısa!!", + "invalid_email": "Lütfen geçerli bir e-posta adresi girin", + "link_copied_to_clipboard": "Bağlantı panoya kopyalandı", + "logged_out": "Çıkış yapıldı", + "login_as_admin": "ve bir yönetici hesabıyla giriş yapın.", + "login_using_email": "Lütfen kullanıcıdan e-postasını kontrol etmesini isteyin veya aşağıdaki bağlantıyı paylaşın", + "login_using_link": "Lütfen kullanıcıdan aşağıdaki bağlantıyı kullanarak giriş yapmasını isteyin", + "logout": "Çıkış Yap", + "magic_link_sign_in": "Giriş yapmak için bağlantıya tıklayın.", + "magic_link_success": "Sihirli bağlantı şu adrese gönderildi", + "microsoft_signin_failure": "Microsoft ile giriş yapılamadı", + "newsletter_failure": "Bülten ayarları güncellenemedi", + "non_admin_logged_in": "Yönetici olmayan kullanıcı olarak giriş yapıldı.", + "non_admin_login": "Giriş yaptınız. Ancak yönetici değilsiniz", + "owner_not_present": "Takımda en az bir sahip bulunmalıdır!!", + "privacy_policy": "Gizlilik Politikası", + "reenter_email": "E-postayı tekrar girin", + "remove_admin_failure": "Yönetici durumu kaldırılamadı!!", + "remove_admin_failure_only_one_admin": "Yönetici durumu kaldırılamadı. En az bir yönetici bulunmalıdır!!", + "remove_admin_success": "Yönetici durumu kaldırıldı!!", + "remove_admin_from_users_failure": "Seçili kullanıcıların yönetici durumu kaldırılamadı!!", + "remove_admin_from_users_success": "Seçili kullanıcıların yönetici durumu kaldırıldı!!", + "remove_admin_to_delete_user": "Kullanıcıyı silmek için yönetici yetkisini kaldırın!!", + "remove_owner_to_delete_user": "Kullanıcıyı silmek için takım sahipliği durumunu kaldırın!!", + "remove_owner_failure_only_one_owner": "Üye kaldırılamadı. Bir takımda en az bir sahip bulunmalıdır!!", + "remove_admin_for_deletion": "Silme işleminden önce yönetici durumunu kaldırın!!", + "remove_owner_for_deletion": "Bir veya daha fazla kullanıcı takım sahibidir. Silmeden önce sahipliği güncelleyin!!", + "remove_invitee_failure": "Davetli kaldırma başarısız oldu!!", + "remove_invitee_success": "Davetli başarıyla kaldırıldı!!", + "remove_member_failure": "Üye kaldırılamadı!!", + "remove_member_success": "Üye başarıyla kaldırıldı!!", + "rename_team_failure": "Çalışma alanı yeniden adlandırılamadı!!", + "rename_team_success": "Çalışma alanı başarıyla yeniden adlandırıldı!", + "rename_user_failure": "Kullanıcı yeniden adlandırılamadı!!", + "rename_user_success": "Kullanıcı başarıyla yeniden adlandırıldı!!", + "require_auth_provider": "Giriş yapmak için en az bir kimlik doğrulama sağlayıcısı ayarlamalısınız.", + "role_update_failed": "Roller güncellenemedi!!", + "role_update_success": "Roller başarıyla güncellendi!!", + "selected": "{count} seçili", + "self_host_docs": "Kendi Sunucunuzda Barındırma Belgeleri", + "send_magic_link": "Sihirli bağlantı gönder", + "setup_failure": "Kurulum başarısız oldu!!", + "setup_success": "Kurulum başarıyla tamamlandı!!", + "sign_in_agreement": "Giriş yaparak şunları kabul etmiş olursunuz:", + "sign_in_options": "Tüm giriş seçenekleri", + "sign_out": "Çıkış yap", + "something_went_wrong": "Bir hata oluştu", + "team_name_too_short": "Çalışma alanı adı en az 6 karakter uzunluğunda olmalıdır!!", + "user_already_invited": "Davet gönderilemedi. Kullanıcı zaten davet edilmiş!!", + "user_not_found": "Kullanıcı altyapıda bulunamadı!!", + "users_to_admin_success": "Seçili kullanıcılar yönetici yapıldı!!", + "users_to_admin_failure": "Seçili kullanıcılar yönetici yapılamadı!!", + "loading_workspaces": "Çalışma alanları yükleniyor", + "loading_collections_in_workspace": "Çalışma alanındaki koleksiyonlar yükleniyor" }, "support": { "changelog": "En son sürümler hakkında daha fazla bilgi edin", @@ -943,6 +1779,7 @@ "history": "Geçmiş", "mqtt": "MQTT", "parameters": "Parametreler", + "post_request_script": "İstek Sonrası Script", "pre_request_script": "Ön İstek Komut Dosyası", "queries": "Sorgular", "query": "Sorgu", @@ -950,18 +1787,27 @@ "shared_requests": "Paylaşılan İstekler", "codegen": "Kod Üret", "code_snippet": "Kod parçası", + "mock_servers": "Mock Sunucular", "share_tab_request": "İstek sekmesini paylaş", "socketio": "Socket.IO", "sse": "SSE", - "tests": "Testler", "types": "Türler", "variables": "Değişkenler", - "websocket": "WebSocket" + "websocket": "WebSocket", + "all_tests": "Tüm Testler", + "passed": "Başarılı", + "failed": "Başarısız" }, "team": { + "activity_logs": "Etkinlik Günlükleri", "already_member": "Siz zaten bu ekibin bir üyesisiniz. Takım sahibinizle iletişime geçin.", "create_new": "Yeni takım oluştur", "deleted": "Takım silindi", + "delete_all_activity_logs": "Tüm etkinlik günlüklerini sil", + "successfully_deleted_all_activity_logs": "Tüm etkinlik günlükleri başarıyla silindi", + "delete_activity_log": "Etkinlik günlüğünü sil", + "deleted_activity_log": "Seçili etkinlik günlüğü silindi", + "deleted_all_activity_logs": "Tüm etkinlik günlükleri silindi", "edit": "Takımı düzenle", "email": "e-posta", "email_do_not_match": "E-posta, hesap ayrıntılarınızla eşleşmiyor. Takım sahibinizle iletişime geçin.", @@ -977,10 +1823,10 @@ "invite": "Davet et", "invite_more": "Daha fazla davet et", "invite_tooltip": "İnsanları bu çalışma alanına davet edin", - "invited_to_team": "{owner} seni {team} takımına davet etti.", + "invited_to_team": "{owner} sizi {workspace} çalışma alanına katılmaya davet etti", "join": "Davet kabul edildi", - "join_team": "{team}'e katıl", - "joined_team": "{team} takımına katıldın", + "join_team": "{workspace} çalışma alanına katıl", + "joined_team": "{workspace} çalışma alanına katıldınız", "joined_team_description": "Artık bu takımın bir üyesisin", "left": "Takımdan ayrıldın", "login_to_continue": "Devam etmek için giriş yapın", @@ -1015,7 +1861,9 @@ "we_sent_invite_link_description": "Tüm davetlilerden gelen kutularını kontrol etmelerini isteyin. Ekibe katılmak için bağlantıya tıklayın.", "invite_sent_smtp_disabled_description": "Bu Hoppscotch örneği için davet e-postaları gönderme devre dışı bırakıldı. Lütfen davet bağlantısını manuel olarak kopyalamak ve paylaşmak için Bağlantıyı kopyala düğmesini kullanın.", "copy_invite_link": "Davet Bağlantısını Kopyala", - "search_title": "Takım İstekleri" + "search_title": "Takım İstekleri", + "user_not_found": "Kullanıcı bu örnekte bulunamadı.", + "invite_members": "Üyeleri Davet Et" }, "team_environment": { "deleted": "Ortam Silindi", @@ -1023,6 +1871,8 @@ "not_found": "Ortam Bulunamadı." }, "test": { + "requests": "İstekler", + "selection": "Seçim", "failed": "Test başarısız", "javascript_code": "JavaScript Kodu", "learn": "Belgeleri okuyun", @@ -1030,7 +1880,14 @@ "report": "Test raporu", "results": "Test sonuçları", "script": "Komut dosyası", - "snippets": "Parçalar" + "snippets": "Parçalar", + "run": "Çalıştır", + "run_again": "Tekrar çalıştır", + "stop": "Durdur", + "new_run": "Yeni Çalıştırma", + "iterations": "Yinelemeler", + "duration": "Süre", + "avg_resp": "Ort. Yanıt Süresi" }, "websocket": { "communication": "İletişim", @@ -1080,19 +1937,394 @@ "cli_environment_id_description": "Bu ortam ID'si, Hoppscotch için CLI koleksiyon çalıştırıcısı tarafından kullanılacaktır.", "include_active_environment": "Aktif ortamı dahil et:", "cli": "CLI", + "cli_comming_soon_for_personal_collection": "Kişisel koleksiyonlar için CLI'da Koleksiyon Çalıştırıcı desteği yakında eklenecek.", + "delay": "Gecikme", + "negative_delay": "Gecikme negatif olamaz", "ui": "Runner (yakında)", + "running_collection": "Koleksiyon çalıştırılıyor", + "run_config": "Çalıştırma Yapılandırması", + "advanced_settings": "Gelişmiş Ayarlar", + "stop_on_error": "Hata oluşursa çalıştırmayı durdur", + "persist_responses": "Yanıtları sakla", + "keep_variable_values": "Değişken değerlerini koru", + "collection_not_found": "Koleksiyon bulunamadı. Silinmiş veya taşınmış olabilir.", + "empty_collection": "Koleksiyon boş. Çalıştırmak için istek ekleyin.", + "no_response_persist": "Koleksiyon çalıştırıcısı şu anda yanıtları saklamayacak şekilde yapılandırılmıştır. Bu ayar, yanıt verilerinin gösterilmesini engeller. Bu davranışı değiştirmek için yeni bir çalıştırma yapılandırması başlatın.", + "select_request": "Yanıt ve test sonuçlarını görmek için bir istek seçin", + "response_body_lost_rerun": "Yanıt gövdesi kayboldu. Yanıt gövdesini almak için koleksiyonu tekrar çalıştırın.", "cli_command_generation_description_cloud": "Aşağıdaki komutu kopyalayın ve CLI üzerinden çalıştırın. Lütfen bir kişisel erişim anahtarı belirtin.", "cli_command_generation_description_sh": "Aşağıdaki komutu kopyalayın ve CLI üzerinden çalıştırın. Lütfen bir kişisel erişim anahtarı belirtin ve oluşturulan SH örneği sunucu URL'sini doğrulayın.", "cli_command_generation_description_sh_with_server_url_placeholder": "Aşağıdaki komutu kopyalayın ve CLI üzerinden çalıştırın. Lütfen bir kişisel erişim anahtarı ve SH örneği sunucu URL'sini belirtin.", - "run_collection": "Koleksiyonu Çalıştır" - }, - "shortcodes": { - "actions": "İşlemler", - "created_on": "Oluşturuldu", - "deleted": "Kısa kod silindi", - "method": "Metod", - "not_found": "Kısa kod bulunamadı", - "short_code": "Kısa kod", - "url": "URL" + "run_collection": "Koleksiyonu Çalıştır", + "no_passed_tests": "Başarılı test yok", + "no_failed_tests": "Başarısız test yok" + }, + "ai_experiments": { + "generate_request_name": "AI Kullanarak İstek Adı Oluştur", + "generate_or_modify_request_body": "İstek Gövdesini Oluştur veya Değiştir", + "modify_with_ai": "AI ile Değiştir", + "generate": "Oluştur", + "generate_or_modify_request_body_input_placeholder": "İstek gövdesini değiştirmek için komutunuzu girin", + "accept_change": "Değişikliği Kabul Et", + "feedback_success": "Geri bildirim başarıyla gönderildi", + "feedback_failure": "Geri bildirim gönderilemedi", + "feedback_thank_you": "Geri bildiriminiz için teşekkürler!", + "feedback_cta_text_long": "Üretimi değerlendirin, iyileştirmemize yardımcı olun", + "feedback_cta_request_name": "Oluşturulan adı beğendiniz mi?", + "modify_request_body_error": "İstek gövdesi değiştirilemedi", + "generate_or_modify_prerequest_input_placeholder": "İstek öncesi betiği oluşturmak veya değiştirmek için bir komut girin", + "generate_or_modify_post_request_script_input_placeholder": "İstek sonrası betiği oluşturmak veya değiştirmek için bir komut girin", + "modify_post_request_script_error": "İstek sonrası betik değiştirilemedi", + "modify_prerequest_error": "İstek öncesi betik değiştirilemedi" + }, + "configs": { + "auth_providers": { + "callback_url": "GERİ ÇAĞIRMA URL'Sİ", + "client_id": "İSTEMCİ KİMLİĞİ", + "client_secret": "İSTEMCİ GİZLİ ANAHTARI", + "description": "Sunucunuz için kimlik doğrulama sağlayıcılarını yapılandırın", + "provider_not_specified": "Lütfen en az bir kimlik doğrulama sağlayıcısını etkinleştirin", + "scope": "KAPSAM", + "tenant": "KİRACI", + "title": "Kimlik Doğrulama Sağlayıcıları", + "update_failure": "Kimlik doğrulama sağlayıcısı yapılandırmaları güncellenemedi!" + }, + "confirm_changes": "Yeni değişikliklerin yansıması için Hoppscotch sunucusunun yeniden başlatılması gerekir. Sunucu yapılandırmalarında yapılan değişiklikleri onaylıyor musunuz?", + "input_empty": "Yapılandırmaları güncellemeden önce lütfen tüm alanları doldurun", + "data_sharing": { + "title": "Veri Paylaşımı", + "description": "Anonim veri paylaşarak Hoppscotch'u iyileştirmeye yardımcı olun", + "enable": "Veri Paylaşımını Etkinleştir", + "secondary_title": "Veri Paylaşımı Yapılandırmaları", + "see_shared": "Nelerin paylaşıldığını gör", + "toggle_description": "Anonim veri paylaş", + "update_failure": "Veri paylaşımı yapılandırmaları güncellenemedi!" + }, + "load_error": "Sunucu yapılandırmaları yüklenemedi", + "mail_configs": { + "address_from": "GÖNDERİCİ ADRESİ", + "custom_smtp_configs": "Özel SMTP Yapılandırmaları Kullan", + "description": "SMTP yapılandırmalarını ayarlayın", + "enable_email_auth": "E-posta tabanlı kimlik doğrulamayı etkinleştir", + "enable_smtp": "SMTP'yi Etkinleştir", + "host": "POSTA SUNUCUSU", + "password": "POSTA ŞİFRESİ", + "port": "POSTA PORTU", + "secure": "POSTA GÜVENLİ", + "smtp_url": "POSTA SMTP URL'Sİ", + "tls_reject_unauthorized": "TLS YETKİSİZ BAĞLANTIYI REDDET", + "title": "SMTP Yapılandırmaları", + "toggle_failure": "SMTP değiştirilemedi!", + "update_failure": "SMTP yapılandırmaları güncellenemedi!", + "user": "POSTA KULLANICISI" + }, + "reset": { + "confirm_reset": "Yeni değişikliklerin yansıması için Hoppscotch sunucusunun yeniden başlatılması gerekir. Sunucu yapılandırmalarının sıfırlanmasını onaylıyor musunuz?", + "description": "Ortam dosyasında belirtilen varsayılan yapılandırmalar yüklenecektir", + "failure": "Yapılandırmalar sıfırlanamadı!", + "title": "Yapılandırmaları Sıfırla", + "info": "Sunucu yapılandırmalarını sıfırla" + }, + "restart": { + "description": "Bu sayfa otomatik olarak yenilenmeden önce {duration} saniye kaldı", + "initiate": "Sunucu yeniden başlatılıyor...", + "title": "Sunucu yeniden başlatılıyor" + }, + "save_changes": "Değişiklikleri Kaydet", + "title": "Yapılandırmalar", + "update_failure": "Sunucu yapılandırmaları güncellenemedi", + "restrict_access": "Erişimi Kısıtla", + "site_protection": { + "control_access": "Hoppscotch uygulamasına kimin erişebileceğini kontrol edin", + "description": "Site koruma ayarlarını kullanarak ziyaretçilerin Hoppscotch uygulamanıza nasıl erişeceğini özelleştirin.", + "enable": "Site korumasını etkinleştir", + "note": "Hoppscotch uygulamasını ziyaret eden kullanıcılar giriş sayfasını görecektir, uygulamaya erişmek için giriş zorunludur. Yetkilendirme için yönetici onayı hâlâ gereklidir", + "update_failure": "Site koruma yapılandırmaları güncellenemedi!" + }, + "domain_whitelisting": { + "add_domain": "Yeni Alan Adı Ekle", + "description": "Beyaz listedeki alan adlarında kayıtlı e-posta adresine sahip kullanıcıların Hoppscotch uygulamasına erişmek için yönetici onayına ihtiyacı yoktur", + "enable": "Alan adı beyaz listesini etkinleştir", + "enter_domain": "Alan adı girin", + "title": "Beyaz Listedeki Alan Adları", + "toggle_failure": "Alan adı beyaz listesi değiştirilemedi", + "update_failure": "Alan adı beyaz listesi yapılandırmaları güncellenemedi!" + }, + "oidc_configs": { + "auth_url": "Auth URL", + "callback_url": "Geri Çağırma URL'si", + "client_id": "İstemci Kimliği", + "client_secret": "İstemci Gizli Anahtarı", + "description": "OIDC yapılandırmalarını ayarlayın", + "enable": "OIDC tabanlı kimlik doğrulamayı etkinleştir", + "issuer": "Veren", + "provider_name": "Sağlayıcı Adı", + "scope": "Kapsam", + "title": "OIDC Yapılandırmaları", + "token_url": "Token URL", + "update_failure": "OIDC yapılandırmaları güncellenemedi!", + "user_info_url": "Kullanıcı Bilgisi URL'si" + }, + "saml": { + "audience": "Hedef Kitle", + "callback_url": "Geri Çağırma URL'si", + "certificate": "Sertifika", + "description": "SAML yapılandırmalarını ayarlayın", + "enable": "SAML tabanlı kimlik doğrulamayı etkinleştir", + "entry_point": "Giriş Noktası", + "issuer": "Veren", + "title": "SAML Yapılandırmaları", + "update_failure": "SAML SSO yapılandırmaları güncellenemedi!", + "want_assertions_signed": "Bildirimleri İmzala", + "want_response_signed": "Yanıtı İmzala" + } + }, + "data_sharing": { + "description": "Hoppscotch'u iyileştirmek için anonim kullanım verisi paylaşın", + "enable": "Veri Paylaşımını Etkinleştir", + "see_shared": "Nelerin paylaşıldığını gör", + "toggle_description": "Veri paylaşın ve Hoppscotch'u daha iyi yapın", + "title": "Hoppscotch'u Daha İyi Yapın", + "welcome": "Hoş geldiniz" + }, + "infra_tokens": { + "copy_token_warning": "Altyapı token'ınızı şimdi kopyaladığınızdan emin olun. Tekrar görüntüleyemezsiniz!", + "deletion_success": "{label} altyapı token'ı silindi", + "empty": "Altyapı token'ları boş", + "expired": "Süresi Dolmuş", + "expiration_label": "Son Kullanma", + "expires_on": "Bitiş tarihi", + "generate_modal_title": "Yeni Altyapı Token'ı", + "generate_new_token": "Yeni token oluştur", + "generate_token": "Token Oluştur", + "invalid_label": "Lütfen token için bir etiket girin", + "last_used_on": "Son kullanım tarihi", + "no_expiration": "Süresiz", + "no_expiration_verbose": "Bu token'ın süresi asla dolmayacak!", + "section_description": "Altyapı token'ları ile Hoppscotch kullanıcılarınızı API'ler aracılığıyla yönetin", + "section_title": "Altyapı Token'ları", + "tab_title": "Altyapı Token'ları", + "token_expires_on": "Bu token'ın süresi şu tarihte dolacak:", + "token_purpose": "Bu token'ı tanımlamak için bir etiket girin" + }, + "metrics": { + "dashboard": "Gösterge Paneli", + "no_metrics": "Metrik bulunamadı", + "total_collections": "Toplam Koleksiyon", + "total_requests": "Toplam İstek", + "total_teams": "Toplam Çalışma Alanı", + "total_users": "Toplam Kullanıcı" + }, + "newsletter": { + "description": "En son haberlerimiz hakkında güncellemeler alın", + "subscribe": "Abone Ol", + "title": "İletişimde Kalın", + "toggle_description": "Hoppscotch'taki en son gelişmeler hakkında güncellemeler alın", + "unsubscribe": "Abonelikten Çık" + }, + "teams": { + "add_member": "Üye Ekle", + "add_members": "Üyeleri Ekle", + "add_new": "Yeni Ekle", + "admin": "Yönetici", + "admin_Email": "Yönetici E-postası", + "admin_id": "Yönetici ID", + "cancel": "İptal", + "confirm_team_deletion": "Çalışma alanını silmeyi onaylıyor musunuz?", + "copy": "Kopyala", + "create_team": "Çalışma Alanı Oluştur", + "date": "Tarih", + "delete_team": "Çalışma Alanını Sil", + "details": "Ayrıntılar", + "edit": "Düzenle", + "editor": "EDİTÖR", + "editor_description": "Editörler istek ve koleksiyon ekleyebilir, düzenleyebilir ve silebilir.", + "email": "Çalışma alanı sahibi e-postası", + "email_address": "E-posta Adresi", + "email_title": "E-posta", + "empty_name": "Takım adı boş olamaz!!", + "error": "Bir hata oluştu. Lütfen daha sonra tekrar deneyin.", + "id": "Çalışma Alanı ID", + "invited_email": "Davetli E-postası", + "invited_on": "Davet Tarihi", + "invites": "Davetler", + "load_info_error": "Çalışma alanı bilgileri yüklenemedi", + "load_list_error": "Çalışma Alanı Listesi Yüklenemedi", + "members": "Üye sayısı", + "no_invite": "Davet yok", + "no_invite_description": "İş birliğine başlamak için takımınızı davet edin", + "owner": "SAHİP", + "owner_description": "Sahipler istek, koleksiyon ve çalışma alanı üyelerini ekleyebilir, düzenleyebilir ve silebilir.", + "permissions": "İzinler", + "name": "Çalışma Alanı Adı", + "no_members": "Bu çalışma alanında üye yok. İş birliği yapmak için bu çalışma alanına üye ekleyin", + "no_pending_invites": "Bekleyen davet yok", + "no_teams": "Çalışma alanı bulunamadı..", + "no_teams_description": "Takımınızla iş birliği yapmak için bir çalışma alanı oluşturun", + "pending_invites": "Bekleyen davetler", + "roles": "Roller", + "roles_description": "Roller, paylaşılan koleksiyonlara erişimi kontrol etmek için kullanılır.", + "remove": "Kaldır", + "rename": "Yeniden Adlandır", + "save": "Kaydet", + "save_changes": "Değişiklikleri Kaydet", + "send_invite": "Davet Gönder", + "show_more": "Daha fazla göster", + "team_details": "Çalışma alanı ayrıntıları", + "team_members": "Üyeler", + "team_members_tab": "Çalışma alanı üyeleri", + "teams": "Çalışma Alanı", + "uid": "UID", + "unnamed": "(Adsız Çalışma Alanı)", + "viewer": "İZLEYİCİ", + "viewer_description": "İzleyiciler yalnızca istekleri görüntüleyebilir ve kullanabilir", + "valid_name": "Lütfen geçerli bir çalışma alanı adı girin", + "valid_owner_email": "Lütfen geçerli bir sahip e-postası girin" + }, + "users": { + "add_user": "Kullanıcı Ekle", + "admin": "Yönetici", + "admin_id": "Yönetici ID", + "cancel": "İptal", + "created_on": "Oluşturulma Tarihi", + "copy_invite_link": "Davet Bağlantısını Kopyala", + "copy_link": "Bağlantıyı Kopyala", + "date": "Tarih", + "delete": "Sil", + "delete_user": "Kullanıcıyı Sil", + "delete_users": "Kullanıcıları Sil", + "details": "Ayrıntılar", + "edit": "Düzenle", + "email": "E-posta", + "email_address": "E-posta Adresi", + "empty_name": "Ad boş olamaz!!", + "id": "Kullanıcı ID", + "invalid_user": "Geçersiz Kullanıcı", + "invite_load_list_error": "Davet Edilen Kullanıcılar Listesi Yüklenemedi", + "invite_user": "Kullanıcı Davet Et", + "invited_by": "Davet Eden", + "invited_on": "Davet Tarihi", + "invited_users": "Davet Edilen Kullanıcılar", + "invitee_email": "Davetli E-postası", + "last_active_on": "Son Etkinlik", + "load_info_error": "Kullanıcı bilgileri yüklenemedi", + "load_list_error": "Kullanıcı Listesi Yüklenemedi", + "make_admin": "Yönetici Yap", + "name": "Ad", + "new_user_added": "Yeni Kullanıcı Eklendi", + "no_invite": "Bekleyen davet bulunamadı", + "no_invite_description": "Bekleyen davet yok! Takım arkadaşlarınızı Hoppscotch'a davet etmeye başlayın", + "no_shared_requests": "Kullanıcı tarafından oluşturulmuş paylaşılan istek yok", + "no_users": "Kullanıcı bulunamadı", + "not_available": "Mevcut Değil", + "not_found": "Kullanıcı bulunamadı", + "pending_invites": "Bekleyen Davetler", + "remove_admin_privilege": "Yönetici Yetkisini Kaldır", + "remove_admin_status": "Yönetici Durumunu Kaldır", + "rename": "Yeniden Adlandır", + "revoke_invitation": "Daveti İptal Et", + "searchbar_placeholder": "Ad veya e-posta ile arayın..", + "send_invite": "Davet Gönder", + "show_more": "Daha fazla göster", + "uid": "UID", + "unnamed": "(Adsız Kullanıcı)", + "user_not_found": "Kullanıcı altyapıda bulunamadı!!", + "users": "Kullanıcılar", + "valid_email": "Lütfen geçerli bir e-posta adresi girin", + "deactivate": "Devre Dışı Bırak", + "deactivate_user": "Kullanıcıyı Devre Dışı Bırak" + }, + "organization": { + "login_to_continue_description": "Bir organizasyon örneğine katılmak için giriş yapmanız gerekir.", + "create_an_organization": "Bir organizasyon oluşturun", + "deactivate_user_failure": "Kullanıcı devre dışı bırakma başarısız oldu!", + "deactivate_user_success": "Kullanıcı başarıyla devre dışı bırakıldı!", + "delete_account_description": "Bu işlem, Hoppscotch hesabınızla ilişkili tüm verileri silecektir; bu hesap ve parçası olduğunuz diğer tüm organizasyonlar dahil.", + "delete_account": "Hoppscotch Hesabını Sil", + "user_deletion_failed_sole_admin": "Kullanıcı bir veya daha fazla organizasyon örneğinin tek yöneticisidir. Silme işleminden önce lütfen kullanıcıyı yöneticilikten çıkarın.", + "user_deletion_failed_sole_team_owner": "Kullanıcı bir veya daha fazla organizasyon örneğinde tek takım sahibidir. Silme işleminden önce lütfen sahipliği devredin veya ilgili çalışma alanlarını silin.", + "no_organizations": "Herhangi bir organizasyonun üyesi değilsiniz", + "admin": "Yönetici" + }, + "organization_sidebar": { + "hoppscotch_cloud": "Hoppscotch Cloud", + "cloud_locked": "Varsayılan örnek kaldırılamaz", + "admin": "Yönetici", + "error_loading": "Organizasyonlar yüklenemedi", + "inactive_orgs": "Pasif Organizasyonlar", + "no_orgs_found": "Organizasyon bulunamadı", + "no_active_orgs_found": "Aktif organizasyon bulunamadı", + "organizations_for": "{email} için organizasyonlar", + "multi_account_notice": "Her organizasyon kendi oturumunu tutar ve en son erişilen hesabı kullanır.", + "inactive_orgs_tooltip": "Yardım için destek ekibiyle iletişime geçin." + }, + "billing": { + "confirm": { + "update_seat_count": "Kullanıcı sayısını {newSeatCount} olarak güncellemek istediğinizden emin misiniz?", + "update_billing_cycle": "Fatura döngüsünü {newBillingCycle} olarak güncellemek istediğinizden emin misiniz?" + }, + "cancel_subscription": "Aboneliği iptal et" + }, + "app_console": { + "entries": "Konsol kayıtları", + "no_entries": "Kayıt yok" + }, + "mockServer": { + "create_modal": { + "title": "Mock Sunucu Oluştur", + "name_label": "Mock Sunucu Adı", + "name_placeholder": "Mock sunucu adını girin", + "name_required": "Mock sunucu adı gereklidir", + "collection_source_label": "Koleksiyon Kaynağı", + "existing_collection": "Mevcut Koleksiyon", + "new_collection": "Yeni Koleksiyon", + "select_collection_label": "Koleksiyon Seç", + "select_collection_placeholder": "Bir koleksiyon seçin", + "collection_required": "Lütfen bir koleksiyon seçin", + "collection_name_label": "Koleksiyon Adı", + "collection_name_placeholder": "Koleksiyon adını girin", + "collection_name_required": "Koleksiyon adı gereklidir", + "request_config_label": "İstek Yapılandırması", + "add_request": "İstek Ekle", + "create_button": "Mock Sunucu Oluştur", + "success": "Mock sunucu başarıyla oluşturuldu", + "error": "Mock sunucu oluşturulamadı", + "no_collections": "Kullanılabilir koleksiyon yok" + }, + "edit_modal": { + "title": "Mock Sunucuyu Düzenle", + "name_label": "Mock Sunucu Adı", + "name_placeholder": "Mock sunucu adını girin", + "name_required": "Mock sunucu adı gereklidir", + "active_label": "Aktif", + "url_label": "Mock Sunucu URL'si", + "collection_label": "Koleksiyon", + "update_button": "Mock Sunucuyu Güncelle", + "success": "Mock sunucu başarıyla güncellendi", + "error": "Mock sunucu güncellenemedi", + "url_copied": "URL panoya kopyalandı" + }, + "dashboard": { + "title": "Mock Sunucular", + "subtitle": "API mock sunucularınızı oluşturun ve yönetin", + "create_button": "Mock Sunucu Oluştur", + "create_first": "İlk mock sunucunuzu oluşturun", + "empty_title": "Mock sunucu bulunamadı", + "empty_description": "Arka uç bağımlılığı olmadan ön uç ve mobil geliştirmeyi etkinleştirmek için API koleksiyonlarınıza dayalı mock sunucular oluşturun.", + "collection": "Koleksiyon", + "active": "Aktif", + "inactive": "Pasif", + "mock_url": "Mock URL", + "endpoints": "Uç Noktalar", + "created": "Oluşturulma", + "view_collection": "Koleksiyonu Görüntüle", + "documentation": "Dokümantasyon", + "doc_description": "Bu URL'yi uygulamalarınızda API temel URL'si olarak kullanın:", + "url_copied": "Mock sunucu URL'si panoya kopyalandı", + "delete_title": "Mock Sunucuyu Sil", + "delete_description": "Bu mock sunucuyu silmek istediğinizden emin misiniz?", + "delete_success": "Mock sunucu başarıyla silindi", + "delete_error": "Mock sunucu silinemedi" + } } } diff --git a/packages/hoppscotch-common/package.json b/packages/hoppscotch-common/package.json index 9a3267e1711..6abc4db9b5a 100644 --- a/packages/hoppscotch-common/package.json +++ b/packages/hoppscotch-common/package.json @@ -1,7 +1,7 @@ { "name": "@hoppscotch/common", "private": true, - "version": "2026.3.1", + "version": "2026.4.0", "scripts": { "dev": "pnpm exec npm-run-all -p -l dev:*", "test": "vitest --run", @@ -44,8 +44,8 @@ "@hoppscotch/ui": "0.2.5", "@hoppscotch/vue-toasted": "0.1.0", "@lezer/highlight": "1.2.1", - "@noble/curves": "2.0.1", - "@scure/base": "2.0.0", + "@noble/curves": "2.2.0", + "@scure/base": "2.2.0", "@shopify/lang-jsonc": "1.0.1", "@tauri-apps/api": "2.1.1", "@tauri-apps/plugin-store": "2.4.1", @@ -59,16 +59,16 @@ "@vueuse/core": "14.2.1", "acorn-walk": "8.3.5", "aws4fetch": "1.0.20", - "axios": "1.13.6", + "axios": "1.15.2", "buffer": "6.0.3", "cookie-es": "2.0.0", "dioc": "3.0.2", - "dompurify": "3.3.3", + "dompurify": "3.4.1", "esprima": "4.0.1", "events": "3.3.0", "fp-ts": "2.16.11", "globalthis": "1.0.4", - "graphql": "16.13.1", + "graphql": "16.13.2", "graphql-language-service-interface": "2.10.2", "graphql-tag": "2.12.6", "hawk": "9.0.2", @@ -80,7 +80,7 @@ "js-md5": "0.8.3", "js-yaml": "4.1.1", "jsonc-parser": "3.3.1", - "lodash-es": "4.17.23", + "lodash-es": "4.18.1", "lossless-json": "4.3.0", "markdown-it": "14.1.1", "minisearch": "7.2.0", @@ -90,9 +90,9 @@ "path": "0.12.7", "postman-collection": "5.3.0", "process": "0.11.10", - "qs": "6.15.0", + "qs": "6.15.1", "quicktype-core": "23.2.6", - "rollup": "4.59.0", + "rollup": "4.60.2", "rxjs": "7.8.2", "set-cookie-parser": "2.7.2", "set-cookie-parser-es": "1.0.5", @@ -111,8 +111,8 @@ "util": "0.12.5", "uuid": "13.0.0", "verzod": "0.4.0", - "vue": "3.5.31", - "vue-i18n": "11.3.0", + "vue": "3.5.33", + "vue-i18n": "11.4.0", "vue-json-pretty": "2.6.0", "vue-pdf-embed": "2.1.4", "vue-router": "4.6.4", @@ -129,17 +129,17 @@ "@esbuild-plugins/node-modules-polyfill": "0.2.2", "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.2", - "@graphql-codegen/add": "6.0.0", - "@graphql-codegen/cli": "6.2.1", - "@graphql-codegen/typed-document-node": "6.1.7", - "@graphql-codegen/typescript": "5.0.9", - "@graphql-codegen/typescript-operations": "5.0.9", + "@graphql-codegen/add": "6.0.1", + "@graphql-codegen/cli": "6.3.1", + "@graphql-codegen/typed-document-node": "6.1.8", + "@graphql-codegen/typescript": "5.0.10", + "@graphql-codegen/typescript-operations": "5.1.0", "@graphql-codegen/typescript-urql-graphcache": "3.1.1", "@graphql-codegen/urql-introspection": "3.0.1", "@graphql-typed-document-node/core": "3.2.0", - "@iconify-json/lucide": "1.2.99", + "@iconify-json/lucide": "1.2.104", "@import-meta-env/cli": "0.7.4", - "@intlify/unplugin-vue-i18n": "11.0.7", + "@intlify/unplugin-vue-i18n": "11.1.2", "@relmify/jest-fp-ts": "2.1.1", "@rushstack/eslint-patch": "1.16.1", "@types/har-format": "1.2.16", @@ -151,35 +151,35 @@ "@types/qs": "6.15.0", "@types/splitpanes": "2.2.6", "@types/yargs-parser": "21.0.3", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@vitejs/plugin-vue": "6.0.5", - "@vue/compiler-sfc": "3.5.31", + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", + "@vitejs/plugin-vue": "6.0.6", + "@vue/compiler-sfc": "3.5.33", "@vue/eslint-config-typescript": "14.7.0", - "@vue/runtime-core": "3.5.31", - "autoprefixer": "10.4.27", + "@vue/runtime-core": "3.5.33", + "autoprefixer": "10.5.0", "cross-env": "10.1.0", - "dotenv": "17.3.1", + "dotenv": "17.4.2", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", - "eslint-plugin-vue": "10.8.0", + "eslint-plugin-vue": "10.9.0", "glob": "13.0.6", "globals": "16.5.0", "jsdom": "27.4.0", "npm-run-all": "4.1.5", "openapi-types": "12.1.3", - "postcss": "8.5.8", - "prettier": "3.8.1", + "postcss": "8.5.10", + "prettier": "3.8.3", "prettier-plugin-tailwindcss": "0.7.2", "rollup-plugin-polyfill-node": "0.13.0", - "sass": "1.98.0", + "sass": "1.99.0", "tailwindcss": "3.4.16", "tsup": "8.5.1", "typescript": "5.9.3", "unplugin-fonts": "1.4.0", "unplugin-icons": "22.5.0", "unplugin-vue-components": "30.0.0", - "vite": "7.3.1", + "vite": "7.3.2", "vite-plugin-checker": "0.12.0", "vite-plugin-fonts": "0.7.0", "vite-plugin-html-config": "2.0.2", @@ -187,7 +187,7 @@ "vite-plugin-pages-sitemap": "1.7.1", "vite-plugin-pwa": "1.2.0", "vite-plugin-vue-layouts": "0.11.0", - "vitest": "4.1.2", + "vitest": "4.1.5", "vue-tsc": "1.8.8" } } diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts index 6a8215eabff..5cf1795bf38 100644 --- a/packages/hoppscotch-common/src/components.d.ts +++ b/packages/hoppscotch-common/src/components.d.ts @@ -245,6 +245,7 @@ declare module 'vue' { IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default'] IconLucideCircleCheck: typeof import('~icons/lucide/circle-check')['default'] IconLucideFileQuestion: typeof import('~icons/lucide/file-question')['default'] + IconLucideFileSymlink: typeof import('~icons/lucide/file-symlink')['default'] IconLucideFileText: typeof import('~icons/lucide/file-text')['default'] IconLucideFileX: typeof import('~icons/lucide/file-x')['default'] IconLucideFolder: typeof import('~icons/lucide/folder')['default'] @@ -305,6 +306,7 @@ declare module 'vue' { RealtimeSubscription: typeof import('./components/realtime/Subscription.vue')['default'] SettingsAgent: typeof import('./components/settings/Agent.vue')['default'] SettingsAgentSubtitle: typeof import('./components/settings/AgentSubtitle.vue')['default'] + SettingsDesktop: typeof import('./components/settings/Desktop.vue')['default'] SettingsExtension: typeof import('./components/settings/Extension.vue')['default'] SettingsExtensionSubtitle: typeof import('./components/settings/ExtensionSubtitle.vue')['default'] SettingsInterceptorErrorPlaceholder: typeof import('./components/settings/InterceptorErrorPlaceholder.vue')['default'] diff --git a/packages/hoppscotch-common/src/components/MonacoScriptEditor.vue b/packages/hoppscotch-common/src/components/MonacoScriptEditor.vue index 9cc7295c6df..0c9c15d1bd3 100644 --- a/packages/hoppscotch-common/src/components/MonacoScriptEditor.vue +++ b/packages/hoppscotch-common/src/components/MonacoScriptEditor.vue @@ -26,9 +26,11 @@ const props = withDefaults( defineProps<{ modelValue: string type: "pre-request" | "post-request" + readOnly?: boolean }>(), { modelValue: "", + readOnly: false, } ) @@ -40,12 +42,15 @@ const emit = defineEmits<{ const editorModel = ref(null) -const MONACO_EDITOR_OPTIONS: Readonly = - { - automaticLayout: true, - formatOnType: true, - formatOnPaste: true, - } +const MONACO_EDITOR_OPTIONS = computed< + Readonly +>(() => ({ + automaticLayout: true, + formatOnType: !props.readOnly, + formatOnPaste: !props.readOnly, + readOnly: props.readOnly, + domReadOnly: props.readOnly, +})) // Static imports: import X from "URL" const staticImportRegex = @@ -237,3 +242,27 @@ const monacoEditorTheme = computed(() => ["dark", "black"].includes(theme.value) ? "vs-dark" : "vs" ) + + diff --git a/packages/hoppscotch-common/src/components/app/Sidenav.vue b/packages/hoppscotch-common/src/components/app/Sidenav.vue index 336058e3892..e325ae29b8e 100644 --- a/packages/hoppscotch-common/src/components/app/Sidenav.vue +++ b/packages/hoppscotch-common/src/components/app/Sidenav.vue @@ -10,6 +10,7 @@ content: !EXPAND_NAVIGATION ? t(navigation.title) : null, }" :to="navigation.target" + :aria-label="!EXPAND_NAVIGATION ? t(navigation.title) : null" class="nav-link" tabindex="0" :exact="navigation.exact" diff --git a/packages/hoppscotch-common/src/components/collections/Properties.vue b/packages/hoppscotch-common/src/components/collections/Properties.vue index a11e10258f4..9d97acb71f1 100644 --- a/packages/hoppscotch-common/src/components/collections/Properties.vue +++ b/packages/hoppscotch-common/src/components/collections/Properties.vue @@ -64,6 +64,83 @@ /> + +
+ + +
+
+ +
+
+
+
+ + +
+
+ +
+
+
+
+
+ +
+ + {{ t("helpers.collection_properties_scripts") }} +
+
+
+ + + diff --git a/packages/hoppscotch-common/src/components/http/InheritedScriptsModal.vue b/packages/hoppscotch-common/src/components/http/InheritedScriptsModal.vue new file mode 100644 index 00000000000..3e3b8c2810d --- /dev/null +++ b/packages/hoppscotch-common/src/components/http/InheritedScriptsModal.vue @@ -0,0 +1,145 @@ + + + diff --git a/packages/hoppscotch-common/src/components/http/PreRequestScript.vue b/packages/hoppscotch-common/src/components/http/PreRequestScript.vue index fba723da721..a94a1c461b0 100644 --- a/packages/hoppscotch-common/src/components/http/PreRequestScript.vue +++ b/packages/hoppscotch-common/src/components/http/PreRequestScript.vue @@ -3,9 +3,26 @@
- +
+ + +
+ () const emit = defineEmits<{ (e: "update:modelValue", value: string): void @@ -121,6 +148,16 @@ const emit = defineEmits<{ const preRequestScript = useVModel(props, "modelValue", emit) +const showInheritedModal = ref(false) + +const inheritedScripts = computed(() => { + return ( + props.inheritedProperties?.scripts?.filter((script) => + hasActualScript(script.preRequestScript) + ) ?? [] + ) +}) + const preRequestEditor = ref(null) const WRAP_LINES = useNestedSetting("WRAP_LINES", "httpPreRequest") diff --git a/packages/hoppscotch-common/src/components/http/RequestOptions.vue b/packages/hoppscotch-common/src/components/http/RequestOptions.vue index 7619b92b525..d9ac58a7add 100644 --- a/packages/hoppscotch-common/src/components/http/RequestOptions.vue +++ b/packages/hoppscotch-common/src/components/http/RequestOptions.vue @@ -54,17 +54,16 @@ :id="'preRequestScript'" :label="`${t('tab.pre_request_script')}`" :indicator=" - 'preRequestScript' in request && - request.preRequestScript && - request.preRequestScript.length > 0 - ? true - : false + ('preRequestScript' in request && + hasActualScript(request.preRequestScript)) || + hasInheritedPreRequestScripts " >
{ return Boolean(request.value.body.body && request.value.body.body.length > 0) }) +const hasInheritedPreRequestScripts = computed(() => { + return ( + props.inheritedProperties?.scripts?.some((script) => + hasActualScript(script.preRequestScript) + ) ?? false + ) +}) + +const hasInheritedTestScripts = computed(() => { + return ( + props.inheritedProperties?.scripts?.some((script) => + hasActualScript(script.testScript) + ) ?? false + ) +}) + defineActionHandler("request.open-tab", ({ tab }) => { selectedOptionTab.value = tab as RESTOptionTabs }) diff --git a/packages/hoppscotch-common/src/components/http/Tests.vue b/packages/hoppscotch-common/src/components/http/Tests.vue index 9b9ddd256eb..f00afa83e80 100644 --- a/packages/hoppscotch-common/src/components/http/Tests.vue +++ b/packages/hoppscotch-common/src/components/http/Tests.vue @@ -3,9 +3,26 @@
- +
+ + +
+ () + const emit = defineEmits(["update:modelValue"]) const testScript = useVModel(props, "modelValue", emit) + +const showInheritedModal = ref(false) + +const inheritedScripts = computed(() => { + return ( + props.inheritedProperties?.scripts?.filter((script) => + hasActualScript(script.testScript) + ) ?? [] + ) +}) + const testScriptEditor = ref(null) const WRAP_LINES = useNestedSetting("WRAP_LINES", "httpTest") diff --git a/packages/hoppscotch-common/src/components/http/test/Runner.vue b/packages/hoppscotch-common/src/components/http/test/Runner.vue index 5600a81ab7d..9290cae1373 100644 --- a/packages/hoppscotch-common/src/components/http/test/Runner.vue +++ b/packages/hoppscotch-common/src/components/http/test/Runner.vue @@ -249,6 +249,11 @@ const runTests = async () => { ) let resolvedCollection: HoppCollection = collection.value + // Scripts declared on ancestors above the selected run-start node — must be + // seeded into the runner so partial-scope runs still honor the documented + // Root → Parent → Child → Request inheritance chain. + let ancestorPreRequestScripts: string[] = [] + let ancestorTestScripts: string[] = [] if (!isPersonalWorkspace) { const requestAuth = tab.value.document.inheritedProperties?.auth @@ -270,6 +275,19 @@ const runTests = async () => { tab.value.document.inheritedProperties?.variables ?? [] ) + // Team cascade includes the selected node itself in its scripts array; + // drop it here because runTestCollection will cascade that node's scripts + // as part of the normal tree walk, and we must not double-run them. + const inheritedScripts = ( + tab.value.document.inheritedProperties?.scripts ?? [] + ).filter((s) => s.parentID !== collectionID) + ancestorPreRequestScripts = inheritedScripts + .map((s) => s.preRequestScript) + .filter((s) => s && s.trim().length > 0) + ancestorTestScripts = inheritedScripts + .map((s) => s.testScript) + .filter((s) => s && s.trim().length > 0) + resolvedCollection = { ...collection.value, auth: requestAuth, @@ -277,12 +295,23 @@ const runTests = async () => { variables: parentVariables, } } else { - const { auth, headers, variables } = collectionInheritedProps ?? { + const { + auth, + headers, + variables, + ancestorPreRequestScripts: preAncestors, + ancestorTestScripts: testAncestors, + } = collectionInheritedProps ?? { auth: { authActive: true, authType: "none" }, headers: [], variables: [], + ancestorPreRequestScripts: [], + ancestorTestScripts: [], } + ancestorPreRequestScripts = preAncestors + ancestorTestScripts = testAncestors + resolvedCollection = { ...collection.value, auth, @@ -292,10 +321,16 @@ const runTests = async () => { } testRunnerStopRef.value = false // when testRunnerStopRef is false, the test runner will start running - testRunnerService.runTests(tab, resolvedCollection, { - ...testRunnerConfig.value, - stopRef: testRunnerStopRef, - }) + testRunnerService.runTests( + tab, + resolvedCollection, + { + ...testRunnerConfig.value, + stopRef: testRunnerStopRef, + }, + ancestorPreRequestScripts, + ancestorTestScripts + ) } const stopTests = () => { diff --git a/packages/hoppscotch-common/src/components/settings/Desktop.vue b/packages/hoppscotch-common/src/components/settings/Desktop.vue new file mode 100644 index 00000000000..659dae2f993 --- /dev/null +++ b/packages/hoppscotch-common/src/components/settings/Desktop.vue @@ -0,0 +1,282 @@ + + + + + diff --git a/packages/hoppscotch-common/src/components/settings/Proxy.vue b/packages/hoppscotch-common/src/components/settings/Proxy.vue index 6c136ea5ff3..5a2f92f1798 100644 --- a/packages/hoppscotch-common/src/components/settings/Proxy.vue +++ b/packages/hoppscotch-common/src/components/settings/Proxy.vue @@ -31,20 +31,17 @@ diff --git a/packages/hoppscotch-common/src/composables/desktop-settings.ts b/packages/hoppscotch-common/src/composables/desktop-settings.ts new file mode 100644 index 00000000000..c8f66f8bfef --- /dev/null +++ b/packages/hoppscotch-common/src/composables/desktop-settings.ts @@ -0,0 +1,180 @@ +import { reactive, ref, readonly } from "vue" +import * as E from "fp-ts/Either" +import { invoke } from "@tauri-apps/api/core" + +// Bind to the unified, process-wide store rather than the org-scoped +// default `Store`. Desktop settings are machine-level configuration +// (for example the "disable update checks" toggle), and the Tauri +// shell reads them through its own `kernel/store.ts` wrapper at the +// same physical path. Going through the org-scoped store would route +// writes to a different file and the shell would never see them. +import { UnifiedStore as Store } from "~/kernel/store" +import { + DESKTOP_SETTINGS_SCHEMA, + DESKTOP_SETTINGS_STORE_KEY, + DESKTOP_SETTINGS_STORE_NAMESPACE, + parseDesktopSettings, + type DesktopSettings, +} from "~/platform/desktop-settings" +import { Log } from "~/kernel/log" + +const LOG_TAG = "useDesktopSettings" + +/** + * Webview-side accessor for the desktop-app user settings. + * + * Reads and writes through `tauri-plugin-store` under the same namespace + * and key as the Tauri shell's persistence service, and mirrors every + * webview-originated write into the Rust-side `DESKTOP_CONFIG` mailbox + * via the `set_desktop_config` Tauri command. + * + * Why the webview handles its own Rust sync rather than relying on the + * shell's watch-based sync: the shell window closes once `appload` loads + * this webview bundle, which tears down the shell's persistence service + * and its watch subscription. Writes made after that point have no shell + * listener to forward them, so the webview owns the sync for its own + * lifetime. The shell's sync handles initial prime at app startup plus + * any shell-originated writes (the portable welcome screen) during its + * short pre-webview life. + * + * `update(key, value)` is transactional: the reactive object is mutated + * first so callers see an optimistic update, but a persist failure rolls + * the reactive back to its previous value and rethrows, so in-memory + * state never drifts from what's in the store. + * + * Module-level singleton: every caller shares the same reactive object + * so the settings section and any other consumer bound to these values + * stay coherent. + */ + +type UpdateFn = ( + key: K, + value: DesktopSettings[K] +) => Promise + +// Singleton state, initialized on first `useDesktopSettings()` call. +const settings = reactive(DESKTOP_SETTINGS_SCHEMA.parse({})) +const loaded = ref(false) +let initPromise: Promise | undefined + +async function loadInitial(): Promise { + // Open the unified store before reading. The shell already inits this + // path through its own `DesktopPersistenceService.init`, but the + // webview runs in a separate window with its own process state, so + // the underlying Tauri store still needs to be opened here. Repeat + // calls land on the same on-disk file and are harmless. + const initResult = await Store.init() + if (E.isLeft(initResult)) { + Log.warn(LOG_TAG, "Failed to init unified store", initResult.left) + } + + const result = await Store.get( + DESKTOP_SETTINGS_STORE_NAMESPACE, + DESKTOP_SETTINGS_STORE_KEY + ) + const raw = E.isRight(result) ? result.right : undefined + Object.assign(settings, parseDesktopSettings(raw)) + loaded.value = true + + // Subscribe to external writes (for example the Tauri shell's portable + // welcome screen) so the reactive object stays current. One subscription + // per process is enough because the reactive object is a module-level + // singleton. + try { + const emitter = await Store.watch( + DESKTOP_SETTINGS_STORE_NAMESPACE, + DESKTOP_SETTINGS_STORE_KEY + ) + emitter.on("change", ({ value }: { value?: unknown }) => { + if (value !== undefined) { + Object.assign(settings, parseDesktopSettings(value)) + } + }) + } catch (err) { + Log.warn(LOG_TAG, "Failed to subscribe to store", err) + } +} + +async function persist(): Promise { + const validated = DESKTOP_SETTINGS_SCHEMA.parse(settings) + const writeResult = await Store.set( + DESKTOP_SETTINGS_STORE_NAMESPACE, + DESKTOP_SETTINGS_STORE_KEY, + validated + ) + if (E.isLeft(writeResult)) { + // `StoreError` is a tagged union. Formatting `kind` and `message` + // explicitly keeps the thrown error readable. A plain + // `${writeResult.left}` interpolation stringifies to + // `[object Object]` and hides the actual cause from stack traces. + const err = writeResult.left + Log.error(LOG_TAG, "Failed to write desktopSettings", err) + throw new Error( + `Failed to write desktopSettings: ${err.kind}: ${err.message}` + ) + } + + // Mirror to Rust. Non-fatal on failure because Rust falls back to + // its compile-time defaults when the mailbox is empty, so a missed + // sync degrades to "Rust reads an older value" rather than rejecting + // the write the user already committed to. + try { + await invoke("set_desktop_config", { config: validated }) + } catch (err) { + Log.warn(LOG_TAG, "Failed to push DesktopSettings to Rust", err) + } +} + +export function useDesktopSettings(): { + /** Reactive settings object. Read-only externally, bind via refs in templates. */ + settings: Readonly + /** True once the initial store read has completed. */ + loaded: Readonly + /** Updates a single setting and persists immediately, rolling back on failure. */ + update: UpdateFn +} { + if (!initPromise) { + initPromise = loadInitial().catch((err) => { + Log.error(LOG_TAG, "Initial load failed", err) + // Swallow so repeat calls retry on next `update()`. + initPromise = undefined + throw err + }) + } + + const update: UpdateFn = async (key, value) => { + // Wait for the initial load before mutating. Without this, a + // user clicking a toggle immediately after mount could interleave + // with `loadInitial()`: the optimistic mutation and persist would + // land first, and then `loadInitial()` would resolve and call + // `Object.assign(settings, ...)` with the old on-disk value, + // overwriting the user's change in memory. + if (initPromise) { + try { + await initPromise + } catch { + // Load failed. The caller's `update` will still attempt a + // persist below, which is the right behaviour: the user + // wants their change saved even if the initial read failed. + } + } + + const previous = settings[key] + settings[key] = value + try { + await persist() + } catch (err) { + // Restore the reactive state so the in-memory view reflects what's + // actually in the store. Without this, a failed persist leaves the + // settings object holding a value the next app start will not find. + settings[key] = previous + throw err + } + } + + return { + settings: readonly(settings) as Readonly, + loaded: readonly(loaded), + update, + } +} diff --git a/packages/hoppscotch-common/src/composables/oauth2/useOAuth2GrantTypes.ts b/packages/hoppscotch-common/src/composables/oauth2/useOAuth2GrantTypes.ts index ea62fc29ac9..dff495a2296 100644 --- a/packages/hoppscotch-common/src/composables/oauth2/useOAuth2GrantTypes.ts +++ b/packages/hoppscotch-common/src/composables/oauth2/useOAuth2GrantTypes.ts @@ -535,7 +535,7 @@ export const useOAuth2GrantTypes = ( }, { id: "password" as const, - label: "Password", + label: t("authorization.oauth.label_password"), formElements: computed(() => { if (!(auth.value.grantTypeInfo.grantType === "PASSWORD")) { return diff --git a/packages/hoppscotch-common/src/composables/update-check.ts b/packages/hoppscotch-common/src/composables/update-check.ts new file mode 100644 index 00000000000..101a694209f --- /dev/null +++ b/packages/hoppscotch-common/src/composables/update-check.ts @@ -0,0 +1,383 @@ +import { ref, readonly, type Ref } from "vue" +import * as E from "fp-ts/Either" +import { invoke } from "@tauri-apps/api/core" +import { listen, type UnlistenFn } from "@tauri-apps/api/event" + +// Bind to the unified, process-wide store rather than the org-scoped +// default `Store`. Persisted `UpdateState` is machine-level, not +// per-org, and the Tauri shell reads the same physical file through +// its own `kernel/store.ts` wrapper. Going through the org-scoped +// store would route writes to a file the shell never reads. +import { UnifiedStore as Store } from "~/kernel/store" +import { + UPDATE_STATE_SCHEMA, + UPDATE_STATE_STORE_KEY, + UPDATE_STATE_STORE_NAMESPACE, + type DownloadProgress as WireDownloadProgress, + type UpdateState as PersistedUpdateState, +} from "~/platform/update-state" +import { Log } from "~/kernel/log" + +const LOG_TAG = "useUpdateCheck" + +/** + * Webview-side accessor for the desktop updater. + * + * Wraps the Tauri updater commands (`check_for_updates`, + * `download_and_install_update`, `restart_application`, `cancel_update`) + * and the `updater-event` Tauri channel into a single reactive accessor. + * + * State is modelled as a discriminated union where each variant carries + * exactly the fields that variant needs (the `available` variant carries + * `latestVersion`, the `downloading` variant carries `progress`, and so + * on). Impossible combinations ("available without a version", "not + * downloading but progress is set") are unrepresentable by construction, + * and callers narrow through `state.kind`. + * + * State transitions are owned by a single pure `applyEvent` function + * driven by the `updater-event` channel. Action wrappers (`check`, + * `download`, `restart`, `cancel`) await initialization before invoking + * so the listener is guaranteed to be subscribed before any command + * fires, and rely on the event stream for the transitions rather than + * mutating state themselves. This removes the "fast path + event" drift + * that made two paths responsible for updating the same refs. + * + * Module-level singleton: every caller gets the same reactive state so + * any consumer (settings page, portable welcome, startup flow) sees the + * same value. + */ + +// Download progress with a derived `percentage`. The wire form from +// Rust and the persisted form only carry `downloaded` and optional +// `total`. The `percentage` is computed on top so the UI has a +// ready-to-bind field. +export interface DownloadProgress extends WireDownloadProgress { + percentage: number +} + +// Response from the `check_for_updates` Tauri command. Used only to +// invoke the command. Actual state transitions arrive on the event +// channel. +interface UpdateInfo { + available: boolean + currentVersion: string + latestVersion?: string + releaseNotes?: string +} + +// Tauri event payload variants. Must match the `UpdateEvent` tagged union in +// `hoppscotch-desktop/src/services/updater.client.ts`. Centralizing this +// type into common would remove the duplication, but the event channel is +// a Rust-to-webview wire contract that currently lives in the shell, so +// keeping the mirror here scoped to this composable is acceptable until +// that contract gets its own shared module. +type UpdateEvent = + | { type: "CheckStarted" } + | { type: "CheckCompleted"; info: UpdateInfo } + | { type: "CheckFailed"; error: string } + | { type: "DownloadStarted"; totalBytes?: number } + // The Rust-emitted payload only carries `downloaded` and optional + // `total`. The reducer derives `percentage` and the persisted + // `DownloadProgress` form below extends with that derived field. + | { type: "DownloadProgress"; progress: WireDownloadProgress } + | { type: "DownloadCompleted" } + | { type: "InstallStarted" } + | { type: "InstallCompleted" } + | { type: "RestartRequired" } + | { type: "UpdateCancelled" } + | { type: "Error"; message: string } + +// The composable's internal state. Each variant carries exactly the +// fields that variant needs. `currentVersion` rides along with any +// post-check variant so the UI can display "currently on vX" context +// regardless of whether an update was found. +export type UpdateState = + | { kind: "idle" } + | { kind: "checking" } + | { + kind: "available" + currentVersion: string + latestVersion: string + } + | { kind: "not_available"; currentVersion: string } + | { kind: "downloading"; progress: DownloadProgress } + | { kind: "installing" } + | { kind: "ready_to_restart" } + | { kind: "error"; message: string } + +// String-literal helper for consumers that want to compare without +// destructuring `state.kind` directly. `UpdateState["kind"]` gives the +// same union at the type level. +export const UpdateKind = { + IDLE: "idle", + CHECKING: "checking", + AVAILABLE: "available", + NOT_AVAILABLE: "not_available", + DOWNLOADING: "downloading", + INSTALLING: "installing", + READY_TO_RESTART: "ready_to_restart", + ERROR: "error", +} as const satisfies Record + +// Singleton state. +const state = ref({ kind: "idle" }) +let initPromise: Promise | undefined +let unlistenFn: UnlistenFn | undefined + +function percentageOf(downloaded: number, total: number | undefined): number { + if (!total || total <= 0) return 0 + return (downloaded / total) * 100 +} + +/** + * Derives the composable's internal `UpdateState` from the flat + * persisted form. The persisted form is a wire contract with Rust and + * older shell code, and translating on read keeps that contract + * unchanged while the composable gets the richer internal type. + */ +function fromPersisted( + persisted: PersistedUpdateState | null | undefined +): UpdateState { + if (!persisted) return { kind: "idle" } + + switch (persisted.status) { + case "idle": + return { kind: "idle" } + case "checking": + return { kind: "checking" } + case "available": + // The persisted form is optional on `version`. If the writer + // omitted it, fall back to idle rather than fabricating a version. + return persisted.version + ? { + kind: "available", + currentVersion: "", + latestVersion: persisted.version, + } + : { kind: "idle" } + case "not_available": + return { kind: "not_available", currentVersion: "" } + case "downloading": { + const downloaded = persisted.progress?.downloaded ?? 0 + const total = persisted.progress?.total + return { + kind: "downloading", + progress: { + downloaded, + total, + percentage: percentageOf(downloaded, total), + }, + } + } + case "installing": + return { kind: "installing" } + case "ready_to_restart": + return { kind: "ready_to_restart" } + case "error": + return { kind: "error", message: persisted.message ?? "Unknown error" } + } +} + +/** + * Pure reducer from current state + incoming event to next state. Kept + * pure (no ref access, no side effects) so it can be exercised in + * isolation and so the full transition table is readable at a glance. + */ +function nextState(current: UpdateState, event: UpdateEvent): UpdateState { + switch (event.type) { + case "CheckStarted": + return { kind: "checking" } + + case "CheckCompleted": + if (event.info.available && event.info.latestVersion) { + return { + kind: "available", + currentVersion: event.info.currentVersion, + latestVersion: event.info.latestVersion, + } + } + return { + kind: "not_available", + currentVersion: event.info.currentVersion, + } + + case "CheckFailed": + return { kind: "error", message: event.error } + + case "DownloadStarted": + return { + kind: "downloading", + progress: { + downloaded: 0, + total: event.totalBytes, + percentage: 0, + }, + } + + case "DownloadProgress": + // The wire form has no `percentage`. Without computing it + // here, `Math.round(progress.percentage)` in the view runs on + // `undefined` and the button label renders "Downloading NaN%" + // for every progress tick. `DownloadStarted` above takes the + // same approach. + return { + kind: "downloading", + progress: { + downloaded: event.progress.downloaded, + total: event.progress.total, + percentage: percentageOf( + event.progress.downloaded, + event.progress.total + ), + }, + } + + case "DownloadCompleted": + return { kind: "installing" } + + case "InstallStarted": + return { kind: "installing" } + + case "InstallCompleted": + // Install is a short step that transitions straight into awaiting a + // restart. The `RestartRequired` event follows and flips the state, + // so keep the current state here rather than double-transitioning. + return current + + case "RestartRequired": + return { kind: "ready_to_restart" } + + case "UpdateCancelled": + return { kind: "idle" } + + case "Error": + return { kind: "error", message: event.message } + } +} + +async function loadPersistedState(): Promise { + // Open the unified store before reading. The shell already opens + // this path through `DesktopPersistenceService.init`, but the + // webview runs in a separate window with its own process state, so + // the underlying Tauri store still needs to be opened here. Repeat + // calls land on the same on-disk file and are harmless. + const initResult = await Store.init() + if (E.isLeft(initResult)) { + Log.warn(LOG_TAG, "Failed to init unified store", initResult.left) + } + + const result = await Store.get( + UPDATE_STATE_STORE_NAMESPACE, + UPDATE_STATE_STORE_KEY + ) + if (E.isRight(result) && result.right) { + const parsed = UPDATE_STATE_SCHEMA.safeParse(result.right) + if (parsed.success) { + state.value = fromPersisted(parsed.data) + } + } +} + +async function subscribeToEvents(): Promise { + if (unlistenFn) return + unlistenFn = await listen("updater-event", (event) => { + state.value = nextState(state.value, event.payload) + }) +} + +async function ensureInitialized(): Promise { + if (!initPromise) { + initPromise = (async () => { + await loadPersistedState() + await subscribeToEvents() + })().catch((err) => { + Log.error(LOG_TAG, "Initialization failed", err) + initPromise = undefined + throw err + }) + } + await initPromise +} + +// Action wrappers. Each awaits initialization so the event listener is +// guaranteed subscribed before the Tauri command runs, then invokes the +// command. State transitions arrive via the event channel, so the +// wrappers do not mutate `state` on success. On `invoke` failure they +// feed a synthetic "failed" event through the same reducer so the +// transition path stays uniform. +async function check(): Promise { + await ensureInitialized() + try { + await invoke("check_for_updates", { showNativeDialog: false }) + } catch (err) { + state.value = nextState(state.value, { + type: "CheckFailed", + error: err instanceof Error ? err.message : String(err), + }) + } +} + +async function download(): Promise { + await ensureInitialized() + try { + await invoke("download_and_install_update") + } catch (err) { + state.value = nextState(state.value, { + type: "Error", + message: err instanceof Error ? err.message : String(err), + }) + } +} + +async function restart(): Promise { + await ensureInitialized() + try { + await invoke("restart_application") + } catch (err) { + state.value = nextState(state.value, { + type: "Error", + message: err instanceof Error ? err.message : String(err), + }) + } +} + +async function cancel(): Promise { + await ensureInitialized() + try { + await invoke("cancel_update") + // State advances to `idle` via the `updater-event` channel. The + // Rust updater emits `UpdateCancelled` on success, so the + // subscribed listener applies the transition. Applying it here + // as well would produce two `idle` transitions per cancel, which + // is harmless today but would double-fire any future side effect + // added to the `UpdateCancelled` case in `nextState`. + } catch (err) { + state.value = nextState(state.value, { + type: "Error", + message: err instanceof Error ? err.message : String(err), + }) + } +} + +export function useUpdateCheck(): { + state: Readonly> + check: () => Promise + download: () => Promise + restart: () => Promise + cancel: () => Promise +} { + // Fire-and-forget initialization so the composable returns synchronously. + // Actions await initialization internally before invoking commands, so + // race-with-subscription is not possible through the action path. A + // consumer that reads `state.value` immediately sees `idle`, which is + // the correct default for a fresh mount. + void ensureInitialized() + + return { + state: readonly(state), + check, + download, + restart, + cancel, + } +} diff --git a/packages/hoppscotch-common/src/composables/useMockServer.ts b/packages/hoppscotch-common/src/composables/useMockServer.ts index ece3df4b72d..32102249f02 100644 --- a/packages/hoppscotch-common/src/composables/useMockServer.ts +++ b/packages/hoppscotch-common/src/composables/useMockServer.ts @@ -4,6 +4,7 @@ import { useToast } from "@composables/toast" import { useService } from "dioc/vue" import { pipe } from "fp-ts/function" import * as TE from "fp-ts/TaskEither" +import { translateToNewEnvironmentVariables } from "@hoppscotch/data" import { computed } from "vue" import { WorkspaceType } from "~/helpers/backend/graphql" import type { MockServer } from "~/helpers/backend/types/MockServer" @@ -13,6 +14,7 @@ import { updateTeamEnvironment, } from "~/helpers/backend/mutations/TeamEnvironment" import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter" +import { uniqueID } from "~/helpers/utils/uniqueID" import { restCollections$ } from "~/newstore/collections" import { addEnvironmentVariable, @@ -27,14 +29,36 @@ import { updateMockServer as updateMockServerInStore, loadMockServers, } from "~/newstore/mockServers" +import { CurrentValueService } from "~/services/current-environment-value.service" import { TeamCollectionsService } from "~/services/team-collection.service" import { WorkspaceService } from "~/services/workspace.service" +/** + * Picks which mock-server URL should be stored as the `mockUrl` + * environment variable. + * + * Policy: always prefer the subdomain-based URL + * (`serverUrlDomainBased`) when it's available and fall back to the + * path-based URL (`serverUrlPathBased`) otherwise. The backend only + * returns `serverUrlDomainBased` when a wildcard domain is configured, + * so the path-based URL is the universal fallback. On the cloud + * instance only `serverUrlDomainBased` is returned, so that URL is + * used there. + */ +function pickMockUrl( + server: Pick +): string { + const path = server.serverUrlPathBased ?? "" + const subdomain = server.serverUrlDomainBased ?? "" + return subdomain || path +} + export function useMockServer() { const t = useI18n() const toast = useToast() const workspaceService = useService(WorkspaceService) const teamCollectionsService = useService(TeamCollectionsService) + const currentValueService = useService(CurrentValueService) const mockServers = useReadonlyStream(mockServers$, []) const collections = useReadonlyStream(restCollections$, []) @@ -93,7 +117,13 @@ export function useMockServer() { const workspaceType = currentWorkspace.value.type if (workspaceType === "personal") { - // For personal workspace, add to selected environment or create new one + // For personal workspace, add to selected environment or create new one. + // + // Architectural note: env variables are split into a persisted half + // (`initialValue`, goes to the store / backend) and a local half + // (`currentValue`, stored only in CurrentValueService). The persisted + // payload must always carry `currentValue: ""`; the real value is + // registered separately via `currentValueService`. const selectedEnvIndex = getSelectedEnvironmentIndex() if (selectedEnvIndex.type === "MY_ENV") { @@ -104,36 +134,72 @@ export function useMockServer() { ) if (existingVariableIndex === -1) { - // Add to existing selected environment + // Add to existing selected environment. The new variable will be + // appended at `env.variables.length` once the dispatch lands. + const newVarIndex = env.variables.length addEnvironmentVariable(selectedEnvIndex.index, { key: "mockUrl", initialValue: mockUrl, - currentValue: mockUrl, + currentValue: "", secret: false, }) + currentValueService.addEnvironmentVariable(env.id, { + key: "mockUrl", + currentValue: mockUrl, + varIndex: newVarIndex, + isSecret: false, + }) toast.success(t("mock_server.environment_variable_added")) } else { - // Update existing mockUrl variable with new value using the store dispatcher + // Update existing mockUrl variable with new value using the + // store dispatcher. Persist initial only; update the current + // value separately via the service (remove + add, since there + // is no explicit update API on the service). updateEnvironmentVariable( selectedEnvIndex.index, existingVariableIndex, { key: "mockUrl", initialValue: mockUrl, - currentValue: mockUrl, + currentValue: "", } ) + currentValueService.removeEnvironmentVariable( + env.id, + existingVariableIndex + ) + currentValueService.addEnvironmentVariable(env.id, { + key: "mockUrl", + currentValue: mockUrl, + varIndex: existingVariableIndex, + isSecret: false, + }) toast.success(t("mock_server.environment_variable_updated")) } } else { - // Create a new environment with the mock URL + // Create a new environment with the mock URL. + // We generate the env ID up front so we can register the current + // value against the same ID without racing the dispatch. const envName = `${collectionName} Environment` - createEnvironment(envName, [ + const envID = uniqueID() + createEnvironment( + envName, + [ + { + key: "mockUrl", + initialValue: mockUrl, + currentValue: "", + secret: false, + }, + ], + envID + ) + currentValueService.addEnvironment(envID, [ { key: "mockUrl", - initialValue: mockUrl, currentValue: mockUrl, - secret: false, + varIndex: 0, + isSecret: false, }, ]) toast.success(t("mock_server.environment_created_with_variable")) @@ -158,24 +224,64 @@ export function useMockServer() { let updatedVariables let successMessage + // Track the varIndex that will hold mockUrl after the update + // so we can register the current value against the right slot. + let mockUrlVarIndex: number + if (existingVariableIndex === -1) { - // Variable doesn't exist, add it + // Variable doesn't exist, append it. Team env variables follow + // the v2 schema ({ key, initialValue, currentValue, secret }). + // `currentValue` must be empty on persist — the real value is + // stored locally via CurrentValueService. + mockUrlVarIndex = existingEnv.environment.variables.length updatedVariables = [ ...existingEnv.environment.variables, - { key: "mockUrl", value: mockUrl }, + { + key: "mockUrl", + initialValue: mockUrl, + currentValue: "", + secret: false, + }, ] successMessage = t("mock_server.environment_variable_added") } else { - // Variable exists, update its value + // Variable exists, bump its initialValue; keep currentValue + // empty on persist and refresh the service entry below. + // + // We rebuild the v2 shape explicitly rather than spreading + // the existing variable — a legacy `{ key, value }` row + // would otherwise leak its `value` field alongside + // `initialValue` / `currentValue` and produce a mixed- + // schema payload. + mockUrlVarIndex = existingVariableIndex updatedVariables = existingEnv.environment.variables.map((v, idx) => - idx === existingVariableIndex ? { ...v, value: mockUrl } : v + idx === existingVariableIndex + ? { + key: "mockUrl", + initialValue: mockUrl, + currentValue: "", + secret: false, + } + : v ) successMessage = t("mock_server.environment_variable_updated") } + // Normalize every entry before persisting. Other variables + // in this list may still be legacy `{ key, value }` rows + // because `TeamEnvironmentAdapter` subscribes via raw + // `JSON.parse` without running the translator — if we just + // stringified `updatedVariables` as-is we could send a + // mixed-schema payload back to the backend. Running each + // row through `translateToNewEnvironmentVariables` guarantees + // all entries are in the v2 shape. + const normalizedVariables = updatedVariables.map( + translateToNewEnvironmentVariables + ) + await pipe( updateTeamEnvironment( - JSON.stringify(updatedVariables), + JSON.stringify(normalizedVariables), existingEnv.id, existingEnv.environment.name ), @@ -185,14 +291,36 @@ export function useMockServer() { toast.error(t("error.something_went_wrong")) }, () => { + // Persist succeeded — now register the real current value + // against the team env's ID. Remove any stale entry at the + // same slot first (no explicit update API on the service). + currentValueService.removeEnvironmentVariable( + existingEnv.id, + mockUrlVarIndex + ) + currentValueService.addEnvironmentVariable(existingEnv.id, { + key: "mockUrl", + currentValue: mockUrl, + varIndex: mockUrlVarIndex, + isSecret: false, + }) toast.success(successMessage) } ) )() } else { - // Create new team environment + // Create new team environment. Variables go out with an empty + // currentValue; the real value is registered locally against + // the server-assigned env ID once the mutation returns. const envName = `${collectionName} Environment` - const variables = [{ key: "mockUrl", value: mockUrl }] + const variables = [ + { + key: "mockUrl", + initialValue: mockUrl, + currentValue: "", + secret: false, + }, + ] await pipe( createTeamEnvironment(JSON.stringify(variables), teamID, envName), @@ -201,7 +329,18 @@ export function useMockServer() { console.error("Failed to create team environment:", error) toast.error(t("error.something_went_wrong")) }, - () => { + (result) => { + const newEnvID = result.createTeamEnvironment.id + if (newEnvID) { + currentValueService.addEnvironment(newEnvID, [ + { + key: "mockUrl", + currentValue: mockUrl, + varIndex: 0, + isSecret: false, + }, + ]) + } toast.success(t("mock_server.environment_created_with_variable")) } ) @@ -284,10 +423,12 @@ export function useMockServer() { return { success: false, server: null } } - // Add mock URL to environment if enabled + // Add mock URL to environment if enabled. + // Always prefer `serverUrlDomainBased`; fall back to + // `serverUrlPathBased` when the backend has no wildcard domain + // configured and the subdomain URL comes back null. if (setInEnvironment) { - const mockUrl = - result.serverUrlPathBased || result.serverUrlDomainBased || "" + const mockUrl = pickMockUrl(result) if (mockUrl) { await addMockUrlToEnvironment(mockUrl, collectionName) } diff --git a/packages/hoppscotch-common/src/helpers/RequestRunner.ts b/packages/hoppscotch-common/src/helpers/RequestRunner.ts index 52e223c9909..299d2f832f9 100644 --- a/packages/hoppscotch-common/src/helpers/RequestRunner.ts +++ b/packages/hoppscotch-common/src/helpers/RequestRunner.ts @@ -27,7 +27,7 @@ import { map } from "fp-ts/Either" import { runPreRequestScript, runTestScript } from "@hoppscotch/js-sandbox/web" import { useSetting } from "~/composables/settings" import { getService } from "~/modules/dioc" -import { stripModulePrefix } from "~/helpers/scripting" +import { combineScriptsWithIIFE, hasActualScript } from "~/helpers/scripting" import { createHoppFetchHook } from "~/helpers/hopp-fetch" import { KernelInterceptorService } from "~/services/kernel-interceptor.service" import { @@ -364,14 +364,21 @@ const delegatePreRequestScriptRunner = ( selected: Environment["variables"] temp: Environment["variables"] }, - cookies: Cookie[] | null + cookies: Cookie[] | null, + inheritedPreRequestScripts: string[] = [] ): Promise> => { const { preRequestScript } = request + const experimentalScriptingSandbox = EXPERIMENTAL_SCRIPTING_SANDBOX.value + const target = experimentalScriptingSandbox ? "experimental" : "legacy" - const cleanScript = stripModulePrefix(preRequestScript) + // Pre-request order: root → request. + const combinedScript = combineScriptsWithIIFE( + [...inheritedPreRequestScripts, preRequestScript], + target + ) // Short-circuit empty scripts to avoid unnecessary WASM initialization - if (cleanScript.trim().length === 0) { + if (combinedScript.length === 0) { return Promise.resolve( E.right({ updatedEnvs: envs, @@ -380,19 +387,16 @@ const delegatePreRequestScriptRunner = ( ) } - if (!EXPERIMENTAL_SCRIPTING_SANDBOX.value) { - // Strip `export {};\n` before executing in legacy sandbox to prevent syntax errors - - return runPreRequestScript(cleanScript, { + if (!experimentalScriptingSandbox) { + return runPreRequestScript(combinedScript, { envs, experimentalScriptingSandbox: false, }) } - // Experimental sandbox enabled - use faraday-cage with hook const hoppFetchHook = createHoppFetchHook(kernelInterceptorService) - return runPreRequestScript(cleanScript, { + return runPreRequestScript(combinedScript, { envs, request, cookies, @@ -405,14 +409,21 @@ const runPostRequestScript = ( envs: TestResult["envs"], request: HoppRESTRequest, response: HoppRESTResponse, - cookies: Cookie[] | null + cookies: Cookie[] | null, + inheritedTestScripts: string[] = [] ): Promise> => { const { testScript } = request + const experimentalScriptingSandbox = EXPERIMENTAL_SCRIPTING_SANDBOX.value + const target = experimentalScriptingSandbox ? "experimental" : "legacy" - const cleanScript = stripModulePrefix(testScript) + // Test order: request → root (reverse of pre-request). + const combinedScript = combineScriptsWithIIFE( + [testScript, ...inheritedTestScripts.slice().reverse()], + target + ) // Short-circuit empty scripts to avoid unnecessary WASM initialization - if (cleanScript.trim().length === 0) { + if (combinedScript.length === 0) { return Promise.resolve( E.right({ tests: { descriptor: "root", expectResults: [], children: [] }, @@ -423,20 +434,17 @@ const runPostRequestScript = ( ) } - if (!EXPERIMENTAL_SCRIPTING_SANDBOX.value) { - // Strip `export {};\n` before executing in legacy sandbox to prevent syntax errors - - return runTestScript(cleanScript, { + if (!experimentalScriptingSandbox) { + return runTestScript(combinedScript, { envs, response, experimentalScriptingSandbox: false, }) } - // Experimental sandbox enabled - use faraday-cage with hook const hoppFetchHook = createHoppFetchHook(kernelInterceptorService) - return runTestScript(cleanScript, { + return runTestScript(combinedScript, { envs, request, response, @@ -497,10 +505,20 @@ export function runRESTRequest$( initialEnvsForComparison, } = captureInitialEnvironmentState() + // Extract inherited scripts from collection hierarchy, filtering out empty/module-prefix-only scripts + const inheritedScripts = inheritedProperties?.scripts ?? [] + const inheritedPreRequestScripts = inheritedScripts + .map((s) => s.preRequestScript) + .filter(hasActualScript) + const inheritedTestScripts = inheritedScripts + .map((s) => s.testScript) + .filter(hasActualScript) + const res = delegatePreRequestScriptRunner( resolvedRequest, initialEnvs, - cookieJarEntries + cookieJarEntries, + inheritedPreRequestScripts ).then(async (preRequestScriptResult) => { if (cancelCalled) return E.left("cancellation" as const) @@ -579,7 +597,8 @@ export function runRESTRequest$( statusText: res.statusText, responseTime: res.meta.responseDuration, }, - preRequestScriptResult.right.updatedCookies ?? null + preRequestScriptResult.right.updatedCookies ?? null, + inheritedTestScripts ) if (E.isRight(postRequestScriptResult)) { @@ -795,7 +814,9 @@ export async function runTestRunnerRequest( request: HoppRESTRequest, persistEnv = true, inheritedVariables: HoppCollectionVariable[] = [], - initialEnvironmentState: InitialEnvironmentState + initialEnvironmentState: InitialEnvironmentState, + inheritedPreRequestScripts: string[] = [], + inheritedTestScripts: string[] = [] ): Promise< | E.Left<"script_fail"> | E.Right<{ @@ -824,7 +845,8 @@ export async function runTestRunnerRequest( return delegatePreRequestScriptRunner( request, initialEnvs, - cookieJarEntries + cookieJarEntries, + inheritedPreRequestScripts ).then(async (preRequestScriptResult) => { if (E.isLeft(preRequestScriptResult)) { console.error("[Pre-Request Script Error]", preRequestScriptResult.left) @@ -883,7 +905,8 @@ export async function runTestRunnerRequest( statusText: res.statusText, responseTime: res.meta.responseDuration, }, - preRequestScriptResult.right.updatedCookies ?? null + preRequestScriptResult.right.updatedCookies ?? null, + inheritedTestScripts ) if (E.isRight(postRequestScriptResult)) { diff --git a/packages/hoppscotch-common/src/helpers/__tests__/postman-import.spec.ts b/packages/hoppscotch-common/src/helpers/__tests__/postman-import.spec.ts new file mode 100644 index 00000000000..c1eb3c9ef46 --- /dev/null +++ b/packages/hoppscotch-common/src/helpers/__tests__/postman-import.spec.ts @@ -0,0 +1,60 @@ +import * as E from "fp-ts/Either" +import { describe, expect, it } from "vitest" + +import { hoppPostmanImporter } from "../import-export/import/postman" + +const postmanCollectionWithArrayHeader = JSON.stringify({ + info: { + name: "Array Header Import", + schema: + "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + }, + item: [ + { + name: "Import Array Header", + request: { + method: "GET", + header: [ + { + key: "Authorization", + value: ["Basic xxxxx", "Basic xxxxxxxxxxxx="], + }, + { + key: "Content-Type", + value: "application/x-www-form-urlencoded", + }, + ], + url: "https://echo.hoppscotch.io/get", + }, + }, + ], +}) + +describe("Postman importer", () => { + it("coerces array header values instead of crashing during import", async () => { + const result = await hoppPostmanImporter([ + postmanCollectionWithArrayHeader, + ])() + + expect(E.isRight(result)).toBe(true) + + if (E.isLeft(result)) { + throw new Error("Expected Postman import to succeed") + } + + expect(result.right[0].requests[0].headers).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + key: "Authorization", + value: "Basic xxxxx,Basic xxxxxxxxxxxx=", + active: true, + }), + expect.objectContaining({ + key: "Content-Type", + value: "application/x-www-form-urlencoded", + active: true, + }), + ]) + ) + }) +}) diff --git a/packages/hoppscotch-common/src/helpers/backend/helpers.ts b/packages/hoppscotch-common/src/helpers/backend/helpers.ts index a7a2848e3f0..e75312c8439 100644 --- a/packages/hoppscotch-common/src/helpers/backend/helpers.ts +++ b/packages/hoppscotch-common/src/helpers/backend/helpers.ts @@ -40,6 +40,8 @@ export type CollectionDataProps = { headers: HoppRESTHeaders variables: HoppCollectionVariable[] description: string | null + preRequestScript: string + testScript: string } export const BACKEND_PAGE_SIZE = 10 @@ -121,6 +123,8 @@ const parseCollectionData = ( headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", } if (!data) { @@ -159,11 +163,23 @@ const parseCollectionData = ( ? parsedData.description : defaultDataProps.description + const preRequestScript = + typeof parsedData?.preRequestScript === "string" + ? parsedData.preRequestScript + : defaultDataProps.preRequestScript + + const testScript = + typeof parsedData?.testScript === "string" + ? parsedData.testScript + : defaultDataProps.testScript + return { auth, headers, variables, description, + preRequestScript, + testScript, } } @@ -171,9 +187,14 @@ const parseCollectionData = ( export const teamCollectionJSONToHoppRESTColl = ( coll: TeamCollectionJSON ): HoppCollection => { - const { auth, headers, variables, description } = parseCollectionData( - coll.data - ) + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = parseCollectionData(coll.data) return makeCollection({ id: coll.id, @@ -184,6 +205,8 @@ export const teamCollectionJSONToHoppRESTColl = ( headers, variables, description, + preRequestScript, + testScript, }) } @@ -247,7 +270,14 @@ export const teamCollToHoppRESTColl = ( description: null, } - const { auth, headers, variables, description } = parseCollectionData(data) + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = parseCollectionData(data) return makeCollection({ id: coll.id, @@ -258,6 +288,8 @@ export const teamCollToHoppRESTColl = ( headers: headers ?? [], variables: variables ?? [], description: description ?? null, + preRequestScript: preRequestScript ?? "", + testScript: testScript ?? "", }) } diff --git a/packages/hoppscotch-common/src/helpers/backend/queries/PublishedDocs.ts b/packages/hoppscotch-common/src/helpers/backend/queries/PublishedDocs.ts index 05b73ac3780..806ef75cfc8 100644 --- a/packages/hoppscotch-common/src/helpers/backend/queries/PublishedDocs.ts +++ b/packages/hoppscotch-common/src/helpers/backend/queries/PublishedDocs.ts @@ -98,6 +98,8 @@ function parseCollectionDataFromString(data?: string): CollectionDataProps { headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", } if (!data) { @@ -111,6 +113,9 @@ function parseCollectionDataFromString(data?: string): CollectionDataProps { headers: parsed.headers || defaultDataProps.headers, variables: parsed.variables || defaultDataProps.variables, description: parsed.description || defaultDataProps.description, + preRequestScript: + parsed.preRequestScript || defaultDataProps.preRequestScript, + testScript: parsed.testScript || defaultDataProps.testScript, } } catch (error) { console.error("Failed to parse collection data:", error) @@ -127,8 +132,14 @@ export function collectionFolderToHoppCollection( folder: CollectionFolder ): HoppCollection { // Parse the data field to extract auth, headers, variables, and description - const { auth, headers, variables, description } = - parseCollectionDataFromString(folder.data) + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = parseCollectionDataFromString(folder.data) return makeCollection({ name: folder.name, @@ -139,6 +150,8 @@ export function collectionFolderToHoppCollection( variables, description, id: folder.id, + preRequestScript: preRequestScript ?? "", + testScript: testScript ?? "", }) } diff --git a/packages/hoppscotch-common/src/helpers/collection/collection.ts b/packages/hoppscotch-common/src/helpers/collection/collection.ts index 58aa4abf3fb..f56c656ced9 100644 --- a/packages/hoppscotch-common/src/helpers/collection/collection.ts +++ b/packages/hoppscotch-common/src/helpers/collection/collection.ts @@ -311,6 +311,8 @@ export function transformCollectionForImport( headers: collection.headers, variables: collection.variables, description: collection.description, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const obj: CollectionFolder = { diff --git a/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts b/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts index 4b3e1df202f..23564fd293e 100644 --- a/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts +++ b/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts @@ -42,6 +42,7 @@ import { HOPP_ENVIRONMENT_REGEX, } from "~/helpers/environment-regex" import { + stabilizeTooltipHover, constrainTooltipToViewport, createTooltipValueRow, } from "~/helpers/utils/tooltip" @@ -313,6 +314,9 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) => // Apply viewport-aware overflow constraints to the tooltip constrainTooltipToViewport(dom, tooltipContainer) + // Apply an interactive bridge to stabilize hover transitions + stabilizeTooltipHover(dom) + return { dom } }, } diff --git a/packages/hoppscotch-common/src/helpers/editor/extensions/HoppPredefinedVariables.ts b/packages/hoppscotch-common/src/helpers/editor/extensions/HoppPredefinedVariables.ts index dc3c004804b..4a20280a154 100644 --- a/packages/hoppscotch-common/src/helpers/editor/extensions/HoppPredefinedVariables.ts +++ b/packages/hoppscotch-common/src/helpers/editor/extensions/HoppPredefinedVariables.ts @@ -10,6 +10,7 @@ import { HOPP_SUPPORTED_PREDEFINED_VARIABLES } from "@hoppscotch/data" import IconSquareAsterisk from "~icons/lucide/square-asterisk?raw" import { isComment } from "./helpers" import { + stabilizeTooltipHover, constrainTooltipToViewport, truncateText, } from "~/helpers/utils/tooltip" @@ -146,6 +147,9 @@ const cursorTooltipField = () => // Apply viewport-aware overflow constraints constrainTooltipToViewport(dom, tooltipContainer) + // Apply an interactive bridge to stabilize hover transitions + stabilizeTooltipHover(dom) + return { dom } }, } diff --git a/packages/hoppscotch-common/src/helpers/import-export/import/har.ts b/packages/hoppscotch-common/src/helpers/import-export/import/har.ts index ec9378777ee..3ca073b0ca4 100644 --- a/packages/hoppscotch-common/src/helpers/import-export/import/har.ts +++ b/packages/hoppscotch-common/src/helpers/import-export/import/har.ts @@ -39,6 +39,8 @@ export const harImporter = ( headers: [], description: null, variables: [], + preRequestScript: "", + testScript: "", }) return E.right([collection]) diff --git a/packages/hoppscotch-common/src/helpers/import-export/import/insomnia/insomniaColl.ts b/packages/hoppscotch-common/src/helpers/import-export/import/insomnia/insomniaColl.ts index 6d1bb907d1e..c2b84b16b5d 100644 --- a/packages/hoppscotch-common/src/helpers/import-export/import/insomnia/insomniaColl.ts +++ b/packages/hoppscotch-common/src/helpers/import-export/import/insomnia/insomniaColl.ts @@ -245,6 +245,8 @@ const getHoppFolder = ( headers: [], variables: getCollectionVariables(undefined, folderRes), // undefined is used to indicate no environment variables for v4 and below description: folderRes.meta?.description ?? null, + preRequestScript: "", + testScript: "", }) const getHoppCollections = (docs: InsomniaDoc[]) => { @@ -283,6 +285,8 @@ const getParsedHoppFolder = ( headers: [], variables: getCollectionVariables(collection.environment), description: collection.meta.description ?? null, + preRequestScript: "", + testScript: "", }) } @@ -323,6 +327,8 @@ const getParsedHoppCollections = (docs: InsomniaDocV5[]): HoppCollection[] => headers: [], variables: getCollectionVariables(doc.environments?.data), description: doc.meta.description ?? null, + preRequestScript: "", + testScript: "", }) } diff --git a/packages/hoppscotch-common/src/helpers/import-export/import/openapi/index.ts b/packages/hoppscotch-common/src/helpers/import-export/import/openapi/index.ts index 7cccec7ec26..001ea7dea74 100644 --- a/packages/hoppscotch-common/src/helpers/import-export/import/openapi/index.ts +++ b/packages/hoppscotch-common/src/helpers/import-export/import/openapi/index.ts @@ -1186,6 +1186,8 @@ const convertOpenApiDocsToHopp = ( auth: { authType: "inherit", authActive: true }, headers: [], variables: [], + preRequestScript: "", + testScript: "", }) ), requests: requestsWithoutTags, @@ -1193,6 +1195,8 @@ const convertOpenApiDocsToHopp = ( headers: [], variables: [], description, + preRequestScript: "", + testScript: "", }) }) diff --git a/packages/hoppscotch-common/src/helpers/import-export/import/postman.ts b/packages/hoppscotch-common/src/helpers/import-export/import/postman.ts index d074363326e..0245eae4226 100644 --- a/packages/hoppscotch-common/src/helpers/import-export/import/postman.ts +++ b/packages/hoppscotch-common/src/helpers/import-export/import/postman.ts @@ -16,7 +16,7 @@ import { HoppCollectionVariable, } from "@hoppscotch/data" import * as A from "fp-ts/Array" -import { flow, pipe } from "fp-ts/function" +import { pipe } from "fp-ts/function" import * as O from "fp-ts/Option" import * as S from "fp-ts/string" import * as TE from "fp-ts/TaskEither" @@ -63,10 +63,10 @@ const getCollectionSchema = (jsonStr: string): string | null => { } } -export const replacePMVarTemplating = flow( - S.replace(/{{\s*/g, "<<"), - S.replace(/\s*}}/g, ">>") -) +export const replacePMVarTemplating = (value: unknown): string => { + const str = typeof value === "string" ? value : String(value ?? "") + return pipe(str, S.replace(/{{\s*/g, "<<"), S.replace(/\s*}}/g, ">>")) +} const PMRawLanguageOptionsToContentTypeMap: Record< PMRawLanguage, @@ -550,6 +550,36 @@ const getHoppScripts = ( return { preRequestScript, testScript } } +/** + * Extracts pre-request and test scripts from a Postman ItemGroup (collection/folder) + * Postman collections and folders can have their own scripts that run before/after all requests + */ +const getHoppCollectionScripts = ( + ig: ItemGroup, + importScripts: boolean +): { preRequestScript: string; testScript: string } => { + if (!importScripts) { + return { preRequestScript: "", testScript: "" } + } + + let preRequestScript = "" + let testScript = "" + + // ItemGroup (collection/folder) stores scripts in the events property + if (ig.events) { + const events = ig.events.all() + events.forEach((event: any) => { + if (event.listen === "prerequest") { + preRequestScript = extractScriptFromEvent(event) + } else if (event.listen === "test") { + testScript = extractScriptFromEvent(event) + } + }) + } + + return { preRequestScript, testScript } +} + const getCollectionDescription = ( docField?: string | DescriptionDefinition ): string | null => { @@ -609,8 +639,13 @@ const getHoppRequest = ( const getHoppFolder = ( ig: ItemGroup, importScripts: boolean -): HoppCollection => - makeCollection({ +): HoppCollection => { + const { preRequestScript, testScript } = getHoppCollectionScripts( + ig, + importScripts + ) + + return makeCollection({ name: ig.name, folders: pipe( ig.items.all(), @@ -626,7 +661,10 @@ const getHoppFolder = ( headers: [], variables: getHoppCollVariables(ig), description: getCollectionDescription(ig.description), + preRequestScript, + testScript, }) +} export const getHoppCollections = ( collections: PMCollection[], diff --git a/packages/hoppscotch-common/src/helpers/mockServer/exampleCollection.ts b/packages/hoppscotch-common/src/helpers/mockServer/exampleCollection.ts index 2a268076130..a69aeef0346 100644 --- a/packages/hoppscotch-common/src/helpers/mockServer/exampleCollection.ts +++ b/packages/hoppscotch-common/src/helpers/mockServer/exampleCollection.ts @@ -323,5 +323,9 @@ export function createExamplePetStoreCollection( authActive: true, }, headers: [], + variables: [], + description: null, + preRequestScript: "", + testScript: "", }) } diff --git a/packages/hoppscotch-common/src/helpers/mockServer/exampleMockCollection.ts b/packages/hoppscotch-common/src/helpers/mockServer/exampleMockCollection.ts index d1a9858660e..a4f85bae16f 100644 --- a/packages/hoppscotch-common/src/helpers/mockServer/exampleMockCollection.ts +++ b/packages/hoppscotch-common/src/helpers/mockServer/exampleMockCollection.ts @@ -328,6 +328,9 @@ export async function createMockCollectionForPersonal( auth: data.auth, headers: data.headers, variables: data.variables, + description: null, + preRequestScript: "", + testScript: "", }) // Add the backend ID to the collection diff --git a/packages/hoppscotch-common/src/helpers/scripting.ts b/packages/hoppscotch-common/src/helpers/scripting.ts index b7cda9fafb2..39b5f4c1120 100644 --- a/packages/hoppscotch-common/src/helpers/scripting.ts +++ b/packages/hoppscotch-common/src/helpers/scripting.ts @@ -9,14 +9,77 @@ export const MODULE_PREFIX = "export {};\n" as const * (non-module context) or when exporting collections. */ export const stripModulePrefix = (script: string): string => { - return script.startsWith(MODULE_PREFIX) - ? script.slice(MODULE_PREFIX.length) - : script + if (script.startsWith(MODULE_PREFIX)) { + return script.slice(MODULE_PREFIX.length) + } + if (script.startsWith("export {};")) { + return script.slice("export {};".length) + } + return script } /** - * Regex for stripping the JSON-serialized module prefix (`export {};\\n`) - * from scripts during collection exports. - * Note: This matches the literal backslash-n (`\\n`), not an actual newline character. + * Anchored to JSON value-opening delimiters so it only matches inside JSON + * string values during collection export, not inside script source. Matches + * both `export {};\\n` and `export {};` (`\\n` is the literal backslash-n + * pair, not a newline). */ -export const MODULE_PREFIX_REGEX_JSON_SERIALIZED = /export \{\};\\n/g +export const MODULE_PREFIX_REGEX_JSON_SERIALIZED = + /(?<=:\s*")export \{\};(?:\\n)?/g + +export type CombineScriptsTarget = "experimental" | "legacy" + +const wrapScript = (script: string, target: CombineScriptsTarget): string => { + const stripped = stripModulePrefix(script.trim()) + if (!stripped) return "" + const asyncKeyword = target === "experimental" ? "async " : "" + return `${asyncKeyword}function() {\n${stripped}\n}` +} + +/** + * Combines inherited scripts into a sequential chain. Each script runs in + * its own function for scope isolation. + * + * - `experimental`: `await (async function(){...})();` lines, evaluated in + * an async host context so each `await` settles before the next runs. + * - `legacy`: sync `(function(){...}).call(this);` lines. Top-level `await` + * is rejected at parse time. + */ +export const combineScriptsWithIIFE = ( + scripts: string[], + target: CombineScriptsTarget = "experimental" +): string => { + const fns = scripts.map((s) => wrapScript(s, target)).filter((s) => s) + if (fns.length === 0) return "" + if (target === "experimental") { + // Wrap the entire awaited chain in try/catch so a top-level throw (or a + // rejected await) surfaces synchronously via the host reporter. + // faraday-cage swallows rejected keepAlive promises and does not await + // afterScriptExecutionHooks, so this is the only reliable channel for + // async-boundary errors to reach the host caller. + // + // The reporter is captured in a const before the try so a user script + // that tampers with `globalThis.__hoppReportScriptExecutionError` + // inside the try body cannot suppress the report. Bootstrap installs + // the property as non-writable and non-configurable for defense in + // depth; the lexical capture makes that redundant but explicit. + const body = fns.map((fn) => `await (${fn})();`).join("\n") + return [ + "const __hoppReporter = globalThis.__hoppReportScriptExecutionError;", + "try {", + body, + "} catch (__hoppScriptExecutionError) {", + " __hoppReporter(__hoppScriptExecutionError);", + "}", + ].join("\n") + } + // Leading `;` guards against ASI: a prior `})` on the host line would + // otherwise be read as a call against our IIFE expression. + return fns.map((fn) => `;(${fn}).call(this);`).join("\n") +} + +// Monaco prepends "export {};\n" to empty scripts — strip before checking. +export const hasActualScript = (script: string | undefined | null): boolean => { + if (!script) return false + return stripModulePrefix(script.trim()).length > 0 +} diff --git a/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts b/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts index b4b4998e5b4..0850fbea532 100644 --- a/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts +++ b/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts @@ -1,12 +1,9 @@ import * as E from "fp-ts/Either" import { BehaviorSubject, Subscription } from "rxjs" -import { - HoppCollectionVariable, - HoppRESTAuth, - HoppRESTHeader, - translateToNewRequest, -} from "@hoppscotch/data" +import { HoppCollectionVariable, translateToNewRequest } from "@hoppscotch/data" import { pull, remove } from "lodash-es" +import { hasActualScript } from "~/helpers/scripting" +import { CollectionDataProps } from "~/helpers/backend/helpers" import { Subscription as WSubscription } from "wonka" import { runGQLQuery, runGQLSubscription } from "../backend/GQLClient" import { TeamCollection } from "./TeamCollection" @@ -1093,14 +1090,16 @@ export default class NewTeamCollectionAdapter { const variables: HoppInheritedProperty["variables"] = [] - if (!folderPath) return { auth, headers, variables } + const scripts: HoppInheritedProperty["scripts"] = [] + + if (!folderPath) return { auth, headers, variables, scripts } const path = folderPath.split("/") // Check if the path is empty or invalid if (!path || path.length === 0) { console.error("Invalid path:", folderPath) - return { auth, headers, variables } + return { auth, headers, variables, scripts } } // Loop through the path and get the last parent folder with authType other than 'inherit' @@ -1110,20 +1109,12 @@ export default class NewTeamCollectionAdapter { // Check if parentFolder is undefined or null if (!parentFolder) { console.error("Parent folder not found for path:", path) - return { auth, headers, variables } + return { auth, headers, variables, scripts } } - const data: { - auth: HoppRESTAuth - headers: HoppRESTHeader[] - variables: HoppCollectionVariable[] - } = parentFolder.data + const data: Partial = parentFolder.data ? JSON.parse(parentFolder.data) - : { - auth: null, - headers: null, - variables: null, - } + : {} if (!data.auth) { data.auth = { @@ -1141,6 +1132,8 @@ export default class NewTeamCollectionAdapter { const parentFolderAuth = data.auth const parentFolderHeaders = data.headers const parentFolderVariables = data.variables + const parentFolderPreRequestScript = data.preRequestScript ?? "" + const parentFolderTestScript = data.testScript ?? "" if ( parentFolderAuth?.authType === "inherit" && @@ -1200,8 +1193,23 @@ export default class NewTeamCollectionAdapter { ), }) } + + // Update scripts + if ( + hasActualScript(parentFolderPreRequestScript) || + hasActualScript(parentFolderTestScript) + ) { + const currentPath = [...path.slice(0, i + 1)].join("/") + + scripts.push({ + parentID: parentFolder.id ?? currentPath, + parentName: parentFolder.title, + preRequestScript: parentFolderPreRequestScript, + testScript: parentFolderTestScript, + }) + } } - return { auth, headers, variables } + return { auth, headers, variables, scripts } } } diff --git a/packages/hoppscotch-common/src/helpers/teams/TeamsSearch.service.ts b/packages/hoppscotch-common/src/helpers/teams/TeamsSearch.service.ts index 4d75a3955ad..d7fa53df851 100644 --- a/packages/hoppscotch-common/src/helpers/teams/TeamsSearch.service.ts +++ b/packages/hoppscotch-common/src/helpers/teams/TeamsSearch.service.ts @@ -1,7 +1,5 @@ import { - HoppCollectionVariable, HoppRESTAuth, - HoppRESTHeader, HoppRESTRequest, getDefaultRESTRequest, } from "@hoppscotch/data" @@ -10,6 +8,7 @@ import { Service } from "dioc" import * as E from "fp-ts/Either" import { Ref, ref } from "vue" import { getSingleCollection, TeamCollection } from "./TeamCollection" +import { hasActualScript } from "~/helpers/scripting" import { platform } from "~/platform" import { HoppInheritedProperty } from "../types/HoppInheritedProperties" @@ -19,6 +18,24 @@ import { TeamRequest, getCollectionChildCollections, } from "./TeamRequest" +import { CollectionDataProps } from "../backend/helpers" + +/** + * Parses collection data that may be double-encoded JSON + * Handles both single and double JSON stringification + */ +const parseCollectionData = (data: string): CollectionDataProps | null => { + try { + let parsed = JSON.parse(data) + // Handle double-encoded JSON (string containing JSON string) + if (typeof parsed === "string") { + parsed = JSON.parse(parsed) + } + return parsed as CollectionDataProps + } catch { + return null + } +} type CollectionSearchMeta = { isSearchResult?: boolean @@ -354,6 +371,8 @@ export class TeamSearchService extends Service { const defaultInheritedVariables: HoppInheritedProperty["variables"] = [] + const defaultInheritedScripts: HoppInheritedProperty["scripts"] = [] + const collection = Object.values(this.searchResultsCollections).find( (col) => col.id === collectionID ) @@ -363,12 +382,14 @@ export class TeamSearchService extends Service { auth: defaultInheritedAuth, headers: defaultInheritedHeaders, variables: defaultInheritedVariables, + scripts: defaultInheritedScripts, } const inheritedAuthData = this.findInheritableParentAuth(collectionID) const inheritedHeadersData = this.findInheritableParentHeaders(collectionID) const inheritedVariablesData = this.findInheritableParentVariables(collectionID) + const inheritedScriptsData = this.findInheritableParentScripts(collectionID) return { auth: E.isRight(inheritedAuthData) @@ -380,6 +401,9 @@ export class TeamSearchService extends Service { variables: E.isRight(inheritedVariablesData) ? Object.values(inheritedVariablesData.right) : defaultInheritedVariables, + scripts: E.isRight(inheritedScriptsData) + ? Object.values(inheritedScriptsData.right) + : defaultInheritedScripts, } } @@ -403,13 +427,9 @@ export class TeamSearchService extends Service { // has inherited data if (collection.data) { - const parentInheritedData = JSON.parse(collection.data) as { - auth?: HoppRESTAuth - headers?: HoppRESTHeader[] - variables?: HoppCollectionVariable[] - } + const parentInheritedData = parseCollectionData(collection.data) - const inheritedAuth = parentInheritedData.auth + const inheritedAuth = parentInheritedData?.auth if (inheritedAuth && inheritedAuth.authType !== "inherit") { return E.right({ @@ -447,13 +467,9 @@ export class TeamSearchService extends Service { // see if it has headers to inherit, if yes, add it to the existing headers if (collection.data) { - const parentInheritedData = JSON.parse(collection.data) as { - auth?: HoppRESTAuth - headers?: HoppRESTHeader[] - variables?: HoppCollectionVariable[] - } + const parentInheritedData = parseCollectionData(collection.data) - const inheritedHeaders = parentInheritedData.headers + const inheritedHeaders = parentInheritedData?.headers if (inheritedHeaders) { inheritedHeaders.forEach((header) => { @@ -493,13 +509,9 @@ export class TeamSearchService extends Service { } if (collection.data) { - const parentData = JSON.parse(collection.data) as { - auth?: HoppRESTAuth - headers?: HoppRESTHeader[] - variables?: HoppCollectionVariable[] - } + const parentData = parseCollectionData(collection.data) - const variables = parentData.variables + const variables = parentData?.variables if (variables) { vars.push({ @@ -517,6 +529,51 @@ export class TeamSearchService extends Service { return E.right(vars) } + findInheritableParentScripts = ( + collectionID: string, + existingScripts: HoppInheritedProperty["scripts"] = [] + ): E.Either => { + const collection = Object.values(this.searchResultsCollections).find( + (col) => col.id === collectionID + ) + + if (!collection) { + return E.left("PARENT_NOT_FOUND" as const) + } + + // Recurse to parent first to build root→parent→child order + let scripts = [...existingScripts] + if (collection.parentID) { + const parentResult = this.findInheritableParentScripts( + collection.parentID, + scripts + ) + if (E.isLeft(parentResult)) { + return parentResult + } + scripts = parentResult.right + } + + // Then add current collection's scripts + if (collection.data) { + const parentData = parseCollectionData(collection.data) + + const preRequestScript = parentData?.preRequestScript ?? "" + const testScript = parentData?.testScript ?? "" + + if (hasActualScript(preRequestScript) || hasActualScript(testScript)) { + scripts.push({ + parentID: collection.id, + parentName: collection.title, + preRequestScript, + testScript, + }) + } + } + + return E.right(scripts) + } + expandCollection = async (collectionID: string) => { if (this.expandingCollections.value.includes(collectionID)) return diff --git a/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts b/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts index 05609b43f94..bfb986ac63b 100644 --- a/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts +++ b/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts @@ -23,4 +23,10 @@ export type HoppInheritedProperty = { parentName: string inheritedVariables: HoppCollectionVariable[] }[] + scripts: { + parentID: string + parentName: string + preRequestScript: string + testScript: string + }[] } diff --git a/packages/hoppscotch-common/src/helpers/utils/__tests__/tooltip.spec.ts b/packages/hoppscotch-common/src/helpers/utils/__tests__/tooltip.spec.ts index 6e3b01798d1..596459a5ae0 100644 --- a/packages/hoppscotch-common/src/helpers/utils/__tests__/tooltip.spec.ts +++ b/packages/hoppscotch-common/src/helpers/utils/__tests__/tooltip.spec.ts @@ -6,6 +6,7 @@ import { applyTooltipOverflowStyles, createTooltipValueRow, constrainTooltipToViewport, + stabilizeTooltipHover, TOOLTIP_MAX_VALUE_LENGTH, TOOLTIP_MAX_HEIGHT_PX, TOOLTIP_MAX_WIDTH_PX, @@ -374,6 +375,24 @@ describe("constrainTooltipToViewport", () => { }) }) +// ─── stabilizeTooltipHover ─────────────────────────────────────── + +describe("stabilizeTooltipHover", () => { + test("adds 'hopp-tooltip-interactive-wrapper' class to element", () => { + const el = document.createElement("div") + stabilizeTooltipHover(el) + expect(el.classList.contains("hopp-tooltip-interactive-wrapper")).toBe(true) + }) + + test("does not remove existing classes", () => { + const el = document.createElement("div") + el.className = "existing-class" + stabilizeTooltipHover(el) + expect(el.className).toContain("existing-class") + expect(el.className).toContain("hopp-tooltip-interactive-wrapper") + }) +}) + // ─── Constants ─────────────────────────────────────────────────── describe("Tooltip Constants", () => { diff --git a/packages/hoppscotch-common/src/helpers/utils/tooltip.ts b/packages/hoppscotch-common/src/helpers/utils/tooltip.ts index 97698d88d9e..9c760582374 100644 --- a/packages/hoppscotch-common/src/helpers/utils/tooltip.ts +++ b/packages/hoppscotch-common/src/helpers/utils/tooltip.ts @@ -195,3 +195,14 @@ export function constrainTooltipToViewport( tooltipContent.style.overflow = "hidden" tooltipContent.style.boxSizing = "border-box" } + +/** + * Standardized helper to stabilize interactive tooltips in CodeMirror. + * Adds a CSS-based bridge to extend the hover area, allowing the user + * to move the cursor into the tooltip without it closing. + * + * @param dom - The outer tooltip container element (.tippy-box) + */ +export function stabilizeTooltipHover(dom: HTMLElement): void { + dom.classList.add("hopp-tooltip-interactive-wrapper") +} diff --git a/packages/hoppscotch-common/src/kernel/store.ts b/packages/hoppscotch-common/src/kernel/store.ts index 57b49ec5939..eced46a0678 100644 --- a/packages/hoppscotch-common/src/kernel/store.ts +++ b/packages/hoppscotch-common/src/kernel/store.ts @@ -25,21 +25,29 @@ import { diag } from "./log" // a beforeEach guard in modules/router.ts, and survives full-page reloads // because Tauri sets it on the initial webview URL const orgParam = new URLSearchParams(window.location.search).get("org") -const STORE_PATH = orgParam +const HOST_SCOPED_STORE_PATH = orgParam ? `${orgParam.replace(/[^a-zA-Z0-9]/g, "_")}.hoppscotch.store` : `${window.location.host}.hoppscotch.store` +// process-wide store file shared across orgs. holds machine-level state +// (desktop settings, recent-instances list, update state) that should +// not vary per organization. file name matches the path each shell's +// own `kernel/store.ts` wrapper writes to and the path +// `DesktopPersistenceService` uses on the Tauri side, so common +// composables that bind here read/write the same physical file the +// shell does. +const UNIFIED_STORE_PATH = "hoppscotch-unified.store" + diag("store", "--- COMMON store.ts module evaluated ---") diag("store", "orgParam:", orgParam ?? "(none)") -diag("store", "STORE_PATH:", STORE_PATH) +diag("store", "HOST_SCOPED_STORE_PATH:", HOST_SCOPED_STORE_PATH) +diag("store", "UNIFIED_STORE_PATH:", UNIFIED_STORE_PATH) diag("store", "window.location.host:", window.location.host) diag("store", "window.location.href:", window.location.href) -let cachedStorePath: string | undefined - -// These are only defined functions if in desktop mode. -// For more context, take a look at how `hoppscotch-kernel/.../store/v1/` works -// and how the `web` mode store kernel ignores the first file directory input. +// Lazy-loaded Tauri APIs. Module-scoped so every scoped store shares +// the init step and the loaded modules. Web mode never resolves these +// because `isInitd` returns early outside desktop. let invoke: | ((cmd: string, args?: Record) => Promise) | undefined @@ -102,40 +110,56 @@ export const getLogsDir = async (): Promise => { return await invoke("get_logs_dir") } -const getStorePath = async (): Promise => { - if (cachedStorePath) { - diag("store", "getStorePath: returning cached:", cachedStorePath) - return cachedStorePath - } +// Factory for a Store wrapper bound to a specific store file. Each +// instance keeps its own resolved-path cache so two scoped stores +// never alias their absolute paths. Tauri-API loading and kernel +// module access are module-scoped above, so the factory only +// handles the per-store concerns. +function createScopedStore(staticPath: string) { + let cachedStorePath: string | undefined - if (getKernelMode() === "desktop") { - await isInitd() - if (join) { - try { - const storeDir = await getStoreDir() - cachedStorePath = await join(storeDir, STORE_PATH) - diag( - "store", - "getStorePath: resolved desktop path:", - cachedStorePath, - "(STORE_PATH:", - STORE_PATH, - ")" - ) - return cachedStorePath - } catch (error) { - diag("store", "getStorePath: failed to get store dir:", String(error)) - console.error("Failed to get store directory:", error) + const getStorePath = async (): Promise => { + if (cachedStorePath) { + diag( + "store", + `getStorePath(${staticPath}): returning cached:`, + cachedStorePath + ) + return cachedStorePath + } + + if (getKernelMode() === "desktop") { + await isInitd() + if (join) { + try { + const storeDir = await getStoreDir() + cachedStorePath = await join(storeDir, staticPath) + diag( + "store", + `getStorePath(${staticPath}): resolved desktop path:`, + cachedStorePath + ) + return cachedStorePath + } catch (error) { + diag( + "store", + `getStorePath(${staticPath}): failed to get store dir:`, + String(error) + ) + console.error("Failed to get store directory:", error) + } } } - } - cachedStorePath = STORE_PATH - diag("store", "getStorePath: using fallback STORE_PATH:", cachedStorePath) - return cachedStorePath -} + cachedStorePath = staticPath + diag( + "store", + `getStorePath(${staticPath}): using fallback path:`, + cachedStorePath + ) + return cachedStorePath + } -export const Store = (() => { const module = () => getModule("store") return { @@ -143,9 +167,9 @@ export const Store = (() => { init: async () => { const storePath = await getStorePath() - diag("store", "Store.init() called with path:", storePath) + diag("store", `Store.init(${staticPath}) called with path:`, storePath) const result = await module().init(storePath) - diag("store", "Store.init() completed for path:", storePath) + diag("store", `Store.init(${staticPath}) completed for path:`, storePath) return result }, @@ -156,7 +180,11 @@ export const Store = (() => { options?: StorageOptions ): Promise> => { const storePath = await getStorePath() - diag("store", `Store.set(${namespace}, ${key}) on path:`, storePath) + diag( + "store", + `Store.set(${namespace}, ${key}) on ${staticPath}:`, + storePath + ) return module().set(storePath, namespace, key, value, options) }, @@ -165,7 +193,11 @@ export const Store = (() => { key: string ): Promise> => { const storePath = await getStorePath() - diag("store", `Store.get(${namespace}, ${key}) on path:`, storePath) + diag( + "store", + `Store.get(${namespace}, ${key}) on ${staticPath}:`, + storePath + ) const result = await module().get(storePath, namespace, key) if (E.isRight(result)) { const val = result.right @@ -177,9 +209,16 @@ export const Store = (() => { : typeof val === "object" ? `object(${Object.keys(val as Record).length} keys)` : typeof val - diag("store", `Store.get(${namespace}, ${key}) => Right(${shape})`) + diag( + "store", + `Store.get(${namespace}, ${key}) on ${staticPath} => Right(${shape})` + ) } else { - diag("store", `Store.get(${namespace}, ${key}) => Left:`, result.left) + diag( + "store", + `Store.get(${namespace}, ${key}) on ${staticPath} => Left:`, + result.left + ) } return result }, @@ -230,4 +269,16 @@ export const Store = (() => { return extendStore(module(), storePath, namespace) }, } as const -})() +} + +// Org-scoped store. Holds per-org state (auth tokens, collections, +// environments, settings that vary by organization). Default Store +// for almost every consumer in common. +export const Store = createScopedStore(HOST_SCOPED_STORE_PATH) + +// Process-wide store shared across orgs. Holds machine-level state +// like desktop settings, the recent-instances list, and update state. +// Use this for anything that should persist regardless of which org +// the user is viewing, and for state that the desktop shell also +// reads or writes through its own kernel/store wrapper. +export const UnifiedStore = createScopedStore(UNIFIED_STORE_PATH) diff --git a/packages/hoppscotch-common/src/newstore/collections.ts b/packages/hoppscotch-common/src/newstore/collections.ts index ddbf795a303..f33567a78b7 100644 --- a/packages/hoppscotch-common/src/newstore/collections.ts +++ b/packages/hoppscotch-common/src/newstore/collections.ts @@ -11,6 +11,7 @@ import { GQLHeader, } from "@hoppscotch/data" import { cloneDeep } from "lodash-es" +import { hasActualScript } from "~/helpers/scripting" import { pluck } from "rxjs/operators" import { resolveSaveContextOnRequestReorder } from "~/helpers/collection/request" import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" @@ -38,6 +39,8 @@ const defaultRESTCollectionState = { headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }), ], } @@ -55,6 +58,8 @@ const defaultGraphqlCollectionState = { headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }), ], } @@ -142,14 +147,16 @@ export function cascadeParentCollectionForProperties( const variables: HoppInheritedProperty["variables"] = [] - if (!folderPath) return { auth, headers, variables } + const scripts: HoppInheritedProperty["scripts"] = [] + + if (!folderPath) return { auth, headers, variables, scripts } const path = folderPath.split("/").map((i) => parseInt(i)) // Check if the path is empty or invalid if (!path || path.length === 0) { console.error("Invalid path:", folderPath) - return { auth, headers, variables } + return { auth, headers, variables, scripts } } // Loop through the path and get the last parent folder with authType other than 'inherit' @@ -162,7 +169,7 @@ export function cascadeParentCollectionForProperties( // Check if parentFolder is undefined or null if (!parentFolder) { console.error("Parent folder not found for path:", path) - return { auth, headers, variables } + return { auth, headers, variables, scripts } } const parentFolderAuth = parentFolder.auth as HoppRESTAuth | HoppGQLAuth @@ -223,9 +230,27 @@ export function cascadeParentCollectionForProperties( ), }) } + + // Collect scripts from the collection hierarchy (root to child order) + const parentPreRequestScript = parentFolder.preRequestScript ?? "" + const parentTestScript = parentFolder.testScript ?? "" + + if ( + hasActualScript(parentPreRequestScript) || + hasActualScript(parentTestScript) + ) { + const currentPath = [...path.slice(0, i + 1)].join("/") + + scripts.push({ + parentID: parentFolder._ref_id ?? parentFolder.id ?? currentPath, + parentName: parentFolder.name, + preRequestScript: parentPreRequestScript, + testScript: parentTestScript, + }) + } } - return { auth, headers, variables } + return { auth, headers, variables, scripts } } function reorderItems(array: unknown[], from: number, to: number) { @@ -365,6 +390,8 @@ const restCollectionDispatchers = defineDispatchers({ headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }) const newState = state @@ -1026,6 +1053,8 @@ const gqlCollectionDispatchers = defineDispatchers({ headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", }) const newState = state const indexPaths = path.split("/").map((x) => parseInt(x)) @@ -1367,18 +1396,26 @@ export function getRESTCollection(collectionIndex: number) { return restCollectionStore.value.state[collectionIndex] } +export type RESTCollectionInheritedProps = { + auth: HoppRESTAuth + headers: HoppRESTHeaders + variables: HoppCollectionVariable[] + // Ancestor scripts for partial-scope runs (root → target's parent). + // Empty when running from the topmost collection. + ancestorPreRequestScripts: string[] + ancestorTestScripts: string[] +} + function computeCollectionInheritedProps( collection: HoppCollection, ref_id: string, type: "my-collections" | "team-collections" = "my-collections", parentAuth: HoppRESTAuth | null = null, parentHeaders: HoppRESTHeaders | null = null, - parentVariables: HoppCollectionVariable[] | null = null -): { - auth: HoppRESTAuth - headers: HoppRESTHeaders - variables: HoppCollectionVariable[] -} | null { + parentVariables: HoppCollectionVariable[] | null = null, + parentPreRequestScripts: string[] = [], + parentTestScripts: string[] = [] +): RESTCollectionInheritedProps | null { // Determine the inherited authentication and headers const inheritedAuth = collection.auth?.authType === "inherit" && collection.auth.authActive @@ -1406,9 +1443,19 @@ function computeCollectionInheritedProps( auth: inheritedAuth, headers: inheritedHeaders, variables: inheritedVariables, + ancestorPreRequestScripts: parentPreRequestScripts, + ancestorTestScripts: parentTestScripts, } } + // Append this collection's scripts before descending so children see them. + const nextPreRequestScripts = hasActualScript(collection.preRequestScript) + ? [...parentPreRequestScripts, collection.preRequestScript] + : parentPreRequestScripts + const nextTestScripts = hasActualScript(collection.testScript) + ? [...parentTestScripts, collection.testScript] + : parentTestScripts + // Recursively search in folders for (const folder of collection.folders) { const result = computeCollectionInheritedProps( @@ -1417,7 +1464,9 @@ function computeCollectionInheritedProps( type, inheritedAuth, inheritedHeaders, - inheritedVariables + inheritedVariables, + nextPreRequestScripts, + nextTestScripts ) if (result) return result // Return as soon as a match is found } @@ -1429,11 +1478,7 @@ export function getRESTCollectionInheritedProps( collectionID: string, collections: HoppCollection[] = restCollectionStore.value.state, type: "my-collections" | "team-collections" = "my-collections" -): { - auth: HoppRESTAuth - headers: HoppRESTHeaders - variables: HoppCollectionVariable[] -} | null { +): RESTCollectionInheritedProps | null { for (const collection of collections) { const result = computeCollectionInheritedProps( collection, diff --git a/packages/hoppscotch-common/src/newstore/history.ts b/packages/hoppscotch-common/src/newstore/history.ts index 8b3dc390921..3f3fcfc7cb1 100644 --- a/packages/hoppscotch-common/src/newstore/history.ts +++ b/packages/hoppscotch-common/src/newstore/history.ts @@ -106,6 +106,18 @@ export function translateToNewGQLHistory(x: any): GQLHistoryEntry { return obj } +// Decodes a JSON-stringified wire value back to a string. Returns the +// raw value if parsing yields a non-string (object, array, etc.) so +// callers always receive a string per the GQLHistoryEntry contract. +export const decodeGQLHistoryResponse = (value: string): string => { + try { + const parsed = JSON.parse(value) + return typeof parsed === "string" ? parsed : value + } catch { + return value + } +} + export const defaultRESTHistoryState = { state: [] as RESTHistoryEntry[], } diff --git a/packages/hoppscotch-common/src/newstore/settings.ts b/packages/hoppscotch-common/src/newstore/settings.ts index bdfa445823e..cb05f924a56 100644 --- a/packages/hoppscotch-common/src/newstore/settings.ts +++ b/packages/hoppscotch-common/src/newstore/settings.ts @@ -3,7 +3,7 @@ import { Observable } from "rxjs" import { distinctUntilChanged, pluck } from "rxjs/operators" import type { KeysMatching } from "~/types/ts-utils" import DispatchingStore, { defineDispatchers } from "./DispatchingStore" -import { DEFAULT_HOPP_PROXY_URL, getDefaultProxyUrl } from "~/helpers/proxyUrl" +import { DEFAULT_HOPP_PROXY_URL } from "~/helpers/proxyUrl" export const HoppBgColors = ["system", "light", "dark", "black"] as const @@ -87,12 +87,6 @@ export type SettingsDef = { ENABLE_EXPERIMENTAL_DOCUMENTATION: boolean } -let defaultProxyURL = DEFAULT_HOPP_PROXY_URL - -getDefaultProxyUrl().then((url) => { - defaultProxyURL = url -}) - export const getDefaultSettings = (): SettingsDef => { return { syncCollections: true, @@ -122,8 +116,10 @@ export const getDefaultSettings = (): SettingsDef => { // Set empty because interceptor module will set the default value CURRENT_KERNEL_INTERCEPTOR_ID: "", - // TODO: Interceptor related settings should move under the interceptor systems - PROXY_URL: defaultProxyURL, + // Static fallback, the actual platform-aware proxy URL is managed by + // `KernelInterceptorProxyStore` which resolves it at runtime via + // `getDefaultProxyUrl()` (after the platform is initialised). + PROXY_URL: DEFAULT_HOPP_PROXY_URL, URL_EXCLUDES: { auth: true, httpUser: true, diff --git a/packages/hoppscotch-common/src/pages/enter.vue b/packages/hoppscotch-common/src/pages/enter.vue index 489d39b1189..9d476951f13 100644 --- a/packages/hoppscotch-common/src/pages/enter.vue +++ b/packages/hoppscotch-common/src/pages/enter.vue @@ -33,12 +33,13 @@ export default defineComponent({ async mounted() { const { redirect, ...queryParams } = this.route.query - // Org subdomain magic-link flow: redirect back to the originating subdomain - if ( - platform.organization && - !platform.organization.isDefaultCloudInstance && - typeof redirect === "string" - ) { + // Firebase delivers magic links to the default cloud instance + // (e.g. hoppscotch.io) `/enter` route because `continueUrl` must + // point there for trust-domain verification. Org-subdomain + // (e.g. subdomain.hoppscotch.io) logins redirect back to the + // originating subdomain; `getSafeRedirectUrl()` restricts the + // target to the default cloud instance domain and its subdomains. + if (platform.organization && typeof redirect === "string") { const redirectTarget = getSafeRedirectUrl( redirect, platform.organization.getRootDomain() diff --git a/packages/hoppscotch-common/src/pages/view/_id/_version.vue b/packages/hoppscotch-common/src/pages/view/_id/_version.vue index 04a8f3204c7..cb6aa9441ea 100644 --- a/packages/hoppscotch-common/src/pages/view/_id/_version.vue +++ b/packages/hoppscotch-common/src/pages/view/_id/_version.vue @@ -53,6 +53,7 @@ import { translateToNewEnvironmentVariables, } from "@hoppscotch/data" import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" +import { hasActualScript } from "~/helpers/scripting" import { PublishedDocREST, PublishedDocsVersion, @@ -151,6 +152,23 @@ const flattenCollection = ( })), }, ], + scripts: [ + ...(inheritedProperties?.scripts || []), + ...(hasActualScript(collection.preRequestScript) || + hasActualScript(collection.testScript) + ? [ + { + parentID: + collection.id || + collection._ref_id || + `collection-${collection.name}`, + parentName: collection.name, + preRequestScript: collection.preRequestScript || "", + testScript: collection.testScript || "", + }, + ] + : []), + ], } if (collection.folders && collection.folders.length > 0) { diff --git a/packages/hoppscotch-common/src/platform/auth.ts b/packages/hoppscotch-common/src/platform/auth.ts index 152ba63fe71..585afb76f79 100644 --- a/packages/hoppscotch-common/src/platform/auth.ts +++ b/packages/hoppscotch-common/src/platform/auth.ts @@ -38,6 +38,7 @@ export type AuthEvent = | { event: "probable_login"; user: HoppUser } // We have previous login state, but the app is waiting for authentication | { event: "login"; user: HoppUser } // We are authenticated | { event: "logout" } // No authentication and we have no previous state + | { event: "token_refresh"; user: HoppUser } // We have refreshed our tokens and have new ones now export type GithubSignInResult = | { type: "success"; user: HoppUser } // The authentication was a success diff --git a/packages/hoppscotch-common/src/platform/desktop-settings.ts b/packages/hoppscotch-common/src/platform/desktop-settings.ts new file mode 100644 index 00000000000..696a86a4c39 --- /dev/null +++ b/packages/hoppscotch-common/src/platform/desktop-settings.ts @@ -0,0 +1,72 @@ +import { z } from "zod" + +/** + * Shared schema and types for the Tauri desktop app's user settings. + * + * The settings live in `tauri-plugin-store` under namespace + * `DESKTOP_SETTINGS_STORE_NAMESPACE`, key `DESKTOP_SETTINGS_STORE_KEY`. + * Both the Tauri shell (`hoppscotch-desktop`) and the webview + * (`hoppscotch-selfhost-web`, loaded via appload) read and write + * through the same namespace and key. + * + * The schema is the contract between the two sides. A change here + * without coordinating both sides leaves the shell and the webview + * disagreeing about what is in the store. This module lives in + * `hoppscotch-common` because both packages already depend on common + * and neither depends on the other directly, so common is the only + * place a shared definition can live. + * + * Every field has a Zod `.default()` that preserves the pre-settings-epic + * behavior, so a partial read (missing keys, corrupt blob, fresh install) + * parses cleanly into a fully-populated object. Use `parseDesktopSettings()` + * to read raw values safely. + */ + +// Store coordinates. Both sides must use these constants, never string +// literals, so a rename is a single edit and a typo is a compile error. +export const DESKTOP_SETTINGS_STORE_NAMESPACE = "hoppscotch-desktop.v1" +export const DESKTOP_SETTINGS_STORE_KEY = "desktopSettings" + +// Fields are grouped by the area of the app they affect. Defaults +// preserve today's hardcoded behavior so any field not yet bound to a +// control in the settings UI ships without a visible change for existing +// users. +export const DESKTOP_SETTINGS_SCHEMA = z.object({ + // Migrated from the legacy portable-only `PortableSettings`. A future + // epic ticket promotes `disableUpdateNotifications` to a user-facing + // control on all builds. For now it stays portable-only. + disableUpdateNotifications: z.boolean().default(false), + autoSkipWelcome: z.boolean().default(false), + + // Connection and startup behavior. The `connectionTimeoutMs` default + // matches `API_TIMEOUT_SECS` in `config.rs`. User-facing controls for + // these fields are future scope. + connectionTimeoutMs: z.number().int().positive().default(30_000), + autoReconnectLastInstance: z.boolean().default(true), + + // Update-pipeline controls. `disable*` polarity matches the existing + // `disableUpdateNotifications` field so all three update-related + // booleans read uniformly, and the on-by-default framing ("Disable X" + // with default false) nudges users toward keeping the update flow + // active. `disableUpdateChecks` is bound to a toggle in the current + // settings UI. `disableUpdateDownloads` is future scope. + disableUpdateChecks: z.boolean().default(false), + disableUpdateDownloads: z.boolean().default(false), + + // Display and UX. User-facing zoom control is future scope. + zoomLevel: z.number().positive().default(1.0), +}) + +export type DesktopSettings = z.infer + +/** + * Parses a raw value into `DesktopSettings`, falling back to full defaults + * on any validation failure. Never throws. + */ +export const parseDesktopSettings = (raw: unknown): DesktopSettings => { + const parsed = DESKTOP_SETTINGS_SCHEMA.safeParse(raw ?? {}) + if (!parsed.success) { + return DESKTOP_SETTINGS_SCHEMA.parse({}) + } + return parsed.data +} diff --git a/packages/hoppscotch-common/src/platform/instance.ts b/packages/hoppscotch-common/src/platform/instance.ts index 84b154b2a8e..bc766c6eb3e 100644 --- a/packages/hoppscotch-common/src/platform/instance.ts +++ b/packages/hoppscotch-common/src/platform/instance.ts @@ -18,7 +18,7 @@ export const VENDORED_INSTANCE_CONFIG: Instance = { kind: "vendored" as const, serverUrl: "app://hoppscotch", displayName: "Hoppscotch Desktop", - version: "26.3.1", + version: "26.4.0", lastUsed: new Date().toISOString(), bundleName: "Hoppscotch", } diff --git a/packages/hoppscotch-common/src/platform/std/kernel-interceptors/proxy/store.ts b/packages/hoppscotch-common/src/platform/std/kernel-interceptors/proxy/store.ts index f70308a253b..ffe62887879 100644 --- a/packages/hoppscotch-common/src/platform/std/kernel-interceptors/proxy/store.ts +++ b/packages/hoppscotch-common/src/platform/std/kernel-interceptors/proxy/store.ts @@ -1,12 +1,13 @@ +import { ref, readonly, toRaw, type Ref, type DeepReadonly } from "vue" import { Service } from "dioc" import { Store } from "~/kernel/store" -import { settingsStore } from "~/newstore/settings" +import { getDefaultProxyUrl, DEFAULT_HOPP_PROXY_URL } from "~/helpers/proxyUrl" import * as E from "fp-ts/Either" const STORE_NAMESPACE = "interceptors.proxy.v1" const SETTINGS_KEY = "settings" -type ProxySettings = { +export type ProxySettings = { version: "v1" proxyUrl: string accessToken: string @@ -18,16 +19,41 @@ interface StoredData { lastUpdated: string } -const DEFAULT_SETTINGS: ProxySettings = { - version: "v1", - proxyUrl: settingsStore.value.PROXY_URL ?? "https://proxy.hoppscotch.io", - accessToken: import.meta.env.VITE_PROXYSCOTCH_ACCESS_TOKEN ?? "", +/** + * Build fresh default settings. + * Called as a function (not a static const) so that `getDefaultProxyUrl()` + * can resolve against the current platform, which isn't available at + * module-load time. + */ +async function buildDefaultSettings(): Promise { + return { + version: "v1", + proxyUrl: await getDefaultProxyUrl(), + accessToken: import.meta.env.VITE_PROXYSCOTCH_ACCESS_TOKEN ?? "", + } } +/** + * Reactive proxy settings store. + * + * Exposes `settings$` as a readonly ref, any component or service that reads + * `settings$.value` will automatically re-render when settings change. + */ export class KernelInterceptorProxyStore extends Service { public static readonly ID = "KERNEL_PROXY_INTERCEPTOR_STORE" - private settings: ProxySettings = { ...DEFAULT_SETTINGS } + private readonly _settings = ref({ + version: "v1", + proxyUrl: DEFAULT_HOPP_PROXY_URL, + accessToken: import.meta.env.VITE_PROXYSCOTCH_ACCESS_TOKEN ?? "", + }) + + /** + * Reactive, read-only view of the current proxy settings. + */ + public readonly settings$: DeepReadonly> = readonly( + this._settings + ) async onServiceInit(): Promise { const initResult = await Store.init() @@ -42,7 +68,14 @@ export class KernelInterceptorProxyStore extends Service { watcher.on("change", async ({ value }) => { if (value) { const storedData = value as StoredData - this.settings = storedData.settings + this._settings.value = { + ...this._settings.value, + // Only sync user-configurable fields from external changes. + // Fallback to current value if persisted data is missing the field + // (e.g. older schema). accessToken stays env-derived. + proxyUrl: + storedData.settings?.proxyUrl ?? this._settings.value.proxyUrl, + } } }) } @@ -53,21 +86,29 @@ export class KernelInterceptorProxyStore extends Service { SETTINGS_KEY ) + const defaults = await buildDefaultSettings() + if (E.isRight(loadResult) && loadResult.right) { const storedData = loadResult.right - this.settings = { - ...DEFAULT_SETTINGS, - ...storedData.settings, + this._settings.value = { + ...defaults, + // Only restore user-configurable fields from storage. + // accessToken is env-derived (VITE_PROXYSCOTCH_ACCESS_TOKEN) and + // must always reflect the current deployment, not a stale persisted value. + proxyUrl: storedData.settings?.proxyUrl ?? defaults.proxyUrl, } } else { + this._settings.value = { ...defaults } await this.persistSettings() } } private async persistSettings(): Promise { + const rawSettings = toRaw(this._settings.value) + const storedData: StoredData = { version: "v1", - settings: this.settings, + settings: { ...rawSettings }, lastUpdated: new Date().toISOString(), } @@ -82,21 +123,31 @@ export class KernelInterceptorProxyStore extends Service { } } - public async updateSettings(settings: Partial): Promise { - this.settings = { - ...this.settings, - ...settings, + /** + * Update user-configurable proxy settings. + * Only `proxyUrl` is user-configurable, `accessToken` and `version` are + * derived at runtime and cannot be overwritten by callers. + */ + public async updateSettings( + patch: Pick + ): Promise { + this._settings.value = { + ...this._settings.value, + proxyUrl: patch.proxyUrl, } - await this.persistSettings() } + /** + * @deprecated Use `settings$` for reactive access. This exists only for + * non-reactive contexts (e.g. inside `execute()` in the interceptor service). + */ public getSettings(): ProxySettings { - return { ...this.settings } + return { ...this._settings.value } } public async resetSettings(): Promise { - this.settings = { ...DEFAULT_SETTINGS } + this._settings.value = await buildDefaultSettings() await this.persistSettings() } } diff --git a/packages/hoppscotch-common/src/platform/update-state.ts b/packages/hoppscotch-common/src/platform/update-state.ts new file mode 100644 index 00000000000..6235b95b429 --- /dev/null +++ b/packages/hoppscotch-common/src/platform/update-state.ts @@ -0,0 +1,69 @@ +import { z } from "zod" + +/** + * Shared schema and types for the desktop app's auto-updater state. + * + * The updater state is written to `tauri-plugin-store` by the Tauri shell + * (`hoppscotch-desktop/src/utils/updater.ts`) and read by both the shell's + * persistence service and the webview's settings page. This module is the + * single source of truth for the definition that crosses all three + * boundaries (Rust, shell JS, webview JS via the store file). + * + * Persisted form is deliberately flat (status + optional fields). The + * webview's `useUpdateCheck` composable derives a discriminated union + * over this flat form for its internal state, but the wire format that + * hits disk stays simple so existing Rust writers continue to work + * unchanged. + */ + +// Store coordinates. Both the shell persistence service and the webview +// composable reference these constants rather than string literals. +export const UPDATE_STATE_STORE_NAMESPACE = "hoppscotch-desktop.v1" +export const UPDATE_STATE_STORE_KEY = "updateState" + +// `UpdateStatus` as a `const` object rather than a TS `enum` so: +// 1. The values are plain string literals, so they cross the store +// boundary as JSON without extra conversion. +// 2. The inferred union type (`"idle" | "checking" | ...`) narrows +// cleanly in switch statements and matches Zod's `z.enum` output. +// 3. It imports zero-cost into the webview bundle, where TS enums can +// produce runtime objects that tree-shaking sometimes fails to drop. +export const UpdateStatus = { + IDLE: "idle", + CHECKING: "checking", + AVAILABLE: "available", + NOT_AVAILABLE: "not_available", + DOWNLOADING: "downloading", + INSTALLING: "installing", + READY_TO_RESTART: "ready_to_restart", + ERROR: "error", +} as const + +export type UpdateStatus = (typeof UpdateStatus)[keyof typeof UpdateStatus] + +export const UPDATE_STATUS_SCHEMA = z.enum([ + UpdateStatus.IDLE, + UpdateStatus.CHECKING, + UpdateStatus.AVAILABLE, + UpdateStatus.NOT_AVAILABLE, + UpdateStatus.DOWNLOADING, + UpdateStatus.INSTALLING, + UpdateStatus.READY_TO_RESTART, + UpdateStatus.ERROR, +]) + +export const DOWNLOAD_PROGRESS_SCHEMA = z.object({ + downloaded: z.number(), + total: z.number().optional(), +}) + +export type DownloadProgress = z.infer + +export const UPDATE_STATE_SCHEMA = z.object({ + status: UPDATE_STATUS_SCHEMA, + version: z.string().optional(), + message: z.string().optional(), + progress: DOWNLOAD_PROGRESS_SCHEMA.optional(), +}) + +export type UpdateState = z.infer diff --git a/packages/hoppscotch-common/src/services/__tests__/documentation.service.spec.ts b/packages/hoppscotch-common/src/services/__tests__/documentation.service.spec.ts index 5dca939eac1..409fa94ee15 100644 --- a/packages/hoppscotch-common/src/services/__tests__/documentation.service.spec.ts +++ b/packages/hoppscotch-common/src/services/__tests__/documentation.service.spec.ts @@ -14,7 +14,6 @@ import { SetCollectionDocumentationOptions, SetRequestDocumentationOptions, isLiveVersion, - CURRENT_VERSION_TAG, } from "../documentation.service" import { platform } from "~/platform" @@ -41,6 +40,8 @@ describe("DocumentationService", () => { variables: [], id: "collection-123", description: null, + preRequestScript: "", + testScript: "", }) const mockRequest: HoppRESTRequest = makeRESTRequest({ @@ -750,33 +751,11 @@ describe("DocumentationService", () => { }) describe("isLiveVersion", () => { - it("returns true when autoSync is true and version is CURRENT", () => { - expect( - isLiveVersion({ autoSync: true, version: CURRENT_VERSION_TAG }) - ).toBe(true) - }) - - it("is case-insensitive for CURRENT tag", () => { - expect(isLiveVersion({ autoSync: true, version: "current" })).toBe(true) - expect(isLiveVersion({ autoSync: true, version: "Current" })).toBe(true) - }) - - it("returns true for legacy 1.0.0 version with autoSync", () => { - expect(isLiveVersion({ autoSync: true, version: "1.0.0" })).toBe(true) - }) - - it("returns false when autoSync is false even if version is CURRENT", () => { - expect( - isLiveVersion({ autoSync: false, version: CURRENT_VERSION_TAG }) - ).toBe(false) - }) - - it("returns false when autoSync is false for legacy 1.0.0", () => { - expect(isLiveVersion({ autoSync: false, version: "1.0.0" })).toBe(false) + it("returns true when autoSync is true", () => { + expect(isLiveVersion({ autoSync: true })).toBe(true) }) - it("returns false for a snapshot version string", () => { - expect(isLiveVersion({ autoSync: true, version: "2.0.0" })).toBe(false) - expect(isLiveVersion({ autoSync: false, version: "2.0.0" })).toBe(false) + it("returns false when autoSync is false", () => { + expect(isLiveVersion({ autoSync: false })).toBe(false) }) }) diff --git a/packages/hoppscotch-common/src/services/documentation.service.ts b/packages/hoppscotch-common/src/services/documentation.service.ts index da31a850243..8008197abc9 100644 --- a/packages/hoppscotch-common/src/services/documentation.service.ts +++ b/packages/hoppscotch-common/src/services/documentation.service.ts @@ -100,16 +100,11 @@ export const CURRENT_VERSION_TAG = "CURRENT" /** * Checks whether a published doc version is the live (current) version. - * A live version is auto-synced, has the CURRENT version identifier, - * or has version 1.0.0 (used in older versions of the project). - * This version is in sync with the particular collection and will update if the collection is updated. + * A live version is one that has auto-sync enabled — it stays in sync with + * the collection and will update whenever the collection is updated. */ -export const isLiveVersion = (doc: { - autoSync: boolean - version: string -}): boolean => - doc.autoSync && - (doc.version.toUpperCase() === CURRENT_VERSION_TAG || doc.version === "1.0.0") +export const isLiveVersion = (doc: { autoSync: boolean }): boolean => + doc.autoSync /** * This service manages edited documentation for collections and requests. diff --git a/packages/hoppscotch-common/src/services/oauth/flows/authCode.ts b/packages/hoppscotch-common/src/services/oauth/flows/authCode.ts index 6df42613ff2..aff25d2fad6 100644 --- a/packages/hoppscotch-common/src/services/oauth/flows/authCode.ts +++ b/packages/hoppscotch-common/src/services/oauth/flows/authCode.ts @@ -189,7 +189,6 @@ const initAuthCodeOauthFlow = async ({ return E.left("INVALID_AUTH_ENDPOINT") } - url.searchParams.set("grant_type", "authorization_code") url.searchParams.set("client_id", clientID) url.searchParams.set("state", state) url.searchParams.set("response_type", "code") @@ -289,18 +288,31 @@ const handleRedirectForAuthCodeOauthFlow = async (localConfig: string) => { return E.left("AUTH_TOKEN_REQUEST_FAILED" as const) } - const withAccessTokenSchema = z.object({ - access_token: z.string(), - refresh_token: z.string().optional(), - }) + const withAccessTokenSchema = z + .object({ + access_token: z.string().optional(), + id_token: z.string().optional(), + refresh_token: z.string().optional(), + }) + .refine((data) => data.access_token || data.id_token, { + message: "Either access_token or id_token must be present", + }) const parsedTokenResponse = withAccessTokenSchema.safeParse( responsePayload.right ) - return parsedTokenResponse.success - ? E.right(parsedTokenResponse.data) - : E.left("AUTH_TOKEN_REQUEST_INVALID_RESPONSE" as const) + if (!parsedTokenResponse.success) { + return E.left("AUTH_TOKEN_REQUEST_INVALID_RESPONSE" as const) + } + + return E.right({ + access_token: + parsedTokenResponse.data.access_token || + parsedTokenResponse.data.id_token || + "", + refresh_token: parsedTokenResponse.data.refresh_token, + }) } const generateCodeVerifier = () => { diff --git a/packages/hoppscotch-common/src/services/persistence/__tests__/__mocks__/index.ts b/packages/hoppscotch-common/src/services/persistence/__tests__/__mocks__/index.ts index 4716f46493a..e4ee651a8d7 100644 --- a/packages/hoppscotch-common/src/services/persistence/__tests__/__mocks__/index.ts +++ b/packages/hoppscotch-common/src/services/persistence/__tests__/__mocks__/index.ts @@ -1,4 +1,5 @@ import { + CollectionSchemaVersion, Environment, GlobalEnvironment, HoppCollection, @@ -25,7 +26,7 @@ const DEFAULT_SETTINGS = getDefaultSettings() export const REST_COLLECTIONS_MOCK: HoppCollection[] = [ { - v: 11, + v: CollectionSchemaVersion, name: "Echo", requests: [ { @@ -54,13 +55,15 @@ export const REST_COLLECTIONS_MOCK: HoppCollection[] = [ headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", folders: [], }, ] export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [ { - v: 11, + v: CollectionSchemaVersion, name: "Echo", requests: [ { @@ -80,6 +83,8 @@ export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [ headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", folders: [], }, ] diff --git a/packages/hoppscotch-common/src/services/persistence/__tests__/index.spec.ts b/packages/hoppscotch-common/src/services/persistence/__tests__/index.spec.ts index 0f651f03f62..f69f5af06de 100644 --- a/packages/hoppscotch-common/src/services/persistence/__tests__/index.spec.ts +++ b/packages/hoppscotch-common/src/services/persistence/__tests__/index.spec.ts @@ -709,6 +709,74 @@ describe("PersistenceService", () => { ) }) + it(`v=2 migration repairs entries in "${graphqlHistoryKey}" whose response field is a non-string and writes a pre-v2 backup`, async () => { + // Pre-fix sync writes round-tripped via JSON.stringify/parse, + // leaving entries with object-shaped response in localStorage. + const corruptedEntries = [ + { ...GQL_HISTORY_MOCK[0], response: {} }, + { ...GQL_HISTORY_MOCK[0], response: null }, + ] + await setStoreItem(graphqlHistoryKey, corruptedEntries) + + const setItemSpy = spyOnSetItem() + + await invokeSetupLocalPersistence() + + // Original is preserved at the pre-v2 backup key for recovery. + expect(setItemSpy).toHaveBeenCalledWith( + `${graphqlHistoryKey}-pre-v2-backup`, + expect.stringContaining(JSON.stringify(corruptedEntries)) + ) + + // Repaired data is written back to the live key with response coerced. + // - Object response {} stringifies to "{}", which appears in the + // serialized payload as `"response":"{}"`. + // - Null response stringifies to "null", which appears in the + // serialized payload as `"response":"null"` and preserves the + // original semantic of an empty payload. + expect(setItemSpy).toHaveBeenCalledWith( + graphqlHistoryKey, + expect.stringContaining('"response":"{}"') + ) + expect(setItemSpy).toHaveBeenCalledWith( + graphqlHistoryKey, + expect.stringContaining('"response":"null"') + ) + + // Schema version bumps to 2, so the migration won't run again. + expect(setItemSpy).toHaveBeenCalledWith( + schemaVersionKey, + expect.stringMatching(/"data":"2"/) + ) + + // No Zod-failure backup since the migration repaired the shape + // before validation could reject it. + expect(toastErrorFn).not.toHaveBeenCalledWith( + expect.stringContaining(graphqlHistoryKey) + ) + }) + + it(`v=2 migration is a no-op when "${graphqlHistoryKey}" entries already have string responses`, async () => { + // Clean entries — response is already a string per the contract. + await setStoreItem(graphqlHistoryKey, GQL_HISTORY_MOCK) + + const setItemSpy = spyOnSetItem() + + await invokeSetupLocalPersistence() + + // No backup write since needsRepair was false. + expect(setItemSpy).not.toHaveBeenCalledWith( + `${graphqlHistoryKey}-pre-v2-backup`, + expect.anything() + ) + + // Schema version still bumps to 2 so the migration is recorded as run. + expect(setItemSpy).toHaveBeenCalledWith( + schemaVersionKey, + expect.stringMatching(/"data":"2"/) + ) + }) + it(`GQL history schema parsing succeeds if there is no "${graphqlHistoryKey}" key present in localStorage where the fallback of "[]" is chosen`, async () => { window.localStorage.removeItem(graphqlHistoryKey) diff --git a/packages/hoppscotch-common/src/services/persistence/index.ts b/packages/hoppscotch-common/src/services/persistence/index.ts index 83d9e823f3b..e722cb25650 100644 --- a/packages/hoppscotch-common/src/services/persistence/index.ts +++ b/packages/hoppscotch-common/src/services/persistence/index.ts @@ -176,6 +176,76 @@ const migrations: Migration[] = [ } }, }, + { + // Coerce gqlHistory entries with non-string `response` to string, + // backing up originals at `${GQL_HISTORY}-pre-v2-backup`. + version: 2, + migrate: async () => { + const result = await Store.get( + STORE_NAMESPACE, + STORE_KEYS.GQL_HISTORY + ) + + if (!E.isRight(result) || !Array.isArray(result.right)) return + + const entries = result.right + // Only target entries with own `response` field that's non-string; + // unrelated schema mismatches still go through the Zod-fail backup. + const needsRepair = entries.some( + (entry) => + typeof entry === "object" && + entry !== null && + Object.prototype.hasOwnProperty.call(entry, "response") && + typeof (entry as { response?: unknown }).response !== "string" + ) + + if (!needsRepair) return + + // Throw on backup or repair write failure so `runMigrations` can + // skip the schema_version bump and retry on the next launch. The + // alternative — log-and-continue — would mark the migration done + // while leaving poisoned data in place, with no future retry path. + const backupResult = await Store.set( + STORE_NAMESPACE, + `${STORE_KEYS.GQL_HISTORY}-pre-v2-backup`, + entries + ) + if (E.isLeft(backupResult)) { + throw new Error( + `[v2 migration] failed to write pre-v2 backup: ${backupResult.left.kind}: ${backupResult.left.message}` + ) + } + + const repaired = entries.map((entry) => { + if (typeof entry !== "object" || entry === null) return entry + const e = entry as Record + if ( + !Object.prototype.hasOwnProperty.call(e, "response") || + typeof e.response === "string" + ) { + return e + } + // Use JSON.stringify(e.response) directly so a `null` payload + // serializes to the string `"null"` rather than `'""'`. Either + // form satisfies the `response: z.string()` schema, but `"null"` + // preserves the original semantic of an empty payload (e.g. a + // subscription that produced no data) and avoids re-stringifying + // on the next sync write. + return { ...e, response: JSON.stringify(e.response) } + }) + + const repairResult = await Store.set( + STORE_NAMESPACE, + STORE_KEYS.GQL_HISTORY, + repaired + ) + if (E.isLeft(repairResult)) { + throw new Error( + `[v2 migration] failed to write repaired ${STORE_KEYS.GQL_HISTORY}: ${repairResult.left.kind}: ${repairResult.left.message}` + ) + } + }, + }, ] /** @@ -235,13 +305,25 @@ export class PersistenceService extends Service { ) const perhapsVersion = E.isRight(versionResult) ? versionResult.right : "0" const currentVersion = perhapsVersion ?? "0" - const targetVersion = "1" + const targetVersion = "2" if (currentVersion !== targetVersion) { - for (const migration of migrations) { - if (migration.version > parseInt(currentVersion)) { - await migration.migrate() + try { + for (const migration of migrations) { + if (migration.version > parseInt(currentVersion)) { + await migration.migrate() + } } + } catch (err) { + // A migration that throws (e.g. v2 repair on a degraded store) + // aborts the schema_version bump so the next launch retries + // from the same currentVersion rather than recording an + // incomplete migration as done. + console.error( + "[persistence] migration failed; schema_version not advanced:", + err + ) + return } await Store.set(STORE_NAMESPACE, STORE_KEYS.SCHEMA_VERSION, targetVersion) diff --git a/packages/hoppscotch-common/src/services/persistence/validation-schemas/index.ts b/packages/hoppscotch-common/src/services/persistence/validation-schemas/index.ts index a65925132b8..65716f339d3 100644 --- a/packages/hoppscotch-common/src/services/persistence/validation-schemas/index.ts +++ b/packages/hoppscotch-common/src/services/persistence/validation-schemas/index.ts @@ -325,6 +325,16 @@ const HoppInheritedPropertySchema = z }) ) .catch([]), + scripts: z + .array( + z.object({ + parentID: z.string(), + parentName: z.string(), + preRequestScript: z.string(), + testScript: z.string(), + }) + ) + .catch([]), }) .strict() diff --git a/packages/hoppscotch-common/src/services/team-collection.service.ts b/packages/hoppscotch-common/src/services/team-collection.service.ts index 1e1daaa0d68..d6decf27bbd 100644 --- a/packages/hoppscotch-common/src/services/team-collection.service.ts +++ b/packages/hoppscotch-common/src/services/team-collection.service.ts @@ -1,11 +1,6 @@ import * as E from "fp-ts/Either" import { Subscription } from "rxjs" -import { - HoppCollectionVariable, - HoppRESTAuth, - HoppRESTHeader, - translateToNewRequest, -} from "@hoppscotch/data" +import { HoppCollectionVariable, translateToNewRequest } from "@hoppscotch/data" import { pull, remove } from "lodash-es" import { Subscription as WSubscription } from "wonka" import { @@ -34,6 +29,8 @@ import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" import { ref, watch } from "vue" import { Service } from "dioc" import { updateInheritedPropertiesForAffectedRequests } from "~/helpers/collection/collection" +import { hasActualScript } from "~/helpers/scripting" +import { CollectionDataProps } from "~/helpers/backend/helpers" export const TEAMS_BACKEND_PAGE_SIZE = 10 @@ -1123,14 +1120,16 @@ export class TeamCollectionsService extends Service { const variables: HoppInheritedProperty["variables"] = [] - if (!folderPath) return { auth, headers, variables } + const scripts: HoppInheritedProperty["scripts"] = [] + + if (!folderPath) return { auth, headers, variables, scripts } const path = folderPath.split("/") // Check if the path is empty or invalid if (!path || path.length === 0) { console.error("Invalid path:", folderPath) - return { auth, headers, variables } + return { auth, headers, variables, scripts } } // Loop through the path and get the last parent folder with authType other than 'inherit' @@ -1140,20 +1139,12 @@ export class TeamCollectionsService extends Service { // Check if parentFolder is undefined or null if (!parentFolder) { console.error("Parent folder not found for path:", path) - return { auth, headers, variables } + return { auth, headers, variables, scripts } } - const data: { - auth?: HoppRESTAuth - headers?: HoppRESTHeader[] - variables?: HoppCollectionVariable[] - } = parentFolder.data + const data: Partial = parentFolder.data ? JSON.parse(parentFolder.data) - : { - auth: null, - headers: null, - variables: null, - } + : {} if (!data.auth) { data.auth = { @@ -1230,9 +1221,27 @@ export class TeamCollectionsService extends Service { ), }) } + + // Collect scripts from the collection hierarchy (root to child order) + const parentPreRequestScript = data.preRequestScript ?? "" + const parentTestScript = data.testScript ?? "" + + if ( + hasActualScript(parentPreRequestScript) || + hasActualScript(parentTestScript) + ) { + const currentPath = path.slice(0, i + 1).join("/") + + scripts.push({ + parentID: parentFolder.id ?? currentPath, + parentName: parentFolder.title, + preRequestScript: parentPreRequestScript, + testScript: parentTestScript, + }) + } } - return { auth, headers, variables } + return { auth, headers, variables, scripts } } private async waitForCollectionLoading(collectionID: string) { @@ -1260,6 +1269,7 @@ export class TeamCollectionsService extends Service { }, headers: [], variables: [], + scripts: [], } const path = folderPath.split("/") @@ -1278,6 +1288,7 @@ export class TeamCollectionsService extends Service { }, headers: [], variables: [], + scripts: [], } } diff --git a/packages/hoppscotch-common/src/services/test-runner/test-runner.service.ts b/packages/hoppscotch-common/src/services/test-runner/test-runner.service.ts index 2f7361f48a9..2a2033af741 100644 --- a/packages/hoppscotch-common/src/services/test-runner/test-runner.service.ts +++ b/packages/hoppscotch-common/src/services/test-runner/test-runner.service.ts @@ -5,6 +5,7 @@ import { HoppRESTRequest, } from "@hoppscotch/data" import { Service } from "dioc" +import { hasActualScript } from "~/helpers/scripting" import * as E from "fp-ts/Either" import { cloneDeep } from "lodash-es" import { nextTick, Ref } from "vue" @@ -52,7 +53,9 @@ export class TestRunnerService extends Service { public runTests( tab: Ref>, collection: HoppCollection, - options: TestRunnerOptions + options: TestRunnerOptions, + ancestorPreRequestScripts: string[] = [], + ancestorTestScripts: string[] = [] ) { // Reset the result collection tab.value.document.status = "running" @@ -66,9 +69,22 @@ export class TestRunnerService extends Service { requests: [], variables: [], description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } - this.runTestCollection(tab, collection, options) + this.runTestCollection( + tab, + collection, + options, + [], + undefined, + undefined, + [], + undefined, + ancestorPreRequestScripts, + ancestorTestScripts + ) .then(() => { tab.value.document.status = "stopped" }) @@ -96,7 +112,9 @@ export class TestRunnerService extends Service { parentHeaders?: HoppRESTHeaders, parentAuth?: HoppRESTRequest["auth"], parentVariables: HoppCollection["variables"] = [], - parentID?: string + parentID?: string, + parentPreRequestScripts: string[] = [], + parentTestScripts: string[] = [] ) { try { // Compute inherited auth and headers for this collection @@ -121,6 +139,19 @@ export class TestRunnerService extends Service { ) || []), ] + const inheritedPreRequestScripts = [ + ...parentPreRequestScripts, + ...(hasActualScript(collection.preRequestScript) + ? [collection.preRequestScript] + : []), + ] + const inheritedTestScripts = [ + ...parentTestScripts, + ...(hasActualScript(collection.testScript) + ? [collection.testScript] + : []), + ] + // Process folders progressively for (let i = 0; i < collection.folders.length; i++) { if (options.stopRef?.value) { @@ -142,7 +173,6 @@ export class TestRunnerService extends Service { } ) - // Pass inherited headers and auth to the folder await this.runTestCollection( tab, folder, @@ -151,7 +181,9 @@ export class TestRunnerService extends Service { inheritedHeaders, inheritedAuth, inheritedVariables, - collection._ref_id || collection.id + collection._ref_id || collection.id, + inheritedPreRequestScripts, + inheritedTestScripts ) } @@ -188,7 +220,9 @@ export class TestRunnerService extends Service { collection, options, currentPath, - inheritedVariables + inheritedVariables, + inheritedPreRequestScripts, + inheritedTestScripts ) if (options.delay && options.delay > 0) { @@ -279,7 +313,9 @@ export class TestRunnerService extends Service { collection: HoppCollection, options: TestRunnerOptions, path: number[], - inheritedVariables: HoppCollectionVariable[] = [] + inheritedVariables: HoppCollectionVariable[] = [], + inheritedPreRequestScripts: string[] = [], + inheritedTestScripts: string[] = [] ) { if (options.stopRef?.value) { throw new Error("Test execution stopped") @@ -305,7 +341,9 @@ export class TestRunnerService extends Service { request, options.keepVariableValues, inheritedVariables, - initialEnvironmentState + initialEnvironmentState, + inheritedPreRequestScripts, + inheritedTestScripts ) if (options.stopRef?.value) { diff --git a/packages/hoppscotch-data/package.json b/packages/hoppscotch-data/package.json index 0dee1c5d410..399745323c3 100644 --- a/packages/hoppscotch-data/package.json +++ b/packages/hoppscotch-data/package.json @@ -37,13 +37,13 @@ "devDependencies": { "@types/lodash": "4.17.24", "typescript": "5.9.3", - "vite": "7.3.1" + "vite": "7.3.2" }, "dependencies": { "fp-ts": "2.16.11", "io-ts": "2.2.22", "jose": "6.2.2", - "lodash": "4.17.23", + "lodash": "4.18.1", "parser-ts": "0.7.0", "uuid": "13.0.0", "verzod": "0.4.0", diff --git a/packages/hoppscotch-data/src/collection/index.ts b/packages/hoppscotch-data/src/collection/index.ts index ddb0a4e89e7..9ec50135179 100644 --- a/packages/hoppscotch-data/src/collection/index.ts +++ b/packages/hoppscotch-data/src/collection/index.ts @@ -11,6 +11,7 @@ import V8_VERSION from "./v/8" import V9_VERSION from "./v/9" import V10_VERSION from "./v/10" import V11_VERSION from "./v/11" +import V12_VERSION from "./v/12" export { CollectionVariable } from "./v/10" @@ -24,7 +25,7 @@ const versionedObject = z.object({ }) export const HoppCollection = createVersionedEntity({ - latestVersion: 11, + latestVersion: 12, versionMap: { 1: V1_VERSION, 2: V2_VERSION, @@ -37,6 +38,7 @@ export const HoppCollection = createVersionedEntity({ 9: V9_VERSION, 10: V10_VERSION, 11: V11_VERSION, + 12: V12_VERSION, }, getVersion(data) { const versionCheck = versionedObject.safeParse(data) @@ -56,7 +58,7 @@ export type HoppCollectionVariable = InferredEntity< typeof HoppCollection >["variables"][number] -export const CollectionSchemaVersion = 11 +export const CollectionSchemaVersion = 12 /** * Generates a Collection object. This ignores the version number object @@ -88,6 +90,9 @@ export function translateToNewRESTCollection(x: any): HoppCollection { const description = x.description ?? null + const preRequestScript = x.preRequestScript ?? "" + const testScript = x.testScript ?? "" + const obj = makeCollection({ name, folders, @@ -96,6 +101,8 @@ export function translateToNewRESTCollection(x: any): HoppCollection { headers, variables, description, + preRequestScript, + testScript, }) if (x.id) obj.id = x.id @@ -123,6 +130,9 @@ export function translateToNewGQLCollection(x: any): HoppCollection { const description = x.description ?? null + const preRequestScript = x.preRequestScript ?? "" + const testScript = x.testScript ?? "" + const obj = makeCollection({ name, folders, @@ -131,6 +141,8 @@ export function translateToNewGQLCollection(x: any): HoppCollection { headers, variables, description, + preRequestScript, + testScript, }) if (x.id) obj.id = x.id diff --git a/packages/hoppscotch-data/src/collection/v/10.ts b/packages/hoppscotch-data/src/collection/v/10.ts index a9a9cc7ed7f..21759c5956e 100644 --- a/packages/hoppscotch-data/src/collection/v/10.ts +++ b/packages/hoppscotch-data/src/collection/v/10.ts @@ -2,7 +2,7 @@ import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppCollection } from ".." -import { v9_baseCollectionSchema } from "./9" +import { v9_baseCollectionSchema, V9_SCHEMA } from "./9" export const CollectionVariable = z.object({ key: z.string(), @@ -33,7 +33,7 @@ export const V10_SCHEMA = v10_baseCollectionSchema.extend({ export default defineVersion({ initial: false, schema: V10_SCHEMA, - up(old: z.infer) { + up(old: z.infer) { const result: z.infer = { ...old, v: 10 as const, diff --git a/packages/hoppscotch-data/src/collection/v/11.ts b/packages/hoppscotch-data/src/collection/v/11.ts index 3ce931203b1..dcc77a77a90 100644 --- a/packages/hoppscotch-data/src/collection/v/11.ts +++ b/packages/hoppscotch-data/src/collection/v/11.ts @@ -2,7 +2,7 @@ import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppCollection } from ".." -import { v10_baseCollectionSchema } from "./10" +import { v10_baseCollectionSchema, V10_SCHEMA } from "./10" export const v11_baseCollectionSchema = v10_baseCollectionSchema.extend({ v: z.literal(11), @@ -24,11 +24,11 @@ export const V11_SCHEMA = v11_baseCollectionSchema.extend({ export default defineVersion({ initial: false, schema: V11_SCHEMA, - up(old: z.infer) { + up(old: z.infer) { const result: z.infer = { ...old, v: 11 as const, - description: old.description ?? null, + description: null, folders: old.folders.map((folder) => { const result = HoppCollection.safeParseUpToVersion(folder, 11) diff --git a/packages/hoppscotch-data/src/collection/v/12.ts b/packages/hoppscotch-data/src/collection/v/12.ts new file mode 100644 index 00000000000..985d77adb0a --- /dev/null +++ b/packages/hoppscotch-data/src/collection/v/12.ts @@ -0,0 +1,47 @@ +import { defineVersion, entityRefUptoVersion } from "verzod" +import { z } from "zod" + +import { HoppCollection } from ".." +import { v11_baseCollectionSchema, V11_SCHEMA } from "./11" + +export const v12_baseCollectionSchema = v11_baseCollectionSchema.extend({ + v: z.literal(12), + preRequestScript: z.string().catch(""), + testScript: z.string().catch(""), +}) + +type Input = z.input & { + folders: Input[] +} + +type Output = z.output & { + folders: Output[] +} + +export const V12_SCHEMA = v12_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 12))), +}) as z.ZodType + +export default defineVersion({ + initial: false, + schema: V12_SCHEMA, + up(old: z.infer) { + const result: z.infer = { + ...old, + v: 12 as const, + preRequestScript: "", + testScript: "", + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 12) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), + } + + return result + }, +}) diff --git a/packages/hoppscotch-data/src/graphql/v/6.ts b/packages/hoppscotch-data/src/graphql/v/6.ts index 24255eba238..9dfde90ac3e 100644 --- a/packages/hoppscotch-data/src/graphql/v/6.ts +++ b/packages/hoppscotch-data/src/graphql/v/6.ts @@ -53,7 +53,7 @@ export const V6_SCHEMA = V5_SCHEMA.extend({ export default defineVersion({ schema: V6_SCHEMA, initial: false, - up(old: z.infer) { + up(old: z.infer) { const headers = old.headers.map((header) => { return { ...header, diff --git a/packages/hoppscotch-data/src/predefinedVariables.ts b/packages/hoppscotch-data/src/predefinedVariables.ts index a3569f288bb..9fbab46f2b4 100644 --- a/packages/hoppscotch-data/src/predefinedVariables.ts +++ b/packages/hoppscotch-data/src/predefinedVariables.ts @@ -4,29 +4,29 @@ export type PredefinedVariable = { getValue: () => string } +const generateV4Uuid = () => { + const characters = "0123456789abcdef" + let uuid = "" + for (let i = 0; i < 36; i++) { + if (i === 8 || i === 13 || i === 18 || i === 23) { + uuid += "-" + } else if (i === 14) { + uuid += "4" + } else if (i === 19) { + uuid += characters.charAt(8 + Math.floor(Math.random() * 4)) + } else { + uuid += characters.charAt(Math.floor(Math.random() * characters.length)) + } + } + return uuid +} + export const HOPP_SUPPORTED_PREDEFINED_VARIABLES: PredefinedVariable[] = [ // Common { key: "$guid", description: "A v4 style GUID.", - getValue: () => { - const characters = "0123456789abcdef" - let guid = "" - for (let i = 0; i < 36; i++) { - if (i === 8 || i === 13 || i === 18 || i === 23) { - guid += "-" - } else if (i === 14) { - guid += "4" - } else if (i === 19) { - guid += characters.charAt(8 + Math.floor(Math.random() * 4)) - } else { - guid += characters.charAt( - Math.floor(Math.random() * characters.length) - ) - } - } - return guid - }, + getValue: generateV4Uuid, }, { key: "$timestamp", @@ -42,20 +42,7 @@ export const HOPP_SUPPORTED_PREDEFINED_VARIABLES: PredefinedVariable[] = [ { key: "$randomUUID", description: "A random 36-character UUID.", - getValue: () => { - const characters = "0123456789abcdef" - let uuid = "" - for (let i = 0; i < 36; i++) { - if (i === 8 || i === 13 || i === 18 || i === 23) { - uuid += "-" - } else { - uuid += characters.charAt( - Math.floor(Math.random() * characters.length) - ) - } - } - return uuid - }, + getValue: generateV4Uuid, }, // Text, numbers, and colors @@ -140,7 +127,7 @@ export const HOPP_SUPPORTED_PREDEFINED_VARIABLES: PredefinedVariable[] = [ description: "A random IPv6 address.", getValue: () => { const ip = Array.from({ length: 8 }, () => - Math.floor(Math.random() * 65536).toString(16) + Math.floor(Math.random() * 65536).toString(16).padStart(4, "0") ) return ip.join(":") }, @@ -151,7 +138,7 @@ export const HOPP_SUPPORTED_PREDEFINED_VARIABLES: PredefinedVariable[] = [ description: "A random MAC address.", getValue: () => { const mac = Array.from({ length: 6 }, () => - Math.floor(Math.random() * 256).toString(16) + Math.floor(Math.random() * 256).toString(16).padStart(2, "0") ) return mac.join(":") }, diff --git a/packages/hoppscotch-data/src/rest/v/16.ts b/packages/hoppscotch-data/src/rest/v/16.ts index 79f85ded278..aaa40d75308 100644 --- a/packages/hoppscotch-data/src/rest/v/16.ts +++ b/packages/hoppscotch-data/src/rest/v/16.ts @@ -11,11 +11,11 @@ export const V16_SCHEMA = V15_SCHEMA.extend({ const V16_VERSION = defineVersion({ schema: V16_SCHEMA, initial: false, - up(old: z.infer) { + up(old: z.infer) { return { ...old, v: "16" as const, - _ref_id: old._ref_id ?? generateUniqueRefId("req"), + _ref_id: generateUniqueRefId("req"), } }, }) diff --git a/packages/hoppscotch-data/src/rest/v/17.ts b/packages/hoppscotch-data/src/rest/v/17.ts index b538181214e..f7aac36e65d 100644 --- a/packages/hoppscotch-data/src/rest/v/17.ts +++ b/packages/hoppscotch-data/src/rest/v/17.ts @@ -10,11 +10,11 @@ export const V17_SCHEMA = V16_SCHEMA.extend({ const V17_VERSION = defineVersion({ schema: V17_SCHEMA, initial: false, - up(old: z.infer) { + up(old: z.infer) { return { ...old, v: "17" as const, - description: old.description ?? null, + description: null, } }, }) diff --git a/packages/hoppscotch-desktop/package.json b/packages/hoppscotch-desktop/package.json index c4793cce5c2..18a2129b776 100644 --- a/packages/hoppscotch-desktop/package.json +++ b/packages/hoppscotch-desktop/package.json @@ -1,7 +1,7 @@ { "name": "hoppscotch-desktop", "private": true, - "version": "26.3.1", + "version": "26.4.0", "type": "module", "scripts": { "dev": "vite", @@ -23,7 +23,7 @@ }, "dependencies": { "@fontsource-variable/inter": "5.2.8", - "@fontsource-variable/material-symbols-rounded": "5.2.38", + "@fontsource-variable/material-symbols-rounded": "5.2.43", "@fontsource-variable/roboto-mono": "5.2.8", "@hoppscotch/common": "workspace:^", "@hoppscotch/kernel": "workspace:^", @@ -37,7 +37,7 @@ "@tauri-apps/plugin-updater": "2.9.0", "fp-ts": "2.16.11", "rxjs": "7.8.2", - "vue": "3.5.31", + "vue": "3.5.33", "vue-router": "4.6.4", "vue-tippy": "6.7.1", "zod": "3.25.32" @@ -45,25 +45,25 @@ "devDependencies": { "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.2", - "@iconify-json/lucide": "1.2.99", + "@iconify-json/lucide": "1.2.104", "@rushstack/eslint-patch": "1.16.1", "@tauri-apps/cli": "2.9.3", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@vitejs/plugin-vue": "6.0.5", + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", + "@vitejs/plugin-vue": "6.0.6", "@vue/eslint-config-typescript": "14.7.0", - "autoprefixer": "10.4.27", + "autoprefixer": "10.5.0", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", - "eslint-plugin-vue": "10.8.0", + "eslint-plugin-vue": "10.9.0", "globals": "16.5.0", - "postcss": "8.5.8", - "sass": "1.98.0", + "postcss": "8.5.10", + "sass": "1.99.0", "tailwindcss": "3.4.16", "typescript": "5.9.3", "unplugin-icons": "22.5.0", "unplugin-vue-components": "30.0.0", - "vite": "7.3.1", + "vite": "7.3.2", "vue-tsc": "2.2.0" } } diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock index 3ea7b345dd6..5db8192a1c9 100644 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock +++ b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock @@ -1118,8 +1118,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.13.3+wasi-0.2.2", + "wasm-bindgen", "windows-targets 0.52.6", ] @@ -1890,6 +1892,12 @@ version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -2708,13 +2716,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.9" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", - "getrandom 0.2.15", - "rand 0.8.5", + "getrandom 0.3.1", + "lru-slab", + "rand 0.9.4", "ring", "rustc-hash", "rustls", @@ -2774,6 +2783,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -2794,6 +2813,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -2812,6 +2841,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "rand_hc" version = "0.2.0" diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock index 74875226393..03df3f3b168 100644 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock +++ b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock @@ -3,10 +3,11 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1732585607, + "lastModified": 1776802132, + "narHash": "sha256-2yO2SGA7zVFYKe0qyJjdg7WHuMOKNwTQmigL7ydD8hI=", "owner": "cachix", "repo": "devenv", - "rev": "a520f05c40ebecaf5e17064b27e28ba8e70c49fb", + "rev": "91affc7a7b6646852a0079678eadf12ac5029d9d", "type": "github" }, "original": { @@ -24,10 +25,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1732602776, + "lastModified": 1776845169, + "narHash": "sha256-Ya6Ba5oC0+PK1TSU4Rkjpoca73mUp6FoHQV5QGnqbx0=", "owner": "nix-community", "repo": "fenix", - "rev": "e0d44b70dcd2b98dd77857b4c5c7b1dc6b1ef56d", + "rev": "f0b5be1fa2891221ba8b48784f8fded5ef15301f", "type": "github" }, "original": { @@ -36,47 +38,13 @@ "type": "github" } }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1732238832, + "lastModified": 1776329215, + "narHash": "sha256-a8BYi3mzoJ/AcJP8UldOx8emoPRLeWqALZWu4ZvjPXw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8edf06bea5bcbee082df1b7369ff973b91618b8d", + "rev": "b86751bc4085f48661017fa226dee99fab6c651b", "type": "github" }, "original": { @@ -86,58 +54,22 @@ "type": "github" } }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1731797254, - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e8c38b73aeb218e27163376a2d617e61a2ad9b59", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1732021966, - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "3308484d1a443fc5bc92012435d79e80458fe43c", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, "root": { "inputs": { "devenv": "devenv", "fenix": "fenix", "nixpkgs": "nixpkgs", - "pre-commit-hooks": "pre-commit-hooks" + "rust-overlay": "rust-overlay" } }, "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1732562640, + "lastModified": 1776800521, + "narHash": "sha256-f8YJfwAOsLFpIoqZuX3yF69UvMLrkx7iVzMH1pJU7cM=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "157c7d01149e9be7179c5724b89d8d073e923bd8", + "rev": "8954b66d43225e62c92e8bbcc8500191b5cceb1e", "type": "github" }, "original": { @@ -146,8 +78,28 @@ "repo": "rust-analyzer", "type": "github" } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776827647, + "narHash": "sha256-sYixYhp5V8jCajO8TRorE4fzs7IkL4MZdfLTKgkPQBk=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "40e6ccc06e1245a4837cbbd6bdda64e21cc67379", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } } }, "root": "root", "version": 7 -} +} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix index 1e49dd78791..c6f1f7a1a7e 100644 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix +++ b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix @@ -7,12 +7,7 @@ let else pkgs; darwinPackages = with pkgs; [ - darwin.apple_sdk.frameworks.Security - darwin.apple_sdk.frameworks.CoreServices - darwin.apple_sdk.frameworks.CoreFoundation - darwin.apple_sdk.frameworks.Foundation - darwin.apple_sdk.frameworks.AppKit - darwin.apple_sdk.frameworks.WebKit + apple-sdk ]; linuxPackages = with pkgs; [ @@ -27,8 +22,8 @@ in { packages = with pkgs; [ git nodejs_22 - nodePackages_latest.typescript-language-server - nodePackages_latest.vue-language-server + typescript-language-server + vue-language-server cargo-edit ] ++ lib.optionals pkgs.stdenv.isDarwin darwinPackages ++ lib.optionals pkgs.stdenv.isLinux linuxPackages; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml index 9ee9ba3496c..d0169201787 100644 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml +++ b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml @@ -1,23 +1,14 @@ -# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json inputs: - # For NodeJS-22 and above - nixpkgs: - url: github:NixOS/nixpkgs/nixpkgs-unstable - # nixpkgs: - # url: github:cachix/devenv-nixpkgs/rolling fenix: url: github:nix-community/fenix inputs: nixpkgs: follows: nixpkgs - -# If you're using non-OSS software, you can set allowUnfree to true. + nixpkgs: + url: github:NixOS/nixpkgs/nixpkgs-unstable + rust-overlay: + url: github:oxalica/rust-overlay + inputs: + nixpkgs: + follows: nixpkgs allowUnfree: true - -# If you're willing to use a package that's vulnerable -# permittedInsecurePackages: -# - "openssl-1.1.1w" - -# If you have more than one devenv you can merge them -#imports: -# - ./backend diff --git a/packages/hoppscotch-desktop/src-tauri/Cargo.lock b/packages/hoppscotch-desktop/src-tauri/Cargo.lock index e69d720a7c7..81fda23adab 100644 --- a/packages/hoppscotch-desktop/src-tauri/Cargo.lock +++ b/packages/hoppscotch-desktop/src-tauri/Cargo.lock @@ -2068,9 +2068,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -2322,7 +2324,7 @@ dependencies = [ [[package]] name = "hoppscotch-desktop" -version = "26.3.1" +version = "26.4.0" dependencies = [ "axum", "dirs 6.0.0", @@ -2968,7 +2970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3049,6 +3051,12 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lzma-rs" version = "0.3.0" @@ -4183,13 +4191,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.9" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", - "getrandom 0.2.15", - "rand 0.8.5", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.4", "ring", "rustc-hash", "rustls", @@ -4255,6 +4264,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -4275,6 +4294,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -4293,6 +4322,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.3", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -5683,7 +5721,7 @@ dependencies = [ [[package]] name = "tauri-plugin-relay" version = "0.1.0" -source = "git+https://github.com/CuriousCorrelation/tauri-plugin-relay?rev=7cf09c1ad31e228758738c2f4e1c8fe9cc141291#7cf09c1ad31e228758738c2f4e1c8fe9cc141291" +source = "git+https://github.com/CuriousCorrelation/tauri-plugin-relay?rev=42f449e1c5657679fecf0374b0ce5047ad03c069#42f449e1c5657679fecf0374b0ce5047ad03c069" dependencies = [ "relay", "serde", diff --git a/packages/hoppscotch-desktop/src-tauri/Cargo.toml b/packages/hoppscotch-desktop/src-tauri/Cargo.toml index 7d964fcfc5f..611d3a329bf 100644 --- a/packages/hoppscotch-desktop/src-tauri/Cargo.toml +++ b/packages/hoppscotch-desktop/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hoppscotch-desktop" -version = "26.3.1" +version = "26.4.0" description = "Desktop App for hoppscotch.io" authors = ["CuriousCorrelation"] edition = "2021" @@ -30,7 +30,7 @@ tauri-plugin-dialog = "2.2.0" tauri-plugin-fs = "2.2.0" tauri-plugin-deep-link = "2.2.0" tauri-plugin-appload = { git = "https://github.com/CuriousCorrelation/tauri-plugin-appload", rev = "0d58d53be2bc75aeb5916bd0d77794fd209426af" } -tauri-plugin-relay = { git = "https://github.com/CuriousCorrelation/tauri-plugin-relay", rev = "7cf09c1ad31e228758738c2f4e1c8fe9cc141291" } +tauri-plugin-relay = { git = "https://github.com/CuriousCorrelation/tauri-plugin-relay", rev = "42f449e1c5657679fecf0374b0ce5047ad03c069" } axum = "0.8.1" tower-http = { version = "0.6.2", features = ["cors"] } random-port = "0.1.1" diff --git a/packages/hoppscotch-desktop/src-tauri/src/config.rs b/packages/hoppscotch-desktop/src-tauri/src/config.rs index 2a60ee9dc7b..c3b7aa48695 100644 --- a/packages/hoppscotch-desktop/src-tauri/src/config.rs +++ b/packages/hoppscotch-desktop/src-tauri/src/config.rs @@ -1,9 +1,15 @@ -use std::{fs, path::PathBuf, time::Duration}; +use std::{fs, path::PathBuf, sync::Mutex, time::Duration}; +use serde::Deserialize; use tauri_plugin_appload::{ApiConfig, CacheConfig, Config, StorageConfig, VendorConfig}; use crate::{error::HoppError, path}; +// Appload plugin configuration. These constants are baked into the plugin +// config at startup via `HoppApploadConfig::build()`, before the webview +// exists, so they cannot be overridden by runtime user settings. A future +// user-facing connection timeout override will need a separate mechanism, +// either a startup-time store file read or a deferred appload init. const API_SERVER_URL: &str = "http://localhost:3200"; const API_TIMEOUT_SECS: u64 = 30; const CACHE_MAX_SIZE_MB: usize = 1000; @@ -66,6 +72,72 @@ impl HoppApploadConfig { } } +// Webview-pushed runtime settings bridge. +// +// The webview persists user settings (timeout, zoom, auto-reconnect, and so +// on) via `tauri-plugin-store`. The Tauri shell needs live access to some +// of those values, for example `connectionTimeoutMs` for the appload HTTP +// client. Rather than having Rust read the store file directly, which would +// couple this code to the plugin's on-disk format, the webview pushes the +// current settings to Rust via `set_desktop_config` at init and on change. +// +// The IPC plumbing is wired end-to-end but no Rust code reads +// `DESKTOP_CONFIG` yet. Consumers such as the appload connection timeout +// are future scope. +// +// The struct deliberately only deserializes fields Rust actually consumes. +// TS sends the full `DESKTOP_SETTINGS_SCHEMA` payload and serde drops the +// rest. Adding a new Rust consumer means adding a field here, not changing +// the IPC contract. + +/// Subset of the webview-side `DesktopSettings` that Rust services consume. +/// +/// Field names are snake_case with `rename_all = "camelCase"` so they line +/// up with what the TS store produces from `DESKTOP_SETTINGS_SCHEMA`. +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DesktopConfig { + /// Timeout (ms) for outbound HTTP requests in the appload client and + /// related connection paths. Mirrors `API_TIMEOUT_SECS` when the value + /// is 30_000. + pub connection_timeout_ms: u64, +} + +/// Live copy of the most recent settings pushed from the webview. +/// +/// `None` means the webview has not called `set_desktop_config` yet, which +/// is the case during the early Tauri startup path before the window loads +/// and for the whole of the pre-webview `PortableHome` and `StandardHome` +/// flow. Consumers must treat `None` as "no override, use the compile-time +/// default". +static DESKTOP_CONFIG: Mutex> = Mutex::new(None); + +/// Returns a clone of the most recent settings pushed from the webview, or +/// `None` if nothing has been pushed yet. +/// +/// Cloning keeps the lock scope short, which is cheap because +/// `DesktopConfig` is a small POD struct. +#[allow(dead_code)] // no Rust consumers yet, see module doc above. +pub fn current_desktop_config() -> Option { + DESKTOP_CONFIG + .lock() + .ok() + .and_then(|guard| guard.clone()) +} + +/// Tauri command invoked by the webview on init and whenever settings +/// change. Overwrites any previously-pushed config and is idempotent on +/// identical input. +#[tauri::command] +pub fn set_desktop_config(config: DesktopConfig) -> Result<(), String> { + tracing::debug!(?config, "Received desktop config from webview"); + let mut guard = DESKTOP_CONFIG + .lock() + .map_err(|e| format!("DESKTOP_CONFIG mutex poisoned: {}", e))?; + *guard = Some(config); + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -117,4 +189,51 @@ mod tests { assert!(!config.config_dir.as_os_str().is_empty()); } + + // The roundtrip and overwrite assertions stay in one test because + // `DESKTOP_CONFIG` is process-wide shared state and cargo runs tests + // in parallel by default. Splitting them into two `#[test]` functions + // would race for the global mutex and produce flaky assertions + // depending on schedule. The other tests in this module exercise + // `DesktopConfig` deserialization in isolation and never touch + // `DESKTOP_CONFIG`, so they are safe to run alongside this one. + #[test] + fn set_desktop_config_roundtrip_and_overwrite() { + let result = set_desktop_config(DesktopConfig { + connection_timeout_ms: 45_000, + }); + assert!(result.is_ok()); + assert_eq!( + current_desktop_config().unwrap().connection_timeout_ms, + 45_000 + ); + + set_desktop_config(DesktopConfig { + connection_timeout_ms: 90_000, + }) + .unwrap(); + assert_eq!( + current_desktop_config().unwrap().connection_timeout_ms, + 90_000 + ); + } + + #[test] + fn desktop_config_deserializes_from_camel_case() { + let json = r#"{"connectionTimeoutMs": 60000}"#; + let cfg: DesktopConfig = serde_json::from_str(json).unwrap(); + assert_eq!(cfg.connection_timeout_ms, 60_000); + } + + #[test] + fn desktop_config_deserialize_ignores_extra_fields() { + // TS pushes the full `DESKTOP_SETTINGS_SCHEMA` so extras must drop. + let json = r#"{ + "connectionTimeoutMs": 30000, + "disableUpdateNotifications": true, + "zoomLevel": 1.25 + }"#; + let cfg: DesktopConfig = serde_json::from_str(json).unwrap(); + assert_eq!(cfg.connection_timeout_ms, 30_000); + } } diff --git a/packages/hoppscotch-desktop/src-tauri/src/lib.rs b/packages/hoppscotch-desktop/src-tauri/src/lib.rs index 62c1f8f78fe..db89d88f321 100644 --- a/packages/hoppscotch-desktop/src-tauri/src/lib.rs +++ b/packages/hoppscotch-desktop/src-tauri/src/lib.rs @@ -248,6 +248,7 @@ pub fn run() { hopp_auth_port, quit_app, backup::check_and_backup_on_version_change, + config::set_desktop_config, updater::check_for_updates, updater::download_and_install_update, updater::restart_application, diff --git a/packages/hoppscotch-desktop/src-tauri/tauri.conf.json b/packages/hoppscotch-desktop/src-tauri/tauri.conf.json index 6efafd899eb..98208f21d62 100644 --- a/packages/hoppscotch-desktop/src-tauri/tauri.conf.json +++ b/packages/hoppscotch-desktop/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Hoppscotch", - "version": "26.3.1", + "version": "26.4.0", "identifier": "io.hoppscotch.desktop", "build": { "beforeDevCommand": "pnpm dev", diff --git a/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json b/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json index f120520d26a..59a12e200dd 100644 --- a/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json +++ b/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Hoppscotch", - "version": "26.3.1", + "version": "26.4.0", "identifier": "io.hoppscotch.desktop", "build": { "beforeDevCommand": "pnpm dev", diff --git a/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json b/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json index b92f4c71a65..c9afe9e9038 100644 --- a/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json +++ b/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Hoppscotch", - "version": "26.3.1", + "version": "26.4.0", "identifier": "io.hoppscotch.desktop", "build": { "beforeDevCommand": "pnpm dev", diff --git a/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts b/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts index e09fde23c25..addfa159411 100644 --- a/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts +++ b/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts @@ -1,4 +1,5 @@ import { ref } from "vue" +import * as E from "fp-ts/Either" import { load, download, close } from "@hoppscotch/plugin-appload" import { getVersion } from "@tauri-apps/api/app" import { invoke } from "@tauri-apps/api/core" @@ -44,7 +45,7 @@ export function useAppInitialization() { const saveConnectionState = async (state: ConnectionState) => { try { - await persistence.setConnectionState(state) + await persistence.connectionState.set(state) } catch (err) { console.error("Failed to save connection state:", err) } @@ -246,8 +247,8 @@ export function useAppInitialization() { // instances. The InstanceService's detectCurrentInstanceFromHostname // persists the detected instance (including cloud-org) to this store, // so on restart the main window can resume the correct instance. - const connectionState = await persistence.getConnectionState() - const recentInstances = await persistence.getRecentInstances() + const connectionState = await persistence.connectionState.get() + const recentInstances = await persistence.recentInstances.get() mainDiag(`loadRecent: connectionState=${JSON.stringify(connectionState)}`) mainDiag( @@ -354,7 +355,18 @@ export function useAppInitialization() { } statusMessage.value = "Initializing stores..." - await persistence.init() + // `init` returns `Either` so callers can decide + // how to surface a failure. Branching to a thrown Error here lets + // the surrounding `initialize()` try/catch route the failure into + // `error.value` for the UI, the same way every other startup + // failure is reported, instead of letting init silently complete + // and leave the app running on defaults with no Rust sync. + const initResult = await persistence.init() + if (E.isLeft(initResult)) { + throw new Error( + `Persistence init failed: ${initResult.left.kind}: ${initResult.left.message}` + ) + } } const initialize = async (customLogic?: () => Promise) => { diff --git a/packages/hoppscotch-desktop/src/kernel/store-resource.ts b/packages/hoppscotch-desktop/src/kernel/store-resource.ts new file mode 100644 index 00000000000..4bbcec3a85f --- /dev/null +++ b/packages/hoppscotch-desktop/src/kernel/store-resource.ts @@ -0,0 +1,120 @@ +import * as E from "fp-ts/Either" +import type { z } from "zod" + +import { Log } from "@hoppscotch/common/kernel/log" + +import { Store } from "~/kernel/store" + +const LOG_TAG = "store-resource" + +/** + * A single schema-validated, namespaced, persistent value in the shared + * store. + * + * The persistence service holds several of these (desktop settings, + * update state, connection state, recent instances) which previously + * existed as bespoke `get*` / `set*` / `watch*` method pairs on the + * service class. Each pair was ~20 lines of near-identical plumbing + * that wrapped `Store.get` with a parse and a default fallback, + * wrapped `Store.set` with validation and a throw on failure, and + * wrapped `Store.watch` with an undefined filter and a parse on every + * incoming value. Extracting the pattern to a factory cuts the + * service down to a thin declarative layer where each resource is + * four lines. + * + * A resource is an ordinary value that can be passed around and composed. + * Compound operations (for example "add an instance to the recent list" + * which reads, transforms, and writes) become free functions over a + * resource rather than methods on a god class, which separates the data + * access concern (this factory) from the business rules (the free + * functions). + */ +export interface StoreResource { + /** + * Reads the current value from the store. Falls back to `defaults()` on + * any read error, missing key, or schema validation failure, so callers + * always receive a valid `T`. + */ + get(): Promise + + /** + * Writes a new value after validating through the schema. Throws on + * validation failure or store write failure. Callers that want silent + * best-effort semantics should wrap the call themselves. + */ + set(value: T): Promise + + /** + * Subscribes to external writes. The handler receives the parsed value + * whenever any writer (this process or another) updates the key. + * Resolves to an unsubscribe function. + */ + watch(handler: (value: T) => void): Promise<() => void> +} + +// Input type is deliberately `any` so this works with schemas whose parse +// input differs from output, most commonly `z.object` schemas that carry +// `.default()` on each field (input has optional fields, output has them +// required). Constraining input to `T` would reject every such schema. +export function createStoreResource( + namespace: string, + key: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema: z.ZodType, + defaults: () => T +): StoreResource { + return { + async get(): Promise { + const result = await Store.get(namespace, key) + if (E.isLeft(result) || result.right === undefined) { + return defaults() + } + const parsed = schema.safeParse(result.right) + if (!parsed.success) { + Log.warn( + LOG_TAG, + `${namespace}/${key} failed schema validation, falling back to defaults`, + parsed.error + ) + return defaults() + } + return parsed.data + }, + + async set(value: T): Promise { + const validated = schema.parse(value) + const result = await Store.set(namespace, key, validated) + if (E.isLeft(result)) { + // `StoreError` is a tagged union with `kind` and `message`. + // Interpolating the object directly stringifies to + // `[object Object]`, which is useless in logs and throws, so + // format it explicitly here. + const err = result.left + throw new Error( + `Failed to persist ${namespace}/${key}: ${err.kind}: ${err.message}` + ) + } + }, + + async watch(handler: (value: T) => void): Promise<() => void> { + const emitter = await Store.watch(namespace, key) + return emitter.on("change", ({ value }: { value?: unknown }) => { + if (value === undefined) return + const parsed = schema.safeParse(value) + if (parsed.success) { + handler(parsed.data) + return + } + // Mirrors the parse-failure log in `get()`. Without this, an + // external writer with a schema mismatch (for example a shell + // and webview temporarily out of sync after a migration) would + // stop delivering updates with no observable signal. + Log.warn( + LOG_TAG, + `${namespace}/${key} watch received invalid value, skipping`, + parsed.error + ) + }) + }, + } +} diff --git a/packages/hoppscotch-desktop/src/services/persistence.service.ts b/packages/hoppscotch-desktop/src/services/persistence.service.ts index 025e7b1487f..adbf4c259c1 100644 --- a/packages/hoppscotch-desktop/src/services/persistence.service.ts +++ b/packages/hoppscotch-desktop/src/services/persistence.service.ts @@ -1,41 +1,52 @@ import * as E from "fp-ts/Either" +import { invoke } from "@tauri-apps/api/core" import { z } from "zod" import { StoreError } from "@hoppscotch/kernel" + +import { + DESKTOP_SETTINGS_SCHEMA, + DESKTOP_SETTINGS_STORE_KEY, + DESKTOP_SETTINGS_STORE_NAMESPACE, + type DesktopSettings, +} from "@hoppscotch/common/platform/desktop-settings" +import { + UPDATE_STATE_SCHEMA, + UPDATE_STATE_STORE_KEY, +} from "@hoppscotch/common/platform/update-state" +import type { Instance } from "@hoppscotch/common/platform/instance" +import { Log } from "@hoppscotch/common/kernel/log" + import { Store } from "~/kernel/store" -import { UpdateState, PortableSettings } from "~/types" +import { + createStoreResource, + type StoreResource, +} from "~/kernel/store-resource" +import type { UpdateState } from "~/types" + +const LOG_TAG = "persistence" -export const STORE_NAMESPACE = "hoppscotch-desktop.v1" +// Shared namespace for every desktop-local store resource. Individual keys +// live in `STORE_KEYS` below. Exported for the small handful of callers +// that still touch the store directly. +export const STORE_NAMESPACE = DESKTOP_SETTINGS_STORE_NAMESPACE export const STORE_KEYS = { - UPDATE_STATE: "updateState", + UPDATE_STATE: UPDATE_STATE_STORE_KEY, CONNECTION_STATE: "connectionState", RECENT_INSTANCES: "recentInstances", SCHEMA_VERSION: "schema_version", + // Legacy key. Written by portable builds in schema v1. Read only by the + // v1 to v2 migration. All other code uses `DESKTOP_SETTINGS`. PORTABLE_SETTINGS: "portableSettings", + DESKTOP_SETTINGS: DESKTOP_SETTINGS_STORE_KEY, } as const -export const UPDATE_STATE_SCHEMA = z.object({ - status: z.enum([ - "idle", - "checking", - "available", - "not_available", - "downloading", - "installing", - "ready_to_restart", - "error", - ]), - version: z.string().optional(), - message: z.string().optional(), - progress: z - .object({ - downloaded: z.number(), - total: z.number().optional(), - }) - .optional(), -}) - -export const INSTANCE_SCHEMA = z.object({ +// Runtime validator for `Instance` values read from the store. The type +// annotation pins the Zod output to the canonical `Instance` in common, +// so any drift between the definition stored here and the definition +// consumed by the webview's instance service would fail typecheck +// rather than silently producing a mismatched runtime value. +export const INSTANCE_SCHEMA: z.ZodType = z.object({ kind: z.enum(["on-prem", "cloud", "cloud-org", "vendored"]), serverUrl: z.string(), displayName: z.string(), @@ -44,38 +55,197 @@ export const INSTANCE_SCHEMA = z.object({ bundleName: z.string().optional(), }) -export const CONNECTION_STATE_SCHEMA = z.object({ +// Runtime definition of the persisted connection state. NOTE: the +// canonical `ConnectionState` type in +// `@hoppscotch/common/platform/instance.ts` is a discriminated union, +// while the persisted form here is flat with optional fields per +// variant. The two are semi-compatible (the union serializes cleanly +// into this flat form), but the reader loses type narrowing. A later +// migration can switch the persisted form to a discriminated union so +// common's type becomes the single source of truth end-to-end. +export const PERSISTED_CONNECTION_STATE_SCHEMA = z.object({ status: z.enum(["idle", "connecting", "connected", "error"]), instance: INSTANCE_SCHEMA.optional(), target: z.string().optional(), message: z.string().optional(), }) -export const PORTABLE_SETTINGS_SCHEMA = z.object({ - disableUpdateNotifications: z.boolean(), - autoSkipWelcome: z.boolean(), -}) - -export type InstanceKind = z.infer["kind"] -export type Instance = z.infer -export type ConnectionState = z.infer +export type PersistedConnectionState = z.infer< + typeof PERSISTED_CONNECTION_STATE_SCHEMA +> + +// Re-exported for callers that import from this service. The canonical type +// lives in `@hoppscotch/common/platform/desktop-settings`. +export type { DesktopSettings } + +// Legacy `PortableSettings` interface. Kept as a local type (not +// exported, not re-exported from `~/types`) because the v2 migration +// is the only reader and no new code should produce this form. Once +// the migration is retired this type can be dropped entirely. +interface LegacyPortableSettings { + disableUpdateNotifications: boolean + autoSkipWelcome: boolean +} interface Migration { version: number - migrate: () => Promise + // Each migration returns its result as an `Either` so the surrounding + // `runMigrations` loop, and in turn `init`, can propagate the + // `StoreError` contract without falling back to throws. + migrate: () => Promise> } const migrations: Migration[] = [ { version: 1, - migrate: async () => {}, + migrate: async () => E.right(undefined), + }, + { + // v1 to v2. Introduces `DesktopSettings` as the single source of truth + // for all desktop builds. Portable users had `portableSettings` with two + // fields, standard-build users had nothing. Both land in `desktopSettings` + // with full defaults for any field not carried over. + // + // Legacy `portableSettings` is intentionally left in place. The key + // is cheap to keep, it preserves a rollback path, and a later + // migration can prune it once the v2 definition has stabilized. + version: 2, + migrate: async () => { + // Decide whether to skip based on the existing `desktopSettings` + // payload. Two paths can re-run this migration after it succeeded + // once. A user downgrades to a pre-v2 build, which resets + // `SCHEMA_VERSION` to "1" because the older code does not + // recognize "2" and rolls it back. A re-upgrade then sees v1 + // again and tries to migrate. The other path is a corrupted + // `SCHEMA_VERSION` value, which the `runMigrations` parse-defense + // coerces to "1" so every migration reruns from scratch. In both + // cases, blindly running the legacy carry-forward would + // overwrite any user-set v2 fields with + // `disableUpdateNotifications` plus schema defaults, undoing the + // user's work. + // + // Three reachable cases here, each handled explicitly. A `Left` + // from `Store.get` means the store is degraded (file I/O + // failure, or not yet open) and there is no way to tell whether + // v2 already ran. Propagating the `Left` aborts the migration + // before `runMigrations` bumps `SCHEMA_VERSION`, so the next + // launch retries on a hopefully-recovered store. A `Right` with + // a present and schema-valid payload is the canonical "v2 + // already happened" signal, since the migration itself is what + // writes a valid payload, so a stored value implies the + // migration ran successfully at least once. A `Right` with + // either no payload (fresh install) or a malformed payload + // (partial object, wrong field types) falls through to the + // legacy carry-forward, which writes a fresh schema-defaults + // `desktopSettings` and self-heals the corruption. + const existingResult = await Store.get( + STORE_NAMESPACE, + STORE_KEYS.DESKTOP_SETTINGS + ) + if (E.isLeft(existingResult)) { + return existingResult + } + if ( + existingResult.right !== undefined && + DESKTOP_SETTINGS_SCHEMA.safeParse(existingResult.right).success + ) { + return E.right(undefined) + } + + const legacyResult = await Store.get>( + STORE_NAMESPACE, + STORE_KEYS.PORTABLE_SETTINGS + ) + const legacy = + E.isRight(legacyResult) && legacyResult.right + ? legacyResult.right + : undefined + + // Use `safeParse` with a defaults fallback. `Store.get` returns + // the raw JSON value cast to the generic without validation, so + // a corrupted legacy entry (for example a stringified boolean + // left behind by an older build) would throw from `.parse` and + // abort the full persistence init. Falling back to a fresh + // defaults parse keeps the migration progressing on bad data. + const parsed = DESKTOP_SETTINGS_SCHEMA.safeParse({ + disableUpdateNotifications: legacy?.disableUpdateNotifications, + autoSkipWelcome: legacy?.autoSkipWelcome, + }) + const migrated = parsed.success + ? parsed.data + : DESKTOP_SETTINGS_SCHEMA.parse({}) + + const writeResult = await Store.set( + STORE_NAMESPACE, + STORE_KEYS.DESKTOP_SETTINGS, + migrated + ) + if (E.isLeft(writeResult)) { + // Return Left so `runMigrations` aborts before recording the + // new `SCHEMA_VERSION`. Swallowing here would let the loop + // bump the version despite the failed write, and the next + // launch would treat the data as already migrated and never + // retry. + Log.error( + LOG_TAG, + "v2 migration failed to write desktopSettings", + writeResult.left + ) + return writeResult + } + return E.right(undefined) + }, }, ] +/** + * Facade over the desktop-local persistent store. + * + * Each persistent value is exposed as a `StoreResource`, which + * carries a uniform `{ get, set, watch }` API validated through a Zod + * schema. The service itself is a thin orchestrator. It runs + * schema-version migrations on init, subscribes once to the + * desktop-settings resource so the Rust mailbox stays in sync with any + * writer, and exposes the resources as readonly members. + * + * Callers move from `persistence.setFoo(value)` to `persistence.foo.set(value)` + * and likewise for `get` / `watch`. Compound operations (e.g. adding to the + * recent-instances list) live as free functions over the resource, below. + */ export class DesktopPersistenceService { private static instance: DesktopPersistenceService - private constructor() {} + readonly desktopSettings: StoreResource + readonly updateState: StoreResource + readonly connectionState: StoreResource + readonly recentInstances: StoreResource + + private constructor() { + this.desktopSettings = createStoreResource( + STORE_NAMESPACE, + STORE_KEYS.DESKTOP_SETTINGS, + DESKTOP_SETTINGS_SCHEMA, + () => DESKTOP_SETTINGS_SCHEMA.parse({}) + ) + this.updateState = createStoreResource( + STORE_NAMESPACE, + STORE_KEYS.UPDATE_STATE, + UPDATE_STATE_SCHEMA.nullable(), + () => null + ) + this.connectionState = createStoreResource( + STORE_NAMESPACE, + STORE_KEYS.CONNECTION_STATE, + PERSISTED_CONNECTION_STATE_SCHEMA.nullable(), + () => null + ) + this.recentInstances = createStoreResource( + STORE_NAMESPACE, + STORE_KEYS.RECENT_INSTANCES, + z.array(INSTANCE_SCHEMA), + () => [] + ) + } public static getInstance(): DesktopPersistenceService { if (!DesktopPersistenceService.instance) { @@ -87,176 +257,150 @@ export class DesktopPersistenceService { async init(): Promise> { const initResult = await Store.init() if (E.isLeft(initResult)) { - console.error( - "[PersistenceService] Failed to initialize store:", - initResult.left - ) + Log.error(LOG_TAG, "Failed to initialize store", initResult.left) return initResult } - await this.runMigrations() - return initResult - } - - private async runMigrations() { - const versionResult = await Store.get( - STORE_NAMESPACE, - STORE_KEYS.SCHEMA_VERSION - ) - const perhapsVersion = E.isRight(versionResult) ? versionResult.right : "1" - const currentVersion = perhapsVersion ?? "1" - const targetVersion = "1" - - if (currentVersion !== targetVersion) { - for (const migration of migrations) { - if (migration.version > parseInt(currentVersion)) { - await migration.migrate() - } - } - - await Store.set(STORE_NAMESPACE, STORE_KEYS.SCHEMA_VERSION, targetVersion) + const migrationResult = await this.runMigrations() + if (E.isLeft(migrationResult)) { + return migrationResult } + await this.setupRustSync() + return E.right(undefined) } - async setUpdateState(state: UpdateState): Promise { - const result = await Store.set( - STORE_NAMESPACE, - STORE_KEYS.UPDATE_STATE, - state - ) - if (E.isLeft(result)) { - console.error("Failed to save update state:", result.left) + /** + * Keep the Rust-side `DESKTOP_CONFIG` mailbox (see + * `src-tauri/src/config.rs`) in sync with the desktop settings resource. + * + * Two triggers. An initial push so Rust has the current value + * before any consumer reads it. A subscription to the resource's + * `watch` so every subsequent write from any writer (this shell, + * the webview, another process) gets mirrored. The write-side code + * path stays pure persistence, and the sync is a cross-cutting + * concern handled here. + * + * Both paths swallow failures. Rust already has a compile-time default + * for every field Rust cares about, so a failed sync degrades to + * "Rust reads stale value" rather than a user-visible error. + */ + private async setupRustSync(): Promise { + try { + const initial = await this.desktopSettings.get() + await invoke("set_desktop_config", { config: initial }) + } catch (err) { + Log.warn(LOG_TAG, "Initial DesktopSettings sync to Rust failed", err) } - } - - async getUpdateState(): Promise { - const result = await Store.get( - STORE_NAMESPACE, - STORE_KEYS.UPDATE_STATE - ) - if (E.isRight(result) && result.right) { - return result.right - } - return null - } - async watchUpdateState( - handler: (state: UpdateState) => void - ): Promise<() => void> { - const watcher = await Store.watch(STORE_NAMESPACE, STORE_KEYS.UPDATE_STATE) - return watcher.on("change", ({ value }: { value?: unknown }) => { - if (value) { - handler(value as UpdateState) - } - }) - } - - async setConnectionState(state: ConnectionState): Promise { - const result = await Store.set( - STORE_NAMESPACE, - STORE_KEYS.CONNECTION_STATE, - state - ) - if (E.isLeft(result)) { - console.error("Failed to save connection state:", result.left) - } - } - - async getConnectionState(): Promise { - const result = await Store.get( - STORE_NAMESPACE, - STORE_KEYS.CONNECTION_STATE - ) - if (E.isRight(result) && result.right) { - return result.right - } - return null - } - - async setRecentInstances(instances: Instance[]): Promise { - const result = await Store.set( - STORE_NAMESPACE, - STORE_KEYS.RECENT_INSTANCES, - instances - ) - if (E.isLeft(result)) { - console.error("Failed to save recent instances:", result.left) + try { + await this.desktopSettings.watch((settings) => { + invoke("set_desktop_config", { config: settings }).catch((err) => { + Log.warn(LOG_TAG, "DesktopSettings sync to Rust failed", err) + }) + }) + } catch (err) { + Log.warn( + LOG_TAG, + "Failed to subscribe to DesktopSettings for Rust sync", + err + ) } } - async getRecentInstances(): Promise { - const result = await Store.get( + private async runMigrations(): Promise> { + const versionResult = await Store.get( STORE_NAMESPACE, - STORE_KEYS.RECENT_INSTANCES + STORE_KEYS.SCHEMA_VERSION ) - if (E.isRight(result) && result.right) { - return result.right + const perhapsVersion = E.isRight(versionResult) ? versionResult.right : "1" + const rawVersion = perhapsVersion ?? "1" + // Coerce a corrupted or non-numeric stored value to the lowest known + // version. Without this, `parseInt("v2")` or `parseInt("")` would + // return NaN, every `migration.version > NaN` check below would + // evaluate to false, the loop would skip every migration, and the + // code would still write `SCHEMA_VERSION = "2"` at the end. That + // would mark migrations complete without ever running them. + // Falling back to "1" instead reruns every migration from scratch, + // which is safe because each migration is idempotent on a fresh + // store and a real fresh install lands here through the same path. + const parsedVersion = parseInt(rawVersion, 10) + const currentVersion = Number.isNaN(parsedVersion) ? "1" : rawVersion + const targetVersion = "2" + + if (currentVersion === targetVersion) { + return E.right(undefined) } - return [] - } - async addRecentInstance(instance: Instance): Promise { - const instances = await this.getRecentInstances() - const existingIndex = instances.findIndex( - (i) => i.kind === instance.kind && i.serverUrl === instance.serverUrl - ) - - if (existingIndex >= 0) { - instances[existingIndex] = { - ...instance, - lastUsed: new Date().toISOString(), + for (const migration of migrations) { + if (migration.version > parseInt(currentVersion, 10)) { + const result = await migration.migrate() + if (E.isLeft(result)) { + return result + } } - } else { - instances.unshift({ ...instance, lastUsed: new Date().toISOString() }) } - const sortedInstances = instances - .sort( - (a, b) => - new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime() - ) - .slice(0, 10) - - await this.setRecentInstances(sortedInstances) - } - - async removeRecentInstance(serverUrl: string): Promise { - const instances = await this.getRecentInstances() - const filtered = instances.filter((i) => i.serverUrl !== serverUrl) - await this.setRecentInstances(filtered) - } - - async setPortableSettings(settings: PortableSettings): Promise { - console.log("Setting portable settings:", settings) - const result = await Store.set( + // Record the new version only when the write succeeds. A silent + // failure here would leave the stored version stale, and the next + // launch would re-run every migration on already-migrated data. + const versionWrite = await Store.set( STORE_NAMESPACE, - STORE_KEYS.PORTABLE_SETTINGS, - settings + STORE_KEYS.SCHEMA_VERSION, + targetVersion ) - if (E.isLeft(result)) { - console.error("Failed to save portable settings:", result.left) - throw new Error(`Failed to save portable settings: ${result.left}`) - } else { - console.log("Successfully saved portable settings") + if (E.isLeft(versionWrite)) { + Log.error( + LOG_TAG, + "Failed to persist schema version after migrations", + versionWrite.left + ) + return versionWrite } + return E.right(undefined) } +} - async getPortableSettings(): Promise { - const result = await Store.get( - STORE_NAMESPACE, - STORE_KEYS.PORTABLE_SETTINGS +/** + * Adds an instance to the recent list, preserving the "most-recent-first, + * max 10, deduplicated by kind+serverUrl" invariants. Kept as a free + * function over the resource rather than a method on the service so the + * data-access concern (the resource) stays separate from the business + * rules (dedupe, sort, trim). + */ +export async function addRecentInstance( + recent: StoreResource, + instance: Instance +): Promise { + const current = await recent.get() + const now = new Date().toISOString() + const existingIndex = current.findIndex( + (i) => i.kind === instance.kind && i.serverUrl === instance.serverUrl + ) + + const merged = + existingIndex >= 0 + ? current.map((existing, index) => + index === existingIndex ? { ...instance, lastUsed: now } : existing + ) + : [{ ...instance, lastUsed: now }, ...current] + + const next = [...merged] + .sort( + (a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime() ) + .slice(0, 10) - const defaultSettings = { - disableUpdateNotifications: false, - autoSkipWelcome: false, - } - - if (E.isRight(result) && result.right) { - console.log("Loaded portable settings from store:", result.right) - return result.right - } + await recent.set(next) +} - console.log("No portable settings found, using defaults:", defaultSettings) - return defaultSettings - } +/** + * Removes an instance from the recent list by `serverUrl`. Absent entries + * are silently ignored. + */ +export async function removeRecentInstance( + recent: StoreResource, + serverUrl: string +): Promise { + const current = await recent.get() + const filtered = current.filter((i) => i.serverUrl !== serverUrl) + await recent.set(filtered) } diff --git a/packages/hoppscotch-desktop/src/types/index.ts b/packages/hoppscotch-desktop/src/types/index.ts index 2f44a6d7533..73945441dac 100644 --- a/packages/hoppscotch-desktop/src/types/index.ts +++ b/packages/hoppscotch-desktop/src/types/index.ts @@ -1,39 +1,20 @@ -export interface RecentInstance { - url: string - lastUsed: string - version?: string - pinned: boolean -} - -export interface StoreSchema { - recentInstances: RecentInstance[] -} - -export enum UpdateStatus { - IDLE = "idle", - CHECKING = "checking", - AVAILABLE = "available", - NOT_AVAILABLE = "not_available", - DOWNLOADING = "downloading", - INSTALLING = "installing", - READY_TO_RESTART = "ready_to_restart", - ERROR = "error", -} +// Re-exports of types whose canonical definitions live in common. Listed +// here so in-package imports can keep using `~/types` without every caller +// needing to know the precise module path in common. New types that need to +// cross the shell/webview boundary belong in common directly. +export { + UpdateStatus, + type UpdateState, + type DownloadProgress, +} from "@hoppscotch/common/platform/update-state" +// Not to be confused with `UpdateStatus`. `CheckResult` is the outcome of a +// single call to the updater's `checkForUpdates`, where `UpdateStatus` is +// the full state machine covering checking, downloading, installing, and +// restart. Only `checkForUpdates` returns this. export enum CheckResult { AVAILABLE, NOT_AVAILABLE, TIMEOUT, ERROR, } - -export interface UpdateState { - status: UpdateStatus - version?: string - message?: string -} - -export interface PortableSettings { - disableUpdateNotifications: boolean - autoSkipWelcome: boolean -} diff --git a/packages/hoppscotch-desktop/src/views/Home.vue b/packages/hoppscotch-desktop/src/views/Home.vue index 1f841ec422b..62200c7bad7 100644 --- a/packages/hoppscotch-desktop/src/views/Home.vue +++ b/packages/hoppscotch-desktop/src/views/Home.vue @@ -299,7 +299,7 @@ const loadVendored = async () => { const vendoredInstance: VendoredInstance = { type: "vendored", displayName: "Hoppscotch", - version: "26.3.1", + version: "26.4.0", } const connectionState: ConnectionState = { diff --git a/packages/hoppscotch-desktop/src/views/PortableHome.vue b/packages/hoppscotch-desktop/src/views/PortableHome.vue index fa9910cb0a1..83aadedae24 100644 --- a/packages/hoppscotch-desktop/src/views/PortableHome.vue +++ b/packages/hoppscotch-desktop/src/views/PortableHome.vue @@ -116,7 +116,6 @@ import { close } from "@hoppscotch/plugin-appload" import { invoke } from "@tauri-apps/api/core" import { Io } from "~/kernel" -import type { PortableSettings } from "~/types" import { useAppInitialization, AppState, @@ -143,9 +142,18 @@ const updaterClient = new UpdaterClient() const showPortableWelcome = ref(false) const currentDirectory = ref(".") -const portableSettings = reactive({ +// Fields mirrored locally for the portable welcome screen's UI and the +// startup update gate. The welcome screen only lets the user toggle +// `disableUpdateNotifications` and `autoSkipWelcome`, but the update gate +// also reads `disableUpdateChecks` so a user who set that via the settings +// page on a prior session sees the gate respected on next startup. The full +// desktop settings object is loaded and merged in +// `handlePortableWelcomeContinue` so other fields like timeout or zoom, +// written elsewhere, survive intact. +const portableSettings = reactive({ disableUpdateNotifications: false, autoSkipWelcome: false, + disableUpdateChecks: false, }) watch( @@ -183,26 +191,22 @@ const closeApp = async () => { const handlePortableWelcomeContinue = async () => { try { - console.log( - "About to save portable settings:", - JSON.stringify(portableSettings) - ) - - const settingsToSave: PortableSettings = { + // Read-modify-write against the full `DesktopSettings` object so + // unrelated fields like timeout or zoom, potentially written by the + // webview-side settings page in the same session, are preserved. + const current = await persistence.desktopSettings.get() + const updated = { + ...current, disableUpdateNotifications: portableSettings.disableUpdateNotifications, autoSkipWelcome: portableSettings.autoSkipWelcome, } - console.log("Saving portable settings:", settingsToSave) - await persistence.setPortableSettings(settingsToSave) - - const savedSettings = await persistence.getPortableSettings() - console.log("Verified saved settings:", savedSettings) + await persistence.desktopSettings.set(updated) showPortableWelcome.value = false await loadRecent() } catch (error) { - console.error("Failed to save portable settings:", error) + console.error("Failed to save desktop settings:", error) showPortableWelcome.value = false await loadRecent() } @@ -211,8 +215,18 @@ const handlePortableWelcomeContinue = async () => { const checkForUpdatesPortable = async () => { console.log("Checking portable updates, current settings:", portableSettings) - if (portableSettings.disableUpdateNotifications) { - console.log("Update notifications disabled for portable mode") + // Two disable flags land in this gate for backwards compatibility. The + // legacy `disableUpdateNotifications` was originally documented as + // controlling only notifications but was wired up to skip the whole check + // in portable mode. The new `disableUpdateChecks` is the explicit + // opt-out that matches the settings-page toggle. Either flag being true + // skips the startup check, so users upgrading from a prior version keep + // their original behavior and users who set the new flag see it honored. + if ( + portableSettings.disableUpdateNotifications || + portableSettings.disableUpdateChecks + ) { + console.log("Automatic update check disabled for portable mode") return } @@ -238,14 +252,13 @@ const initializePortableMode = async () => { currentDirectory.value = "." } - const settings = await persistence.getPortableSettings() - console.log("Loaded portable settings:", settings) + const settings = await persistence.desktopSettings.get() + console.log("Loaded desktop settings:", settings) portableSettings.disableUpdateNotifications = settings.disableUpdateNotifications portableSettings.autoSkipWelcome = settings.autoSkipWelcome - - console.log("Updated reactive portableSettings:", portableSettings) + portableSettings.disableUpdateChecks = settings.disableUpdateChecks await checkForUpdatesPortable() diff --git a/packages/hoppscotch-desktop/src/views/StandardHome.vue b/packages/hoppscotch-desktop/src/views/StandardHome.vue index e0a89e3aa26..f43068f4f15 100644 --- a/packages/hoppscotch-desktop/src/views/StandardHome.vue +++ b/packages/hoppscotch-desktop/src/views/StandardHome.vue @@ -50,6 +50,7 @@ import { type UpdateEvent, type DownloadProgress, } from "~/services/updater.client" +import { DesktopPersistenceService } from "~/services/persistence.service" import AppHeader from "./shared/AppHeader.vue" import LoadingState from "./shared/LoadingState.vue" @@ -145,10 +146,22 @@ const checkForUpdates = async () => { } const initializeStandardMode = async () => { - const hasUpdates = await checkForUpdates() - if (!hasUpdates) { - await loadRecent() + // The settings page's `disableUpdateChecks` toggle governs the automatic + // startup check, not the manual "Check for updates" button in settings. + // Reading the setting here lets air-gapped and enterprise-network users + // skip the 5-second timeout retry on every launch. They can still trigger + // a check on demand from the settings page whenever they want. + const persistence = DesktopPersistenceService.getInstance() + const settings = await persistence.desktopSettings.get() + + if (!settings.disableUpdateChecks) { + const hasUpdates = await checkForUpdates() + if (hasUpdates) { + return + } } + + await loadRecent() } onMounted(async () => { diff --git a/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue b/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue index 71d47852c30..1359145f724 100644 --- a/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue +++ b/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue @@ -88,6 +88,7 @@ interface Props { withDefaults(defineProps(), { message: "", + progress: undefined, showProgress: true, showCancel: false, }) diff --git a/packages/hoppscotch-js-sandbox/package.json b/packages/hoppscotch-js-sandbox/package.json index 5e059f5fa04..474b3b2df44 100644 --- a/packages/hoppscotch-js-sandbox/package.json +++ b/packages/hoppscotch-js-sandbox/package.json @@ -55,8 +55,8 @@ "chai": "6.2.2", "faraday-cage": "0.1.0", "fp-ts": "2.16.11", - "lodash": "4.17.23", - "lodash-es": "4.17.23" + "lodash": "4.18.1", + "lodash-es": "4.18.1" }, "devDependencies": { "@digitak/esrun": "3.2.26", @@ -67,17 +67,17 @@ "@types/jest": "30.0.0", "@types/lodash": "4.17.24", "@types/node": "24.10.1", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", "eslint": "9.39.2", "eslint-config-prettier": "10.1.8", "eslint-plugin-prettier": "5.5.5", "globals": "16.5.0", "io-ts": "2.2.22", - "prettier": "3.8.1", + "prettier": "3.8.3", "typescript": "5.9.3", - "vite": "7.3.1", - "vitest": "4.1.2" + "vite": "7.3.2", + "vitest": "4.1.5" }, "peerDependencies": { "isolated-vm": "6.1.2" diff --git a/packages/hoppscotch-js-sandbox/src/__tests__/combined/script-execution-error-propagation.spec.ts b/packages/hoppscotch-js-sandbox/src/__tests__/combined/script-execution-error-propagation.spec.ts new file mode 100644 index 00000000000..23c158a35a8 --- /dev/null +++ b/packages/hoppscotch-js-sandbox/src/__tests__/combined/script-execution-error-propagation.spec.ts @@ -0,0 +1,99 @@ +import { describe, expect, test } from "vitest" +import { runPreRequest, runTest } from "~/utils/test-helpers" + +/** + * The experimental sandbox silently swallowed top-level throws inside the + * generated `await (async function(){...})()` wrapper. The fix routes the + * error through a lexically-captured host reporter installed by bootstrap, + * read back on the host side as the Left branch of the TaskEither pipeline. + * + * These tests exercise the sandbox contract directly by reproducing the + * generated wrapper shape that `combineScriptsWithIIFE` emits from + * `@hoppscotch/cli` and `@hoppscotch/common`. + */ +describe("script execution error propagation", () => { + const envs = { global: [], selected: [] } + + // Mirrors `combineScriptsWithIIFE("experimental")` in the CLI and common + // packages. Kept local to avoid a cross-package import. + const wrapExperimental = (body: string): string => + [ + "const __hoppReporter = globalThis.__hoppReportScriptExecutionError;", + "try {", + `await (async function() {\n${body}\n})();`, + "} catch (__hoppScriptExecutionError) {", + " __hoppReporter(__hoppScriptExecutionError);", + "}", + ].join("\n") + + test("experimental pre-request: synchronous top-level throw returns Left", async () => { + const script = wrapExperimental( + `throw new Error("pre-request top-level throw");` + ) + + const result = await runPreRequest(script, envs)() + + expect(result).toBeLeft() + if (result._tag === "Left") { + expect(result.left).toContain("pre-request top-level throw") + } + }) + + test("experimental pre-request: rejected await inside IIFE returns Left", async () => { + const script = wrapExperimental( + `await Promise.reject(new Error("pre-request rejected await"));` + ) + + const result = await runPreRequest(script, envs)() + + expect(result).toBeLeft() + if (result._tag === "Left") { + expect(result.left).toContain("pre-request rejected await") + } + }) + + test("experimental pre-request: valid script still returns Right", async () => { + const script = wrapExperimental(`pw.env.set("FLAG", "ok");`) + + const result = await runPreRequest(script, envs)() + + expect(result).toBeRight() + }) + + test("experimental test-runner: synchronous top-level throw returns Left", async () => { + const script = wrapExperimental( + `throw new Error("test-runner top-level throw");` + ) + + const result = await runTest(script, envs)() + + expect(result).toBeLeft() + if (result._tag === "Left") { + expect(result.left).toContain("test-runner top-level throw") + } + }) + + test("user script cannot tamper with the reporter to suppress error reporting", async () => { + // User script attempts to delete + overwrite the globalThis reporter + // before throwing; both defenses (immutable property + lexical capture + // in the wrapper) keep the report path intact. + const script = wrapExperimental( + ` + try { + delete globalThis.__hoppReportScriptExecutionError; + globalThis.__hoppReportScriptExecutionError = () => {}; + } catch (_e) { + // strict mode may throw on immutable-property tamper; ignore + } + throw new Error("tamper-attempt throw"); + ` + ) + + const result = await runPreRequest(script, envs)() + + expect(result).toBeLeft() + if (result._tag === "Left") { + expect(result.left).toContain("tamper-attempt throw") + } + }) +}) diff --git a/packages/hoppscotch-js-sandbox/src/bootstrap-code/post-request.js b/packages/hoppscotch-js-sandbox/src/bootstrap-code/post-request.js index 17a357e4d11..0486334fa49 100644 --- a/packages/hoppscotch-js-sandbox/src/bootstrap-code/post-request.js +++ b/packages/hoppscotch-js-sandbox/src/bootstrap-code/post-request.js @@ -3,6 +3,27 @@ // Keep strict mode scoped to this IIFE to avoid leaking strictness to concatenated/bootstrapped code "use strict" + // Exposes a host reporter for the generated experimental `try/catch` + // wrapper in combineScriptsWithIIFE. Locked down (non-writable, + // non-configurable) so user scripts cannot delete or overwrite it to + // suppress error reporting. faraday-cage's `runCode` creates a fresh + // QuickJS runtime per call, so re-definition across calls is not a + // concern — the property lives only for the current run's VM. + Object.defineProperty(globalThis, "__hoppReportScriptExecutionError", { + value: (error) => { + const safe = error && typeof error === "object" ? error : {} + inputs.setScriptExecutionError({ + name: typeof safe.name === "string" ? safe.name : "", + message: + typeof safe.message === "string" ? safe.message : String(error), + stack: typeof safe.stack === "string" ? safe.stack : "", + }) + }, + enumerable: false, + configurable: false, + writable: false, + }) + // Sequential test execution promise chain // Initialize with a resolved promise to start the chain // Store on globalThis so pm.sendRequest() and test() can both access and modify it diff --git a/packages/hoppscotch-js-sandbox/src/bootstrap-code/pre-request.js b/packages/hoppscotch-js-sandbox/src/bootstrap-code/pre-request.js index 28477245aa3..4f41249f759 100644 --- a/packages/hoppscotch-js-sandbox/src/bootstrap-code/pre-request.js +++ b/packages/hoppscotch-js-sandbox/src/bootstrap-code/pre-request.js @@ -2,6 +2,28 @@ ;(inputs) => { // Keep strict mode scoped to this IIFE to avoid leaking strictness to concatenated/bootstrapped code "use strict" + + // Exposes a host reporter for the generated experimental `try/catch` + // wrapper in combineScriptsWithIIFE. Locked down (non-writable, + // non-configurable) so user scripts cannot delete or overwrite it to + // suppress error reporting. faraday-cage's `runCode` creates a fresh + // QuickJS runtime per call, so re-definition across calls is not a + // concern — the property lives only for the current run's VM. + Object.defineProperty(globalThis, "__hoppReportScriptExecutionError", { + value: (error) => { + const safe = error && typeof error === "object" ? error : {} + inputs.setScriptExecutionError({ + name: typeof safe.name === "string" ? safe.name : "", + message: + typeof safe.message === "string" ? safe.message : String(error), + stack: typeof safe.stack === "string" ? safe.stack : "", + }) + }, + enumerable: false, + configurable: false, + writable: false, + }) + globalThis.pw = { env: { get: (key) => convertMarkerToValue(inputs.envGet(key)), diff --git a/packages/hoppscotch-js-sandbox/src/cage-modules/scripting-modules.ts b/packages/hoppscotch-js-sandbox/src/cage-modules/scripting-modules.ts index fe818528c16..342b497b2c2 100644 --- a/packages/hoppscotch-js-sandbox/src/cage-modules/scripting-modules.ts +++ b/packages/hoppscotch-js-sandbox/src/cage-modules/scripting-modules.ts @@ -386,7 +386,11 @@ const createScriptingModule = ( type: ModuleType, bootstrapCode: string, config: ModuleConfig, - captureHook?: { capture?: () => void; bootstrapError?: unknown } + captureHook?: { + capture?: () => void + bootstrapError?: unknown + scriptExecutionError?: { name: string; message: string; stack: string } + } ) => { return defineCageModule((ctx) => { // Track test promises for keepAlive (only for post-request scripts) @@ -471,6 +475,27 @@ const createScriptingModule = ( } } + // Reporter invoked from the generated `catch` block that wraps the + // experimental IIFE chain. This is a synchronous host callback — unlike + // rejected keepAlive promises or async afterScriptExecutionHooks, these + // calls cross the QuickJS boundary before the script returns, so the + // host sees the error without relying on faraday-cage's loop behaviour. + ;(inputsObj as Record).setScriptExecutionError = + defineSandboxFn(ctx, "setScriptExecutionError", (error: unknown) => { + if (!captureHook || captureHook.scriptExecutionError) return + const err = (error ?? {}) as { + name?: unknown + message?: unknown + stack?: unknown + } + captureHook.scriptExecutionError = { + name: typeof err.name === "string" ? err.name : "", + message: + typeof err.message === "string" ? err.message : String(error), + stack: typeof err.stack === "string" ? err.stack : "", + } + }) + const sandboxInputsObj = defineSandboxObject(ctx, inputsObj) const bootstrapResult = ctx.vm.callFunction( diff --git a/packages/hoppscotch-js-sandbox/src/node/pre-request/experimental.ts b/packages/hoppscotch-js-sandbox/src/node/pre-request/experimental.ts index 6068a2ab468..945302bc0c8 100644 --- a/packages/hoppscotch-js-sandbox/src/node/pre-request/experimental.ts +++ b/packages/hoppscotch-js-sandbox/src/node/pre-request/experimental.ts @@ -23,7 +23,11 @@ const executePreRequestOnCage = async ( let finalRequest = request let finalCookies = cookies - const captureHook: { capture?: () => void; bootstrapError?: unknown } = {} + const captureHook: { + capture?: () => void + bootstrapError?: unknown + scriptExecutionError?: { name: string; message: string; stack: string } + } = {} const result = await cage.runCode(preRequestScript, [ ...defaultModules({ @@ -72,6 +76,16 @@ const executePreRequestOnCage = async ( return E.left(`Script execution failed: ${String(result.err)}`) } + // Check for errors reported via the generated try/catch wrapper. + // faraday-cage's keepAlive loop swallows rejected promises and does not + // await afterScriptExecutionHooks, so async-boundary errors reach us + // only via this synchronous host reporter. + if (captureHook.scriptExecutionError) { + const { name, message } = captureHook.scriptExecutionError + const prefix = name ? `${name}: ` : "" + return E.left(`Script execution failed: ${prefix}${message}`) + } + if (captureHook.capture) { captureHook.capture() } diff --git a/packages/hoppscotch-js-sandbox/src/node/test-runner/experimental.ts b/packages/hoppscotch-js-sandbox/src/node/test-runner/experimental.ts index d06bf920f3a..a5b656856c5 100644 --- a/packages/hoppscotch-js-sandbox/src/node/test-runner/experimental.ts +++ b/packages/hoppscotch-js-sandbox/src/node/test-runner/experimental.ts @@ -32,7 +32,11 @@ const executeTestOnCage = async ( let finalTestResults = testRunStack const testPromises: Promise[] = [] - const captureHook: { capture?: () => void; bootstrapError?: unknown } = {} + const captureHook: { + capture?: () => void + bootstrapError?: unknown + scriptExecutionError?: { name: string; message: string; stack: string } + } = {} const result = await cage.runCode(testScript, [ ...defaultModules({ @@ -92,6 +96,16 @@ const executeTestOnCage = async ( } } + // Check for errors reported via the generated try/catch wrapper. + // faraday-cage's keepAlive loop swallows rejected promises and does not + // await afterScriptExecutionHooks, so async-boundary errors reach us + // only via this synchronous host reporter. + if (captureHook.scriptExecutionError) { + const { name, message } = captureHook.scriptExecutionError + const prefix = name ? `${name}: ` : "" + return E.left(`Script execution failed: ${prefix}${message}`) + } + if (captureHook.capture) { captureHook.capture() } diff --git a/packages/hoppscotch-js-sandbox/src/web/pre-request/index.ts b/packages/hoppscotch-js-sandbox/src/web/pre-request/index.ts index c80815b3c53..6cf6d6132f2 100644 --- a/packages/hoppscotch-js-sandbox/src/web/pre-request/index.ts +++ b/packages/hoppscotch-js-sandbox/src/web/pre-request/index.ts @@ -53,7 +53,11 @@ const executePreRequestOnCage = async ( let finalRequest = request let finalCookies = cookies - const captureHook: { capture?: () => void; bootstrapError?: unknown } = {} + const captureHook: { + capture?: () => void + bootstrapError?: unknown + scriptExecutionError?: { name: string; message: string; stack: string } + } = {} const result = await cage.runCode(preRequestScript, [ ...defaultModules({ @@ -103,6 +107,16 @@ const executePreRequestOnCage = async ( return E.left(`Script execution failed: ${String(result.err)}`) } + // Check for errors reported via the generated try/catch wrapper. + // faraday-cage's keepAlive loop swallows rejected promises and does not + // await afterScriptExecutionHooks, so async-boundary errors reach us + // only via this synchronous host reporter. + if (captureHook.scriptExecutionError) { + const { name, message } = captureHook.scriptExecutionError + const prefix = name ? `${name}: ` : "" + return E.left(`Script execution failed: ${prefix}${message}`) + } + if (captureHook.capture) { captureHook.capture() } diff --git a/packages/hoppscotch-js-sandbox/src/web/test-runner/index.ts b/packages/hoppscotch-js-sandbox/src/web/test-runner/index.ts index d9ee9854e1b..73d5b87df3e 100644 --- a/packages/hoppscotch-js-sandbox/src/web/test-runner/index.ts +++ b/packages/hoppscotch-js-sandbox/src/web/test-runner/index.ts @@ -62,7 +62,11 @@ const executeTestOnCage = async ( let finalCookies = cookies const testPromises: Promise[] = [] - const captureHook: { capture?: () => void; bootstrapError?: unknown } = {} + const captureHook: { + capture?: () => void + bootstrapError?: unknown + scriptExecutionError?: { name: string; message: string; stack: string } + } = {} const result = await cage.runCode(testScript, [ ...defaultModules({ @@ -122,6 +126,16 @@ const executeTestOnCage = async ( await Promise.all(testPromises) } + // Check for errors reported via the generated try/catch wrapper. + // faraday-cage's keepAlive loop swallows rejected promises and does not + // await afterScriptExecutionHooks, so async-boundary errors reach us + // only via this synchronous host reporter. + if (captureHook.scriptExecutionError) { + const { name, message } = captureHook.scriptExecutionError + const prefix = name ? `${name}: ` : "" + return E.left(`Script execution failed: ${prefix}${message}`) + } + if (captureHook.capture) { captureHook.capture() } diff --git a/packages/hoppscotch-kernel/package.json b/packages/hoppscotch-kernel/package.json index 3bae3fcf036..4c3c2c580a9 100644 --- a/packages/hoppscotch-kernel/package.json +++ b/packages/hoppscotch-kernel/package.json @@ -41,13 +41,13 @@ "devDependencies": { "@eslint/js": "9.39.2", "@types/node": "24.9.1", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", "globals": "16.5.0", "typescript": "5.9.3", - "vite": "7.3.1" + "vite": "7.3.2" }, "peerDependencies": { "@tauri-apps/api": "2.1.1" @@ -58,13 +58,13 @@ } }, "dependencies": { - "@hoppscotch/plugin-relay": "github:CuriousCorrelation/tauri-plugin-relay#7cf09c1ad31e228758738c2f4e1c8fe9cc141291", + "@hoppscotch/plugin-relay": "github:CuriousCorrelation/tauri-plugin-relay#42f449e1c5657679fecf0374b0ce5047ad03c069", "@tauri-apps/plugin-dialog": "2.0.1", "@tauri-apps/plugin-fs": "2.0.2", "@tauri-apps/plugin-shell": "2.3.3", "@tauri-apps/plugin-store": "2.4.1", "aws4fetch": "1.0.20", - "axios": "1.13.6", + "axios": "1.15.2", "fp-ts": "2.16.11", "superjson": "2.2.6", "zod": "3.25.32" diff --git a/packages/hoppscotch-selfhost-web/package.json b/packages/hoppscotch-selfhost-web/package.json index 035a32ddf65..60541e25fdb 100644 --- a/packages/hoppscotch-selfhost-web/package.json +++ b/packages/hoppscotch-selfhost-web/package.json @@ -1,7 +1,7 @@ { "name": "@hoppscotch/selfhost-web", "private": true, - "version": "2026.3.1", + "version": "2026.4.0", "type": "module", "scripts": { "dev:vite": "vite", @@ -24,7 +24,7 @@ }, "dependencies": { "@fontsource-variable/inter": "5.2.8", - "@fontsource-variable/material-symbols-rounded": "5.2.38", + "@fontsource-variable/material-symbols-rounded": "5.2.43", "@fontsource-variable/roboto-mono": "5.2.8", "@hoppscotch/common": "workspace:^", "@hoppscotch/data": "workspace:^", @@ -37,7 +37,7 @@ "@tauri-apps/plugin-fs": "2.0.2", "@tauri-apps/plugin-shell": "2.3.3", "@vueuse/core": "14.2.1", - "axios": "1.13.6", + "axios": "1.15.2", "buffer": "6.0.3", "dioc": "3.0.2", "fp-ts": "2.16.11", @@ -46,45 +46,45 @@ "stream-browserify": "3.0.0", "util": "0.12.5", "verzod": "0.4.0", - "vue": "3.5.31", + "vue": "3.5.33", "workbox-window": "7.4.0", "zod": "3.25.32" }, "devDependencies": { "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.2", - "@graphql-codegen/add": "6.0.0", - "@graphql-codegen/cli": "6.2.1", - "@graphql-codegen/typed-document-node": "6.1.7", - "@graphql-codegen/typescript": "5.0.9", - "@graphql-codegen/typescript-operations": "5.0.9", + "@graphql-codegen/add": "6.0.1", + "@graphql-codegen/cli": "6.3.1", + "@graphql-codegen/typed-document-node": "6.1.8", + "@graphql-codegen/typescript": "5.0.10", + "@graphql-codegen/typescript-operations": "5.1.0", "@graphql-codegen/typescript-urql-graphcache": "3.1.1", "@graphql-codegen/urql-introspection": "3.0.1", "@graphql-typed-document-node/core": "3.2.0", - "@iconify-json/lucide": "1.2.99", - "@intlify/unplugin-vue-i18n": "11.0.7", + "@iconify-json/lucide": "1.2.104", + "@intlify/unplugin-vue-i18n": "11.1.2", "@rushstack/eslint-patch": "1.16.1", - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", "@vitejs/plugin-legacy": "7.2.1", - "@vitejs/plugin-vue": "6.0.5", + "@vitejs/plugin-vue": "6.0.6", "@vue/eslint-config-typescript": "14.7.0", - "autoprefixer": "10.4.27", + "autoprefixer": "10.5.0", "cross-env": "10.1.0", - "dotenv": "17.3.1", + "dotenv": "17.4.2", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", - "eslint-plugin-vue": "10.8.0", + "eslint-plugin-vue": "10.9.0", "globals": "16.5.0", "npm-run-all": "4.1.5", - "postcss": "8.5.8", + "postcss": "8.5.10", "prettier-plugin-tailwindcss": "0.7.2", "tailwindcss": "3.4.16", "typescript": "5.9.3", "unplugin-fonts": "1.4.0", "unplugin-icons": "22.5.0", "unplugin-vue-components": "30.0.0", - "vite": "7.3.1", + "vite": "7.3.2", "vite-plugin-fonts": "0.7.0", "vite-plugin-html-config": "2.0.2", "vite-plugin-inspect": "11.3.3", diff --git a/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts b/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts index 3581daf4cd7..812093eaf13 100644 --- a/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts +++ b/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts @@ -22,8 +22,11 @@ let _isRunningDispatchWithoutSyncing = true export function runDispatchWithOutSyncing(func: () => void) { _isRunningDispatchWithoutSyncing = false - func() - _isRunningDispatchWithoutSyncing = true + try { + func() + } finally { + _isRunningDispatchWithoutSyncing = true + } } export const getSyncInitFunction = >( diff --git a/packages/hoppscotch-selfhost-web/src/main.ts b/packages/hoppscotch-selfhost-web/src/main.ts index 9cb82be0245..b03f7ee5fb4 100644 --- a/packages/hoppscotch-selfhost-web/src/main.ts +++ b/packages/hoppscotch-selfhost-web/src/main.ts @@ -27,6 +27,8 @@ import { InfraPlatform } from "@app/platform/infra/infra.platform" import { kernelIO } from "@hoppscotch/common/platform/std/kernel-io" import { HeaderDownloadableLinksService } from "@app/services/headerDownloadableLinks.service" +import DesktopSettingsSection from "@hoppscotch/common/components/settings/Desktop.vue" + // Std interceptors import { NativeKernelInterceptorService } from "@hoppscotch/common/platform/std/kernel-interceptors/native" import { AgentKernelInterceptorService } from "@hoppscotch/common/platform/std/kernel-interceptors/agent" @@ -142,6 +144,12 @@ async function initApp() { ui: { additionalFooterMenuItems: config.menuItems, additionalSupportOptionsMenuItems: config.supportItems, + // Desktop-only. Renders the "Desktop" block in the shared settings + // page. The component lives in common so every shell that builds a + // Tauri desktop target can register it the same way. Web builds pass + // `undefined` here and the settings page renders without the block. + additionalSettingsSections: + platform === "desktop" ? [DesktopSettingsSection] : undefined, appHeader: { paddingLeft: headerPaddingLeft, paddingTop: headerPaddingTop, diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/gqlCollections.sync.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/gqlCollections.sync.ts index ccfa7533a1e..c1144d98a94 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/gqlCollections.sync.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/gqlCollections.sync.ts @@ -45,6 +45,9 @@ const transformCollectionForBackend = (collection: HoppCollection): any => { headers: collection.headers ?? [], variables: collection.variables ?? [], _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } return { @@ -79,6 +82,9 @@ const recursivelySyncCollections = async ( headers: collection.headers ?? [], variables: collection.variables ?? [], _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createGQLRootUserCollection( collection.name, @@ -98,6 +104,9 @@ const recursivelySyncCollections = async ( headers: [], variables: [], _ref_id: collection._ref_id ?? generateUniqueRefId("coll"), + description: null, + preRequestScript: "", + testScript: "", } collection.id = parentCollectionID @@ -105,6 +114,9 @@ const recursivelySyncCollections = async ( collection.headers = returnedData.headers collection.variables = returnedData.variables collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll") + collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateGraphqlCollectionOrFolder( parentCollectionID, @@ -124,6 +136,9 @@ const recursivelySyncCollections = async ( headers: collection.headers ?? [], variables: collection.variables ?? [], _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createGQLChildUserCollection( @@ -145,6 +160,9 @@ const recursivelySyncCollections = async ( headers: [], variables: [], _ref_id: collection._ref_id ?? generateUniqueRefId("coll"), + description: null, + preRequestScript: "", + testScript: "", } collection.id = childCollectionId @@ -153,6 +171,9 @@ const recursivelySyncCollections = async ( parentCollectionID = childCollectionId collection.variables = returnedData.variables collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll") + collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateGraphqlCollectionOrFolder( childCollectionId, @@ -268,6 +289,9 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< headers: collection.headers, variables: collection.variables, _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } if (collectionID) { @@ -314,6 +338,9 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< headers: folder.headers, variables: folder.variables, _ref_id: folder._ref_id, + description: folder.description ?? null, + preRequestScript: folder.preRequestScript ?? "", + testScript: folder.testScript ?? "", } if (folderBackendId) { diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/index.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/index.ts index 88ced2217fa..bd2452c61e5 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/index.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/index.ts @@ -141,12 +141,14 @@ export function exportedCollectionToHoppCollection( _ref_id: generateUniqueRefId("coll"), variables: [], description: null, + preRequestScript: "", + testScript: "", } return { id: restCollection.id, _ref_id: data._ref_id ?? generateUniqueRefId("coll"), - v: 11, + v: 12, name: restCollection.name, folders: restCollection.folders.map((folder) => exportedCollectionToHoppCollection(folder, collectionType) @@ -200,6 +202,8 @@ export function exportedCollectionToHoppCollection( headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", } } else { const gqlCollection = collection as ExportedUserCollectionGQL @@ -213,12 +217,14 @@ export function exportedCollectionToHoppCollection( _ref_id: generateUniqueRefId("coll"), variables: [], description: null, + preRequestScript: "", + testScript: "", } return { id: gqlCollection.id, _ref_id: data._ref_id ?? generateUniqueRefId("coll"), - v: 11, + v: 12, name: gqlCollection.name, folders: gqlCollection.folders.map((folder) => exportedCollectionToHoppCollection(folder, collectionType) @@ -248,6 +254,8 @@ export function exportedCollectionToHoppCollection( headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", } } } @@ -398,6 +406,9 @@ function setupUserCollectionCreatedSubscription() { headers: [], _ref_id: generateUniqueRefId("coll"), variables: [], + description: null, + preRequestScript: "", + testScript: "", } runDispatchWithOutSyncing(() => { @@ -406,23 +417,27 @@ function setupUserCollectionCreatedSubscription() { name: res.right.userCollectionCreated.title, folders: [], requests: [], - v: 11, + v: 12, _ref_id: data._ref_id, auth: data.auth, headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", }) : addRESTCollection({ name: res.right.userCollectionCreated.title, folders: [], requests: [], - v: 11, + v: 12, _ref_id: data._ref_id, auth: data.auth, headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", }) const localIndex = collectionStore.value.state.length - 1 @@ -625,7 +640,14 @@ function setupUserCollectionDuplicatedSubscription() { ) // Incoming data transformed to the respective internal representations - const { auth, headers, variables, description } = + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = data && data != "null" ? JSON.parse(data) : { @@ -633,6 +655,8 @@ function setupUserCollectionDuplicatedSubscription() { headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", } // Duplicated collection will have a unique ref id const _ref_id = generateUniqueRefId("coll") @@ -649,12 +673,14 @@ function setupUserCollectionDuplicatedSubscription() { name, folders, requests, - v: 11, + v: 12, _ref_id, auth, headers: addDescriptionField(headers), variables: variables ?? [], description: description ?? null, + preRequestScript: preRequestScript ?? "", + testScript: testScript ?? "", } // only folders will have parent collection id @@ -1122,7 +1148,14 @@ function transformDuplicatedCollections( requests: userRequests, title: name, }) => { - const { auth, headers, variables, description } = + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = data && data !== "null" ? JSON.parse(data) : { @@ -1130,6 +1163,8 @@ function transformDuplicatedCollections( headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", } const _ref_id = generateUniqueRefId("coll") @@ -1144,11 +1179,13 @@ function transformDuplicatedCollections( folders, requests, _ref_id, - v: 11, + v: 12, auth, headers: addDescriptionField(headers), variables: variables ?? [], description: description ?? null, + preRequestScript: preRequestScript ?? "", + testScript: testScript ?? "", } } ) diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/sync.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/sync.ts index 32fbdc6d2b7..9e0d44bf178 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/sync.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/desktop/sync.ts @@ -48,6 +48,8 @@ const transformCollectionForBackend = (collection: HoppCollection): any => { variables: collection.variables ?? [], _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } return { @@ -83,6 +85,8 @@ const recursivelySyncCollections = async ( variables: collection.variables ?? [], _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createRESTRootUserCollection( collection.name, @@ -102,6 +106,8 @@ const recursivelySyncCollections = async ( variables: [], _ref_id: generateUniqueRefId("coll"), description: null, + preRequestScript: "", + testScript: "", } collection.id = parentCollectionID @@ -110,6 +116,9 @@ const recursivelySyncCollections = async ( collection.headers = returnedData.headers collection.variables = returnedData.variables collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" + removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath) } else { parentCollectionID = undefined @@ -125,6 +134,8 @@ const recursivelySyncCollections = async ( variables: collection.variables ?? [], _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createRESTChildUserCollection( @@ -147,6 +158,8 @@ const recursivelySyncCollections = async ( variables: [], _ref_id: generateUniqueRefId("coll"), description: null, + preRequestScript: "", + testScript: "", } collection.id = childCollectionId @@ -156,6 +169,8 @@ const recursivelySyncCollections = async ( parentCollectionID = childCollectionId collection.variables = returnedData.variables collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateRESTCollectionOrFolder( childCollectionId, @@ -268,6 +283,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< variables: collection.variables, _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } if (collectionID) { @@ -351,6 +368,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< variables: folder.variables, _ref_id: folder._ref_id, description: folder.description ?? null, + preRequestScript: folder.preRequestScript ?? "", + testScript: folder.testScript ?? "", } if (folderID) { updateUserCollection(folderID, folderName, JSON.stringify(data)) diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/web/gqlCollections.sync.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/web/gqlCollections.sync.ts index 5f50988d4a1..8151d011a7d 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/web/gqlCollections.sync.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/web/gqlCollections.sync.ts @@ -45,6 +45,9 @@ const transformCollectionForBackend = (collection: HoppCollection): any => { headers: collection.headers ?? [], variables: collection.variables ?? [], _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } return { @@ -79,6 +82,9 @@ const recursivelySyncCollections = async ( headers: collection.headers ?? [], variables: collection.variables ?? [], _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createGQLRootUserCollection( collection.name, @@ -98,6 +104,9 @@ const recursivelySyncCollections = async ( headers: [], variables: [], _ref_id: generateUniqueRefId("coll"), + description: null, + preRequestScript: "", + testScript: "", } collection.id = parentCollectionID @@ -105,6 +114,9 @@ const recursivelySyncCollections = async ( collection.auth = returnedData.auth collection.headers = returnedData.headers collection.variables = returnedData.variables + collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateGraphqlCollectionOrFolder( parentCollectionID, @@ -124,6 +136,9 @@ const recursivelySyncCollections = async ( headers: collection.headers ?? [], variables: collection.variables ?? [], _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createGQLChildUserCollection( @@ -145,6 +160,9 @@ const recursivelySyncCollections = async ( headers: [], variables: [], _ref_id: generateUniqueRefId("coll"), + description: null, + preRequestScript: "", + testScript: "", } collection.id = childCollectionId @@ -153,6 +171,9 @@ const recursivelySyncCollections = async ( collection.headers = returnedData.headers parentCollectionID = childCollectionId collection.variables = returnedData.variables + collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateGraphqlCollectionOrFolder( childCollectionId, @@ -268,6 +289,9 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< headers: collection.headers, variables: collection.variables, _ref_id: collection._ref_id, + description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } if (collectionID) { @@ -314,6 +338,9 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< headers: folder.headers, variables: folder.variables, _ref_id: folder._ref_id, + description: folder.description ?? null, + preRequestScript: folder.preRequestScript ?? "", + testScript: folder.testScript ?? "", } if (folderBackendId) { diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/web/import.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/web/import.ts index 39834a27e0c..8ae5154f7e1 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/web/import.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/web/import.ts @@ -70,6 +70,8 @@ export function translateToPersonalCollectionFormat(x: HoppCollection) { headers: x.headers, variables: x.variables, description: x.description, + preRequestScript: x.preRequestScript ?? "", + testScript: x.testScript ?? "", } const obj = { diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/web/index.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/web/index.ts index a018b795de6..631fb3e9aef 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/web/index.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/web/index.ts @@ -142,12 +142,14 @@ export function exportedCollectionToHoppCollection( _ref_id: generateUniqueRefId("coll"), variables: [], description: null, + preRequestScript: "", + testScript: "", } return { id: restCollection.id, _ref_id: data._ref_id ?? generateUniqueRefId("coll"), - v: 11, + v: 12, name: restCollection.name, folders: restCollection.folders.map((folder) => exportedCollectionToHoppCollection(folder, collectionType) @@ -201,6 +203,8 @@ export function exportedCollectionToHoppCollection( auth: data.auth, headers: addDescriptionField(data.headers), variables: data.variables ?? [], + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", } } else { const gqlCollection = collection as ExportedUserCollectionGQL @@ -219,7 +223,7 @@ export function exportedCollectionToHoppCollection( return { id: gqlCollection.id, _ref_id: data._ref_id ?? generateUniqueRefId("coll"), - v: 11, + v: 12, name: gqlCollection.name, folders: gqlCollection.folders.map((folder) => exportedCollectionToHoppCollection(folder, collectionType) @@ -249,6 +253,8 @@ export function exportedCollectionToHoppCollection( headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", } } } @@ -400,6 +406,8 @@ function setupUserCollectionCreatedSubscription() { _ref_id: generateUniqueRefId("coll"), variables: [], description: null, + preRequestScript: "", + testScript: "", } runDispatchWithOutSyncing(() => { @@ -408,23 +416,27 @@ function setupUserCollectionCreatedSubscription() { name: res.right.userCollectionCreated.title, folders: [], requests: [], - v: 11, + v: 12, _ref_id: data._ref_id, auth: data.auth, headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", }) : addRESTCollection({ name: res.right.userCollectionCreated.title, folders: [], requests: [], - v: 11, + v: 12, _ref_id: data._ref_id, auth: data.auth, headers: addDescriptionField(data.headers), variables: data.variables ?? [], description: data.description ?? null, + preRequestScript: data.preRequestScript ?? "", + testScript: data.testScript ?? "", }) const localIndex = collectionStore.value.state.length - 1 @@ -627,7 +639,14 @@ function setupUserCollectionDuplicatedSubscription() { ) // Incoming data transformed to the respective internal representations - const { auth, headers, variables, description } = + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = data && data != "null" ? JSON.parse(data) : { @@ -635,6 +654,8 @@ function setupUserCollectionDuplicatedSubscription() { headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", } // Duplicated collection will have a unique ref id const _ref_id = generateUniqueRefId("coll") @@ -651,12 +672,14 @@ function setupUserCollectionDuplicatedSubscription() { name, folders, requests, - v: 11, + v: 12, _ref_id, auth, headers: addDescriptionField(headers), variables: variables ?? [], description: description ?? null, + preRequestScript: preRequestScript ?? "", + testScript: testScript ?? "", } // only folders will have parent collection id @@ -1122,7 +1145,14 @@ function transformDuplicatedCollections( requests: userRequests, title: name, }) => { - const { auth, headers, variables, description } = + const { + auth, + headers, + variables, + description, + preRequestScript, + testScript, + } = data && data !== "null" ? JSON.parse(data) : { @@ -1130,6 +1160,8 @@ function transformDuplicatedCollections( headers: [], variables: [], description: null, + preRequestScript: "", + testScript: "", } const _ref_id = generateUniqueRefId("coll") @@ -1144,11 +1176,13 @@ function transformDuplicatedCollections( folders, requests, _ref_id, - v: 11, + v: 12, auth, headers: addDescriptionField(headers), variables: variables ?? [], description: description ?? null, + preRequestScript: preRequestScript ?? "", + testScript: testScript ?? "", } } ) diff --git a/packages/hoppscotch-selfhost-web/src/platform/collections/web/sync.ts b/packages/hoppscotch-selfhost-web/src/platform/collections/web/sync.ts index a552258afd0..0a5b93f0980 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/collections/web/sync.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/collections/web/sync.ts @@ -48,6 +48,8 @@ const transformCollectionForBackend = (collection: HoppCollection): any => { variables: collection.variables ?? [], _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } return { @@ -83,6 +85,8 @@ const recursivelySyncCollections = async ( variables: collection.variables ?? [], _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createRESTRootUserCollection( collection.name, @@ -102,6 +106,8 @@ const recursivelySyncCollections = async ( variables: [], _ref_id: generateUniqueRefId("coll"), description: null, + preRequestScript: "", + testScript: "", } collection.id = parentCollectionID @@ -110,6 +116,8 @@ const recursivelySyncCollections = async ( collection.headers = returnedData.headers collection.variables = returnedData.variables collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateRESTCollectionOrFolder( parentCollectionID, `${collectionPath}` @@ -128,6 +136,8 @@ const recursivelySyncCollections = async ( variables: collection.variables ?? [], _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } const res = await createRESTChildUserCollection( @@ -150,6 +160,8 @@ const recursivelySyncCollections = async ( variables: [], _ref_id: generateUniqueRefId("coll"), description: null, + preRequestScript: "", + testScript: "", } collection.id = childCollectionId @@ -159,6 +171,8 @@ const recursivelySyncCollections = async ( parentCollectionID = childCollectionId collection.variables = returnedData.variables collection.description = returnedData.description ?? null + collection.preRequestScript = returnedData.preRequestScript ?? "" + collection.testScript = returnedData.testScript ?? "" removeDuplicateRESTCollectionOrFolder( childCollectionId, @@ -271,6 +285,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< variables: collection.variables, _ref_id: collection._ref_id, description: collection.description ?? null, + preRequestScript: collection.preRequestScript ?? "", + testScript: collection.testScript ?? "", } if (collectionID) { @@ -355,6 +371,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf< variables: folder.variables, _ref_id: folder._ref_id, description: folder.description, + preRequestScript: folder.preRequestScript ?? "", + testScript: folder.testScript ?? "", } if (folderID) { updateUserCollection(folderID, folderName, JSON.stringify(data)) diff --git a/packages/hoppscotch-selfhost-web/src/platform/history/desktop/index.ts b/packages/hoppscotch-selfhost-web/src/platform/history/desktop/index.ts index f36240d574a..dccf9e936b0 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/history/desktop/index.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/history/desktop/index.ts @@ -14,6 +14,7 @@ import { graphqlHistoryStore, deleteGraphqlHistoryEntry, clearGraphqlHistory, + decodeGQLHistoryResponse, } from "@hoppscotch/common/newstore/history" import { translateToNewRequest, translateToGQLRequest } from "@hoppscotch/data" import { HistoryPlatformDef } from "@hoppscotch/common/platform/history" @@ -109,7 +110,7 @@ async function loadHistoryEntries() { const gqlHistoryEntries: GQLHistoryEntry[] = gqlEntries.map((entry) => ({ v: 1, request: translateToGQLRequest(JSON.parse(entry.request)), - response: JSON.parse(entry.responseMetadata), + response: decodeGQLHistoryResponse(entry.responseMetadata), star: entry.isStarred, updatedOn: new Date(entry.executedOn), id: entry.id, @@ -175,7 +176,7 @@ function setupUserHistoryCreatedSubscription() { v: 1, id, request: translateToGQLRequest(JSON.parse(request)), - response: JSON.parse(responseMetadata), + response: decodeGQLHistoryResponse(responseMetadata), star: isStarred, updatedOn: new Date(executedOn), }) diff --git a/packages/hoppscotch-selfhost-web/src/platform/history/web/index.ts b/packages/hoppscotch-selfhost-web/src/platform/history/web/index.ts index 64e1186c28a..9a274161a63 100644 --- a/packages/hoppscotch-selfhost-web/src/platform/history/web/index.ts +++ b/packages/hoppscotch-selfhost-web/src/platform/history/web/index.ts @@ -14,6 +14,7 @@ import { graphqlHistoryStore, deleteGraphqlHistoryEntry, clearGraphqlHistory, + decodeGQLHistoryResponse, } from "@hoppscotch/common/newstore/history" import { translateToNewRequest, translateToGQLRequest } from "@hoppscotch/data" import { HistoryPlatformDef } from "@hoppscotch/common/platform/history" @@ -112,7 +113,7 @@ async function loadHistoryEntries() { const gqlHistoryEntries: GQLHistoryEntry[] = gqlEntries.map((entry) => ({ v: 1, request: translateToGQLRequest(JSON.parse(entry.request)), - response: JSON.parse(entry.responseMetadata), + response: decodeGQLHistoryResponse(entry.responseMetadata), star: entry.isStarred, updatedOn: new Date(entry.executedOn), id: entry.id, @@ -178,7 +179,7 @@ function setupUserHistoryCreatedSubscription() { v: 1, id, request: translateToGQLRequest(JSON.parse(request)), - response: JSON.parse(responseMetadata), + response: decodeGQLHistoryResponse(responseMetadata), star: isStarred, updatedOn: new Date(executedOn), }) diff --git a/packages/hoppscotch-selfhost-web/tsconfig.json b/packages/hoppscotch-selfhost-web/tsconfig.json index d5681338fab..d50b6fcbb38 100644 --- a/packages/hoppscotch-selfhost-web/tsconfig.json +++ b/packages/hoppscotch-selfhost-web/tsconfig.json @@ -18,11 +18,13 @@ "@app/platform/*": ["./src/platform/*"], "@app/services/*": ["./src/services/*"], "@app/components/*": ["./src/components/*"], + "@app/composables/*": ["./src/composables/*"], "@app/helpers/*": ["./src/helpers/*"], "@app/api/*": ["./src/api/*"], "@app/lib/*": ["./src/lib/*"], "@app/kernel/*": ["./src/kernel/*"] - } + }, + "types": ["vite/client", "unplugin-icons/types/vue"] }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] diff --git a/packages/hoppscotch-selfhost-web/vite.config.ts b/packages/hoppscotch-selfhost-web/vite.config.ts index 6b600eff5ff..96fbceba1ae 100644 --- a/packages/hoppscotch-selfhost-web/vite.config.ts +++ b/packages/hoppscotch-selfhost-web/vite.config.ts @@ -86,6 +86,7 @@ export default defineConfig({ "@app/platform": path.resolve(__dirname, "./src/platform"), "@app/services": path.resolve(__dirname, "./src/services"), "@app/components": path.resolve(__dirname, "./src/components"), + "@app/composables": path.resolve(__dirname, "./src/composables"), "@app/helpers": path.resolve(__dirname, "./src/helpers"), "@app/api": path.resolve(__dirname, "./src/api"), "@app/lib": path.resolve(__dirname, "./src/lib"), diff --git a/packages/hoppscotch-selfhost-web/webapp-server/README.md b/packages/hoppscotch-selfhost-web/webapp-server/README.md index 06a2c614c08..224d00c6f60 100644 --- a/packages/hoppscotch-selfhost-web/webapp-server/README.md +++ b/packages/hoppscotch-selfhost-web/webapp-server/README.md @@ -16,15 +16,18 @@ docker build -t hoppscotch-webapp-server . ## Configuration -| Variable | Description | Default | -|----------------------------------|------------------------------------|------------------------------------------------| -| `WEBAPP_SERVER_PORT` | Server port | `3200` | -| `FRONTEND_PATH` | Path to frontend assets | `/site/selfhost-web` (prod) or `../dist` (dev) | -| `WEBAPP_SERVER_SIGNING_SECRET` | Secret string for key derivation | None | -| `WEBAPP_SERVER_SIGNING_SEED` | Base64 encoded 32-byte seed | None | -| `WEBAPP_SERVER_SIGNING_KEY` | Base64 encoded 64-byte private key | None | -| `WEBAPP_SERVER_SIGNING_KEY_FILE` | Custom path for key file | `/data/webapp-server/signing.key` | -| `GO_ENV` | Set to `development` for dev mode | None | +| Variable | Description | Default | +|----------------------------------|------------------------------------------------------------|------------------------------------------------| +| `WEBAPP_SERVER_PORT` | Server port | `3200` | +| `WEBAPP_SERVER_READ_TIMEOUT` | HTTP read timeout (Go duration, e.g. `30s`; `0` disables) | `15s` | +| `WEBAPP_SERVER_WRITE_TIMEOUT` | HTTP write timeout (Go duration, e.g. `30s`; `0` disables) | `15s` | +| `WEBAPP_SERVER_IDLE_TIMEOUT` | HTTP idle timeout (Go duration, e.g. `2m`; `0` disables) | `60s` | +| `FRONTEND_PATH` | Path to frontend assets | `/site/selfhost-web` (prod) or `../dist` (dev) | +| `WEBAPP_SERVER_SIGNING_SECRET` | Secret string for key derivation | None | +| `WEBAPP_SERVER_SIGNING_SEED` | Base64 encoded 32-byte seed | None | +| `WEBAPP_SERVER_SIGNING_KEY` | Base64 encoded 64-byte private key | None | +| `WEBAPP_SERVER_SIGNING_KEY_FILE` | Custom path for key file | `/data/webapp-server/signing.key` | +| `GO_ENV` | Set to `development` for dev mode | None | ## Signing Key Persistence diff --git a/packages/hoppscotch-selfhost-web/webapp-server/internal/bundle/types.go b/packages/hoppscotch-selfhost-web/webapp-server/internal/bundle/types.go index 0b17d14e6f9..09cadbdc620 100644 --- a/packages/hoppscotch-selfhost-web/webapp-server/internal/bundle/types.go +++ b/packages/hoppscotch-selfhost-web/webapp-server/internal/bundle/types.go @@ -3,7 +3,7 @@ package bundle import "time" const ( - Version = "2026.3.1" + Version = "2026.4.0" DefaultMaxSize = 50 * 1024 * 1024 diff --git a/packages/hoppscotch-selfhost-web/webapp-server/internal/config/config.go b/packages/hoppscotch-selfhost-web/webapp-server/internal/config/config.go index 8d4dafa9e9c..e5f48fadf0c 100644 --- a/packages/hoppscotch-selfhost-web/webapp-server/internal/config/config.go +++ b/packages/hoppscotch-selfhost-web/webapp-server/internal/config/config.go @@ -4,17 +4,43 @@ import ( "log" "os" "strconv" + "time" ) const ( DefaultPort = 3200 DefaultFrontendPath = "/site/selfhost-web" DevFrontendPath = "../dist" + + DefaultReadTimeout = 15 * time.Second + DefaultWriteTimeout = 15 * time.Second + DefaultIdleTimeout = 60 * time.Second ) type Config struct { Port int FrontendPath string + ReadTimeout time.Duration + WriteTimeout time.Duration + IdleTimeout time.Duration +} + +// parseDuration reads a Go duration string from an env var (e.g. "30s", "2m", "0"). +// A value of "0" is valid and disables the timeout (net/http semantics). +// If the variable is unset or invalid, it logs a warning and returns the fallback. +func parseDuration(envKey string, fallback time.Duration) time.Duration { + if s := os.Getenv(envKey); s != "" { + if d, err := time.ParseDuration(s); err == nil && d >= 0 { + if d == 0 { + log.Printf("Using %s from environment: %s (timeout disabled)", envKey, s) + } else { + log.Printf("Using %s from environment: %s", envKey, s) + } + return d + } + log.Printf("Warning: Invalid %s value '%s', using default %v", envKey, s, fallback) + } + return fallback } // Load reads config from env vars with sensible defaults @@ -46,5 +72,9 @@ func Load() *Config { log.Println("Running in production mode, using frontend path: /site/selfhost-web") } + cfg.ReadTimeout = parseDuration("WEBAPP_SERVER_READ_TIMEOUT", DefaultReadTimeout) + cfg.WriteTimeout = parseDuration("WEBAPP_SERVER_WRITE_TIMEOUT", DefaultWriteTimeout) + cfg.IdleTimeout = parseDuration("WEBAPP_SERVER_IDLE_TIMEOUT", DefaultIdleTimeout) + return cfg } diff --git a/packages/hoppscotch-selfhost-web/webapp-server/main.go b/packages/hoppscotch-selfhost-web/webapp-server/main.go index 9a9d6a645e1..a1febec09e8 100644 --- a/packages/hoppscotch-selfhost-web/webapp-server/main.go +++ b/packages/hoppscotch-selfhost-web/webapp-server/main.go @@ -62,14 +62,15 @@ func main() { addr := fmt.Sprintf(":%d", cfg.Port) - // NOTE: these timeouts are pretty conservative - // bump them if you're serving huge bundles over slow connections + // NOTE: timeouts default to conservative values but can be overridden + // via WEBAPP_SERVER_READ_TIMEOUT, WEBAPP_SERVER_WRITE_TIMEOUT, WEBAPP_SERVER_IDLE_TIMEOUT + // (Go duration strings, e.g. "30s", "2m", "0" to disable) httpServer := &http.Server{ Addr: addr, Handler: mux, - ReadTimeout: 15 * time.Second, - WriteTimeout: 15 * time.Second, - IdleTimeout: 60 * time.Second, + ReadTimeout: cfg.ReadTimeout, + WriteTimeout: cfg.WriteTimeout, + IdleTimeout: cfg.IdleTimeout, } go func() { diff --git a/packages/hoppscotch-sh-admin/locales/en.json b/packages/hoppscotch-sh-admin/locales/en.json index 15c9d1b0859..f3f6b40be7e 100644 --- a/packages/hoppscotch-sh-admin/locales/en.json +++ b/packages/hoppscotch-sh-admin/locales/en.json @@ -89,6 +89,15 @@ "tls_reject_unauthorized": "TLS Reject Unauthorized", "title": "SMTP Configurations", "smtp_auth_incomplete": "SMTP username and password must both be provided or both left empty", + "auth_switch_description": "Switching will clear the credentials entered in the current authentication type. Any unsaved data will be lost and cannot be undone.", + "auth_type": "Authentication Type", + "auth_type_login": "Basic Auth (Login)", + "auth_type_oauth2": "OAuth 2.0", + "oauth2_user": "OAuth 2.0 User", + "oauth2_client_id": "OAuth 2.0 Client ID", + "oauth2_client_secret": "OAuth 2.0 Client Secret", + "oauth2_refresh_token": "OAuth 2.0 Refresh Token", + "oauth2_access_url": "OAuth 2.0 Access Token URL", "toggle_failure": "Failed to toggle smtp!!", "update_failure": "Failed to update smtp configurations!!", "user": "SMTP User" diff --git a/packages/hoppscotch-sh-admin/package.json b/packages/hoppscotch-sh-admin/package.json index 5d6267696a1..91475a7f4d2 100644 --- a/packages/hoppscotch-sh-admin/package.json +++ b/packages/hoppscotch-sh-admin/package.json @@ -1,7 +1,7 @@ { "name": "hoppscotch-sh-admin", "private": true, - "version": "2026.3.1", + "version": "2026.4.0", "type": "module", "scripts": { "dev": "pnpm exec npm-run-all -p -l dev:*", @@ -14,61 +14,61 @@ }, "dependencies": { "@fontsource-variable/inter": "5.2.8", - "@fontsource-variable/material-symbols-rounded": "5.2.38", + "@fontsource-variable/material-symbols-rounded": "5.2.43", "@fontsource-variable/roboto-mono": "5.2.8", "@graphql-typed-document-node/core": "3.2.0", "@hoppscotch/ui": "0.2.5", "@hoppscotch/vue-toasted": "0.1.0", - "@intlify/unplugin-vue-i18n": "11.0.7", + "@intlify/unplugin-vue-i18n": "11.1.2", "@types/cors": "2.8.19", "@urql/exchange-auth": "3.0.0", - "@urql/vue": "2.0.0", + "@urql/vue": "2.1.0", "@vueuse/core": "14.2.1", - "axios": "1.13.6", + "axios": "1.15.2", "cors": "2.8.6", "date-fns": "4.1.0", "fp-ts": "2.16.11", - "graphql": "16.13.1", + "graphql": "16.13.2", "io-ts": "2.2.22", - "lodash-es": "4.17.23", - "postcss": "8.5.8", + "lodash-es": "4.18.1", + "postcss": "8.5.10", "prettier-plugin-tailwindcss": "0.7.1", "rxjs": "7.8.2", "tailwindcss": "3.4.16", "tippy.js": "6.3.7", "ts-node-dev": "2.0.0", "unplugin-vue-components": "30.0.0", - "vue": "3.5.31", - "vue-i18n": "11.3.0", + "vue": "3.5.33", + "vue-i18n": "11.4.0", "vue-router": "4.6.4", "vue-tippy": "6.7.1" }, "devDependencies": { - "@graphql-codegen/cli": "6.2.1", - "@graphql-codegen/client-preset": "5.2.4", - "@graphql-codegen/introspection": "5.0.1", - "@graphql-codegen/typed-document-node": "6.1.7", - "@graphql-codegen/typescript": "5.0.9", - "@graphql-codegen/typescript-document-nodes": "5.0.9", - "@graphql-codegen/typescript-operations": "5.0.9", + "@graphql-codegen/cli": "6.3.1", + "@graphql-codegen/client-preset": "5.3.0", + "@graphql-codegen/introspection": "5.0.2", + "@graphql-codegen/typed-document-node": "6.1.8", + "@graphql-codegen/typescript": "5.0.10", + "@graphql-codegen/typescript-document-nodes": "5.0.10", + "@graphql-codegen/typescript-operations": "5.1.0", "@graphql-codegen/urql-introspection": "3.0.1", - "@iconify-json/lucide": "1.2.99", + "@iconify-json/lucide": "1.2.104", "@import-meta-env/cli": "0.7.4", "@import-meta-env/unplugin": "0.6.3", "@types/lodash-es": "4.17.12", - "@vitejs/plugin-vue": "6.0.5", - "@vue/compiler-sfc": "3.5.31", - "autoprefixer": "10.4.27", - "dotenv": "17.3.1", + "@vitejs/plugin-vue": "6.0.6", + "@vue/compiler-sfc": "3.5.33", + "autoprefixer": "10.5.0", + "dotenv": "17.4.2", "graphql-tag": "2.12.6", "hoppscotch-backend": "workspace:^", "npm-run-all": "4.1.5", - "sass": "1.98.0", + "sass": "1.99.0", "ts-node": "10.9.2", "typescript": "5.9.3", "unplugin-fonts": "1.4.0", "unplugin-icons": "22.5.0", - "vite": "7.3.1", + "vite": "7.3.2", "vite-plugin-pages": "0.33.2", "vite-plugin-vue-layouts": "0.11.0", "vue-tsc": "2.1.6" diff --git a/packages/hoppscotch-sh-admin/src/components.d.ts b/packages/hoppscotch-sh-admin/src/components.d.ts index 27a89ad6005..0cfce92026a 100644 --- a/packages/hoppscotch-sh-admin/src/components.d.ts +++ b/packages/hoppscotch-sh-admin/src/components.d.ts @@ -46,7 +46,9 @@ declare module 'vue' { IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default'] IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] IconLucideInfo: typeof import('~icons/lucide/info')['default'] + IconLucideLock: typeof import('~icons/lucide/lock')['default'] IconLucideSearch: typeof import('~icons/lucide/search')['default'] + IconLucideShield: typeof import('~icons/lucide/shield')['default'] IconLucideUser: typeof import('~icons/lucide/user')['default'] OnboardingAuthProviderCard: typeof import('./components/onboarding/AuthProviderCard.vue')['default'] OnboardingAuthSetup: typeof import('./components/onboarding/AuthSetup.vue')['default'] @@ -81,5 +83,6 @@ declare module 'vue' { UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default'] UsersSharedRequests: typeof import('./components/users/SharedRequests.vue')['default'] UsersSuccessInviteModal: typeof import('./components/users/SuccessInviteModal.vue')['default'] + UsersTeams: typeof import('./components/users/Teams.vue')['default'] } } diff --git a/packages/hoppscotch-sh-admin/src/components/onboarding/AuthSetup.vue b/packages/hoppscotch-sh-admin/src/components/onboarding/AuthSetup.vue index 257c5c4b324..6d8ca185b20 100644 --- a/packages/hoppscotch-sh-admin/src/components/onboarding/AuthSetup.vue +++ b/packages/hoppscotch-sh-admin/src/components/onboarding/AuthSetup.vue @@ -172,7 +172,7 @@ const props = defineProps<{ isFirstTimeSetup?: boolean }>(); const emit = defineEmits<{ ( e: 'complete-onboarding', - payload: { submittingConfigs: boolean; summary: OnBoardingSummary } + payload: { submittingConfigs: boolean; summary: OnBoardingSummary }, ): void; }>(); @@ -212,10 +212,10 @@ watch( () => enabledConfigs.value, (configs) => { isOAuthEnabled.value = OAuthProviders.some((provider) => - configs.includes(provider) + configs.includes(provider), ); }, - { immediate: true } + { immediate: true }, ); watch( @@ -229,32 +229,41 @@ watch( selectedOptions.value = ['OAUTH', 'SMTP']; } }, - { immediate: true } + { immediate: true }, ); const isSelected = (option: SelectedOption) => selectedOptions.value.includes(option as any); -const isSmtpEnabled = computed(() => enabledConfigs.value.includes('MAILER')); +const isSmtpEnabled = computed( + () => + enabledConfigs.value.includes('MAILER') || + enabledConfigs.value.includes('EMAIL'), +); const updateOAuthEnabled = () => { isOAuthEnabled.value = OAuthProviders.some((provider) => - enabledConfigs.value.includes(provider) + enabledConfigs.value.includes(provider), ); }; +// Card clicks reconcile enabled state to match the card's selection, rather +// than blindly flipping. When the backend pre-populated enabledConfigs +// (e.g. a prior partial onboarding), a plain toggle would wipe the existing +// EMAIL/GOOGLE entries the moment the user clicks the card to "select" them. const toggleSelectedOption = (option: SelectedOption) => { - if (selectedOptions.value.includes(option as any)) { - selectedOptions.value = selectedOptions.value.filter( - (opt) => opt !== option - ); - } else { - selectedOptions.value.push(option as any); - } + const willBeSelected = !selectedOptions.value.includes(option); + + selectedOptions.value = willBeSelected + ? [...selectedOptions.value, option] + : selectedOptions.value.filter((opt) => opt !== option); + if (option === 'SMTP') { - toggleConfig('EMAIL'); - toggleSmtpConfig(); - } else { + if (willBeSelected !== isSmtpEnabled.value) { + toggleConfig('EMAIL'); + toggleSmtpConfig(); + } + } else if (willBeSelected !== isOAuthEnabled.value) { toggleConfig(option); } }; diff --git a/packages/hoppscotch-sh-admin/src/components/onboarding/OAuthSetup.vue b/packages/hoppscotch-sh-admin/src/components/onboarding/OAuthSetup.vue index 82ed1dd6eb4..f1cc7f03f60 100644 --- a/packages/hoppscotch-sh-admin/src/components/onboarding/OAuthSetup.vue +++ b/packages/hoppscotch-sh-admin/src/components/onboarding/OAuthSetup.vue @@ -2,7 +2,8 @@
@@ -106,11 +238,13 @@ import { useVModel } from '@vueuse/core'; import { computed, reactive, watch } from 'vue'; import { useI18n } from '~/composables/i18n'; +import { useSmtpAuthTypeSwitch } from '~/composables/useSmtpAuthTypeSwitch'; import { hasInputValidationFailed, ServerConfigs } from '~/helpers/configs'; -import { makeReadableKey } from '~/helpers/utils/readableKey'; import IconEye from '~icons/lucide/eye'; import IconEyeOff from '~icons/lucide/eye-off'; import IconHelpCircle from '~icons/lucide/help-circle'; +import IconLock from '~icons/lucide/lock'; +import IconShield from '~icons/lucide/shield'; const t = useI18n(); @@ -124,7 +258,6 @@ const emit = defineEmits<{ const workingConfigs = useVModel(props, 'config', emit); -// Get or set smtpConfigs from workingConfigs const smtpConfigs = computed({ get() { return workingConfigs.value?.mailConfigs; @@ -134,43 +267,82 @@ const smtpConfigs = computed({ }, }); -// Mask sensitive fields +type MailFields = ServerConfigs['mailConfigs']['fields']; + +// Extract only the keys whose value type is `string` +type StringFieldKey = { + [K in keyof MailFields]: MailFields[K] extends string ? K : never; +}[keyof MailFields]; + +type BooleanFieldKey = { + [K in keyof MailFields]: MailFields[K] extends boolean ? K : never; +}[keyof MailFields]; + type Field = { name: string; - key: keyof ServerConfigs['mailConfigs']['fields']; + key: StringFieldKey; error?: string; }; -const smtpConfigFields = reactive([ +type CheckboxField = { + name: string; + key: BooleanFieldKey; +}; + +// A typed view of `fields` that only exposes string-valued keys, +// so that `v-model="stringFields[field.key]"` resolves to `string`. +const stringFields = computed( + () => smtpConfigs.value.fields as Pick, +); + +// Basic mode: just the SMTP URL +const basicFields: Field[] = [ { name: t('configs.mail_configs.smtp_url'), key: 'mailer_smtp_url', error: t('configs.mail_configs.input_validation'), }, +]; + +// Connection +const connectionFields: Field[] = [ + { name: t('configs.mail_configs.host'), key: 'mailer_smtp_host' }, + { name: t('configs.mail_configs.port'), key: 'mailer_smtp_port' }, +]; + +// Login auth credentials +const loginAuthFields: Field[] = [ + { name: t('configs.mail_configs.user'), key: 'mailer_smtp_user' }, + { name: t('configs.mail_configs.password'), key: 'mailer_smtp_password' }, +]; + +// OAuth2 auth credentials +const oauth2Fields: Field[] = [ { - name: t('configs.mail_configs.address_from'), - key: 'mailer_from_address', - }, - { - name: t('configs.mail_configs.host'), - key: 'mailer_smtp_host', + name: t('configs.mail_configs.oauth2_user'), + key: 'mailer_smtp_oauth2_user', }, { - name: t('configs.mail_configs.port'), - key: 'mailer_smtp_port', + name: t('configs.mail_configs.oauth2_client_id'), + key: 'mailer_smtp_oauth2_client_id', }, { - name: t('configs.mail_configs.user'), - key: 'mailer_smtp_user', + name: t('configs.mail_configs.oauth2_client_secret'), + key: 'mailer_smtp_oauth2_client_secret', }, { - name: t('configs.mail_configs.password'), - key: 'mailer_smtp_password', + name: t('configs.mail_configs.oauth2_refresh_token'), + key: 'mailer_smtp_oauth2_refresh_token', }, { - name: t('configs.mail_configs.secure'), - key: 'mailer_smtp_secure', + name: t('configs.mail_configs.oauth2_access_url'), + key: 'mailer_smtp_oauth2_access_url', }, +]; + +// Security checkboxes +const securityFields: CheckboxField[] = [ + { name: t('configs.mail_configs.secure'), key: 'mailer_smtp_secure' }, { name: t('configs.mail_configs.ignore_tls'), key: 'mailer_smtp_ignore_tls', @@ -179,7 +351,7 @@ const smtpConfigFields = reactive([ name: t('configs.mail_configs.tls_reject_unauthorized'), key: 'mailer_tls_reject_unauthorized', }, -]); +]; const maskState = reactive>({ mailer_smtp_url: true, @@ -188,6 +360,11 @@ const maskState = reactive>({ mailer_smtp_port: true, mailer_smtp_user: true, mailer_smtp_password: true, + mailer_smtp_oauth2_user: true, + mailer_smtp_oauth2_client_id: true, + mailer_smtp_oauth2_client_secret: true, + mailer_smtp_oauth2_refresh_token: true, + mailer_smtp_oauth2_access_url: true, }); const toggleMask = (fieldKey: keyof ServerConfigs['mailConfigs']['fields']) => { @@ -197,41 +374,8 @@ const toggleMask = (fieldKey: keyof ServerConfigs['mailConfigs']['fields']) => { const isMasked = (fieldKey: keyof ServerConfigs['mailConfigs']['fields']) => maskState[fieldKey]; -const fieldCondition = (field: Field) => { - const advancedFields = [ - 'mailer_smtp_host', - 'mailer_smtp_port', - 'mailer_smtp_user', - 'mailer_smtp_password', - 'mailer_smtp_secure', - 'mailer_smtp_ignore_tls', - 'mailer_tls_reject_unauthorized', - ]; - const basicFields = ['mailer_smtp_url']; - - if (field.key === 'mailer_from_address') { - return true; - } - - if (smtpConfigs.value.fields.mailer_use_custom_configs) { - return ( - !basicFields.includes(field.key) && advancedFields.includes(field.key) - ); - } else return basicFields.includes(field.key); -}; - -const isCheckboxField = (field: Field) => { - const checkboxKeys = [ - 'mailer_smtp_secure', - 'mailer_smtp_ignore_tls', - 'mailer_tls_reject_unauthorized', - ]; - return checkboxKeys.includes(field.key); -}; - -const toggleCheckbox = (field: Field) => - ((smtpConfigs.value.fields[field.key] as boolean) = - !smtpConfigs.value.fields[field.key]); +const toggleCheckbox = (field: CheckboxField) => + (smtpConfigs.value.fields[field.key] = !smtpConfigs.value.fields[field.key]); // Input Validation const fieldErrors = computed(() => { @@ -246,11 +390,29 @@ const fieldErrors = computed(() => { return errors; }); -const getFieldError = ( - fieldKey: keyof ServerConfigs['mailConfigs']['fields'] -) => fieldErrors.value[fieldKey]; +const getFieldError = (fieldKey: StringFieldKey) => fieldErrors.value[fieldKey]; watch(fieldErrors, (errors) => { hasInputValidationFailed.value = Object.values(errors).some(Boolean); }); + +const LOGIN_KEYS: StringFieldKey[] = [ + 'mailer_smtp_user', + 'mailer_smtp_password', +]; +const OAUTH2_KEYS: StringFieldKey[] = [ + 'mailer_smtp_oauth2_user', + 'mailer_smtp_oauth2_client_id', + 'mailer_smtp_oauth2_client_secret', + 'mailer_smtp_oauth2_refresh_token', + 'mailer_smtp_oauth2_access_url', +]; + +const { authType, showAuthSwitchModal, confirmAuthSwitch, cancelAuthSwitch } = + useSmtpAuthTypeSwitch( + () => stringFields.value, + 'mailer_smtp_auth_type', + LOGIN_KEYS, + OAUTH2_KEYS, + ); diff --git a/packages/hoppscotch-sh-admin/src/components/ui/Accordion.vue b/packages/hoppscotch-sh-admin/src/components/ui/Accordion.vue index 75484a457a0..9b5c6305591 100644 --- a/packages/hoppscotch-sh-admin/src/components/ui/Accordion.vue +++ b/packages/hoppscotch-sh-admin/src/components/ui/Accordion.vue @@ -41,7 +41,7 @@ diff --git a/packages/hoppscotch-sh-admin/src/composables/useConfigHandler.ts b/packages/hoppscotch-sh-admin/src/composables/useConfigHandler.ts index 6c42afe2c57..1eda5199564 100644 --- a/packages/hoppscotch-sh-admin/src/composables/useConfigHandler.ts +++ b/packages/hoppscotch-sh-admin/src/composables/useConfigHandler.ts @@ -144,6 +144,23 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) { 'true', mailer_use_custom_configs: getFieldValue(InfraConfigEnum.MailerUseCustomConfigs) === 'true', + mailer_smtp_auth_type: + getFieldValue(InfraConfigEnum.MailerSmtpAuthType) || 'login', + mailer_smtp_oauth2_user: getFieldValue( + InfraConfigEnum.MailerSmtpOauth2User + ), + mailer_smtp_oauth2_client_id: getFieldValue( + InfraConfigEnum.MailerSmtpOauth2ClientId + ), + mailer_smtp_oauth2_client_secret: getFieldValue( + InfraConfigEnum.MailerSmtpOauth2ClientSecret + ), + mailer_smtp_oauth2_refresh_token: getFieldValue( + InfraConfigEnum.MailerSmtpOauth2RefreshToken + ), + mailer_smtp_oauth2_access_url: getFieldValue( + InfraConfigEnum.MailerSmtpOauth2AccessUrl + ), }, }, tokenConfigs: { @@ -277,13 +294,23 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) { // SMTP user and password are optional as a pair (both or neither) const optionalMailerKeys = ['mailer_smtp_user', 'mailer_smtp_password']; + // OAuth2 fields are always optional and auth_type has a default + const oauth2Keys = [ + 'mailer_smtp_auth_type', + 'mailer_smtp_oauth2_user', + 'mailer_smtp_oauth2_client_id', + 'mailer_smtp_oauth2_client_secret', + 'mailer_smtp_oauth2_refresh_token', + 'mailer_smtp_oauth2_access_url', + ]; const excludeKeys = mailer_use_custom_configs - ? ['mailer_smtp_url', ...optionalMailerKeys] + ? ['mailer_smtp_url', ...optionalMailerKeys, ...oauth2Keys] : [ 'mailer_smtp_host', 'mailer_smtp_port', 'mailer_smtp_user', 'mailer_smtp_password', + ...oauth2Keys, ]; return ( @@ -323,6 +350,10 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) { const fields = config.mailConfigs.fields; if (!fields.mailer_use_custom_configs) return false; + // Enforced regardless of auth_type: the backend validates the pair + // on every save, so stale login values left behind after switching + // to the OAuth2 tab would still be rejected. Surface this in the FE + // toast so users know to clear those fields before saving. const hasUser = fields.mailer_smtp_user.trim() !== ''; const hasPass = fields.mailer_smtp_password.trim() !== ''; diff --git a/packages/hoppscotch-sh-admin/src/composables/useOnboardingConfigHandler.ts b/packages/hoppscotch-sh-admin/src/composables/useOnboardingConfigHandler.ts index 0ac0bf26a8e..542c6ef4db6 100644 --- a/packages/hoppscotch-sh-admin/src/composables/useOnboardingConfigHandler.ts +++ b/packages/hoppscotch-sh-admin/src/composables/useOnboardingConfigHandler.ts @@ -31,7 +31,13 @@ export type MailerConfigKeys = | 'SMTP_USER' | 'SMTP_PASSWORD' | 'SMTP_IGNORE_TLS' - | 'TLS_REJECT_UNAUTHORIZED'; + | 'TLS_REJECT_UNAUTHORIZED' + | 'SMTP_AUTH_TYPE' + | 'SMTP_OAUTH2_USER' + | 'SMTP_OAUTH2_CLIENT_ID' + | 'SMTP_OAUTH2_CLIENT_SECRET' + | 'SMTP_OAUTH2_REFRESH_TOKEN' + | 'SMTP_OAUTH2_ACCESS_URL'; export type Configs = { oAuthProviders: { @@ -52,7 +58,7 @@ export type OnBoardingSummary = { }; function mapOAuthProviders( - configs: Partial> + configs: Partial>, ): Configs['oAuthProviders'] { return { GOOGLE: { @@ -78,7 +84,7 @@ function mapOAuthProviders( } function mapMailerConfigs( - configs: Partial> + configs: Partial>, ): Configs['mailerConfigs'] { return { MAILER_SMTP_ENABLE: configs.MAILER_SMTP_ENABLE ?? '', @@ -93,6 +99,14 @@ function mapMailerConfigs( MAILER_SMTP_IGNORE_TLS: configs.MAILER_SMTP_IGNORE_TLS || 'false', MAILER_TLS_REJECT_UNAUTHORIZED: configs.MAILER_TLS_REJECT_UNAUTHORIZED || 'false', + MAILER_SMTP_AUTH_TYPE: configs.MAILER_SMTP_AUTH_TYPE || 'login', + MAILER_SMTP_OAUTH2_USER: configs.MAILER_SMTP_OAUTH2_USER ?? '', + MAILER_SMTP_OAUTH2_CLIENT_ID: configs.MAILER_SMTP_OAUTH2_CLIENT_ID ?? '', + MAILER_SMTP_OAUTH2_CLIENT_SECRET: + configs.MAILER_SMTP_OAUTH2_CLIENT_SECRET ?? '', + MAILER_SMTP_OAUTH2_REFRESH_TOKEN: + configs.MAILER_SMTP_OAUTH2_REFRESH_TOKEN ?? '', + MAILER_SMTP_OAUTH2_ACCESS_URL: configs.MAILER_SMTP_OAUTH2_ACCESS_URL ?? '', }; } @@ -132,7 +146,7 @@ export function useOnboardingConfigHandler() { const toggleConfig = (key: EnabledConfig | 'OAUTH' | 'EMAIL') => { if (key === 'OAUTH') { enabledConfigs.value = enabledConfigs.value.filter( - (c) => !['GOOGLE', 'GITHUB', 'MICROSOFT'].includes(c) + (c) => !['GOOGLE', 'GITHUB', 'MICROSOFT'].includes(c), ); } @@ -140,7 +154,7 @@ export function useOnboardingConfigHandler() { const hasEmail = enabledConfigs.value.includes('EMAIL'); const hasMailer = enabledConfigs.value.includes('MAILER'); enabledConfigs.value = enabledConfigs.value.filter( - (c) => c !== 'EMAIL' && c !== 'MAILER' + (c) => c !== 'EMAIL' && c !== 'MAILER', ); if (!hasEmail || !hasMailer) { enabledConfigs.value.push('EMAIL', 'MAILER'); @@ -234,6 +248,12 @@ export function useOnboardingConfigHandler() { 'MAILER_SMTP_IGNORE_TLS', 'MAILER_TLS_REJECT_UNAUTHORIZED', 'MAILER_SMTP_ENABLE', + 'MAILER_SMTP_AUTH_TYPE', + 'MAILER_SMTP_OAUTH2_USER', + 'MAILER_SMTP_OAUTH2_CLIENT_ID', + 'MAILER_SMTP_OAUTH2_CLIENT_SECRET', + 'MAILER_SMTP_OAUTH2_REFRESH_TOKEN', + 'MAILER_SMTP_OAUTH2_ACCESS_URL', ].includes(key); }); }; @@ -252,7 +272,7 @@ export function useOnboardingConfigHandler() { } const relevantKeys = Object.keys(configs).filter((key) => - enabledConfigs.value.includes(key.split('_')[0] as EnabledConfig) + enabledConfigs.value.includes(key.split('_')[0] as EnabledConfig), ); const neededKeys = filterNeededConfigs(relevantKeys); @@ -263,9 +283,14 @@ export function useOnboardingConfigHandler() { const optionalSmtpKeys = new Set([ 'MAILER_SMTP_USER', 'MAILER_SMTP_PASSWORD', + 'MAILER_SMTP_OAUTH2_USER', + 'MAILER_SMTP_OAUTH2_CLIENT_ID', + 'MAILER_SMTP_OAUTH2_CLIENT_SECRET', + 'MAILER_SMTP_OAUTH2_REFRESH_TOKEN', + 'MAILER_SMTP_OAUTH2_ACCESS_URL', ]); const allFilled = neededKeys.every( - (key) => configs[key] || optionalSmtpKeys.has(key) + (key) => configs[key] || optionalSmtpKeys.has(key), ); if (!allFilled) { @@ -274,14 +299,17 @@ export function useOnboardingConfigHandler() { toast.error( t('onboarding.please_fill_configurations', { fieldName: makeReadableKey(key), - }) + }), ); }); return; } // SMTP credentials must be provided together or both left empty. - // Only enforce when custom SMTP mode is active (not simple URL mode). + // Enforced regardless of auth_type: the backend validates the pair on + // every save, so stale login values left behind after switching to the + // OAuth2 tab would still be rejected. Surface this in the FE toast so + // users know to clear those fields before saving. if ( enabledConfigs.value.includes('MAILER') && configs['MAILER_USE_CUSTOM_CONFIGS'] === 'true' @@ -301,8 +329,8 @@ export function useOnboardingConfigHandler() { Object.entries(configs).filter( ([key, val]) => enabledConfigs.value.includes(key.split('_')[0] as EnabledConfig) && - (val || optionalSmtpKeys.has(key)) - ) + (val || optionalSmtpKeys.has(key)), + ), ); }; @@ -331,7 +359,7 @@ export function useOnboardingConfigHandler() { } const filteredEnabledConfigs = enabledConfigs.value.filter( - (config) => config !== 'OAUTH' && config !== 'MAILER' + (config) => config !== 'OAUTH' && config !== 'MAILER', ); const configWithAuth = { @@ -371,7 +399,22 @@ export function useOnboardingConfigHandler() { const allowed = configs[InfraConfigEnum.ViteAllowedAuthProviders]; if (allowed) { - enabledConfigs.value = allowed.split(',') as EnabledConfig[]; + // Trim each entry so whitespace variations ("GOOGLE, EMAIL") don't + // cause provider-name mismatches in downstream `.includes()` checks. + const parsed = allowed + .split(',') + .map((p) => p.trim()) + .filter(Boolean) as EnabledConfig[]; + + // The backend persists only 'EMAIL' in VITE_ALLOWED_AUTH_PROVIDERS, + // but internally we also track 'MAILER' as the signal that MAILER_* + // keys should be kept on save. toggleConfig('EMAIL') pairs them, so + // mirror that invariant on load to keep the two flags in sync. + if (parsed.includes('EMAIL') && !parsed.includes('MAILER')) { + parsed.push('MAILER'); + } + + enabledConfigs.value = parsed; } currentConfigs.value = { @@ -404,7 +447,7 @@ export function useOnboardingConfigHandler() { enableConfig('EMAIL'); } }, - { deep: true, immediate: true } + { deep: true, immediate: true }, ); return { diff --git a/packages/hoppscotch-sh-admin/src/composables/useSmtpAuthTypeSwitch.ts b/packages/hoppscotch-sh-admin/src/composables/useSmtpAuthTypeSwitch.ts new file mode 100644 index 00000000000..b0f65f589f6 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/composables/useSmtpAuthTypeSwitch.ts @@ -0,0 +1,63 @@ +import { computed, ref } from 'vue'; + +// Shared auth-type tab switching logic for SMTP configuration UIs. +// When switching between login/oauth2 tabs, if the current tab has data +// we confirm before clearing — so stale credentials don't get persisted +// alongside the active set. +// +// `fields` is a lazy accessor to the reactive record (the two call sites +// nest it differently: `currentConfigs.mailerConfigs` vs `smtpConfigs.fields`). +// Calling it inside computed getters/setters preserves reactivity. +export function useSmtpAuthTypeSwitch( + fields: () => Record, + authKey: K, + loginKeys: readonly K[], + oauth2Keys: readonly K[], +) { + const showAuthSwitchModal = ref(false); + const pendingAuthType = ref(null); + + const hasAnyValue = (keys: readonly K[]) => + keys.some((k) => (fields()[k] ?? '').trim() !== ''); + + const authType = computed({ + get: () => fields()[authKey], + set: (next: string) => { + const current = fields()[authKey]; + if (next === current) return; + + const keysToClear = current === 'oauth2' ? oauth2Keys : loginKeys; + if (hasAnyValue(keysToClear)) { + pendingAuthType.value = next; + showAuthSwitchModal.value = true; + return; + } + + fields()[authKey] = next; + }, + }); + + const confirmAuthSwitch = () => { + if (pendingAuthType.value === null) return; + const current = fields()[authKey]; + const keysToClear = current === 'oauth2' ? oauth2Keys : loginKeys; + keysToClear.forEach((k) => { + fields()[k] = ''; + }); + fields()[authKey] = pendingAuthType.value; + pendingAuthType.value = null; + showAuthSwitchModal.value = false; + }; + + const cancelAuthSwitch = () => { + pendingAuthType.value = null; + showAuthSwitchModal.value = false; + }; + + return { + authType, + showAuthSwitchModal, + confirmAuthSwitch, + cancelAuthSwitch, + }; +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/configs.ts b/packages/hoppscotch-sh-admin/src/helpers/configs.ts index 4b915a02bc0..14f5120442f 100644 --- a/packages/hoppscotch-sh-admin/src/helpers/configs.ts +++ b/packages/hoppscotch-sh-admin/src/helpers/configs.ts @@ -56,6 +56,12 @@ export type ServerConfigs = { mailer_smtp_ignore_tls: boolean; mailer_tls_reject_unauthorized: boolean; mailer_use_custom_configs: boolean; + mailer_smtp_auth_type: string; + mailer_smtp_oauth2_user: string; + mailer_smtp_oauth2_client_id: string; + mailer_smtp_oauth2_client_secret: string; + mailer_smtp_oauth2_refresh_token: string; + mailer_smtp_oauth2_access_url: string; }; }; @@ -230,6 +236,30 @@ export const CUSTOM_MAIL_CONFIGS: Config[] = [ name: InfraConfigEnum.MailerTlsRejectUnauthorized, key: 'mailer_tls_reject_unauthorized', }, + { + name: InfraConfigEnum.MailerSmtpAuthType, + key: 'mailer_smtp_auth_type', + }, + { + name: InfraConfigEnum.MailerSmtpOauth2User, + key: 'mailer_smtp_oauth2_user', + }, + { + name: InfraConfigEnum.MailerSmtpOauth2ClientId, + key: 'mailer_smtp_oauth2_client_id', + }, + { + name: InfraConfigEnum.MailerSmtpOauth2ClientSecret, + key: 'mailer_smtp_oauth2_client_secret', + }, + { + name: InfraConfigEnum.MailerSmtpOauth2RefreshToken, + key: 'mailer_smtp_oauth2_refresh_token', + }, + { + name: InfraConfigEnum.MailerSmtpOauth2AccessUrl, + key: 'mailer_smtp_oauth2_access_url', + }, ]; const DATA_SHARING_CONFIGS: Omit[] = [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a9b10a30a5..810356c4e19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,32 +5,19 @@ settings: excludeLinksFromLockfile: false overrides: - '@hono/node-server@>=1.0.0 <1.19.10': 1.19.10 '@nestjs-modules/mailer>mjml': 5.0.0-alpha.4 + '@xmldom/xmldom': 0.8.13 apiconnect-wsdl: 2.0.36 body-parser: 2.2.1 cross-spawn: 7.0.6 - dompurify@>=3.0.0 <3.3.3: 3.3.3 - effect@3.18.4: 3.20.0 execa@<2.0.0: 2.0.0 - flatted@>=3.0.0 <3.4.2: 3.4.2 form-data: 4.0.4 - glob@>=10.2.0 <10.5.0: 10.5.0 glob@>=11.0.0 <11.1.0: 11.1.0 - hono@>=4.0.0 <4.12.7: 4.12.7 - liquidjs@>=10.0.0 <10.25.0: 10.25.0 - lodash@>=4.0.0 <4.17.23: 4.17.23 - mailparser@>=3.0.0 <3.9.3: 3.9.3 - minimatch@>=3.0.0 <3.1.3: 3.1.5 + lodash: 4.18.1 minimatch@>=4.0.0 <4.2.5: 4.2.5 - minimatch@>=5.0.0 <10.2.3: 10.2.3 - path-to-regexp@>=8.0.0 <8.4.0: 8.4.0 - preview-email@>=3.0.0 <3.1.1: 3.1.1 - rollup@>=4.0.0 <4.59.0: 4.59.0 - serialize-javascript@>=7.0.0 <7.0.3: 7.0.3 + serialize-javascript@<7.0.3: 7.0.3 subscriptions-transport-ws>ws: 7.5.10 - svgo@4.0.0: 4.0.1 - vue: 3.5.31 + vue: 3.5.33 ws: 8.17.1 importers: @@ -38,14 +25,14 @@ importers: .: devDependencies: '@commitlint/cli': - specifier: 20.5.0 - version: 20.5.0(@types/node@24.10.1)(conventional-commits-parser@6.3.0)(typescript@5.9.3) + specifier: 20.5.2 + version: 20.5.2(@types/node@24.10.1)(conventional-commits-parser@6.4.0)(typescript@5.9.3) '@commitlint/config-conventional': specifier: 20.5.0 version: 20.5.0 '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@10.0.3(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + version: 0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@types/node': specifier: 24.10.1 version: 24.10.1 @@ -94,7 +81,7 @@ importers: dependencies: '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@tauri-apps/api': specifier: 2.1.1 version: 2.1.1 @@ -103,23 +90,23 @@ importers: version: 2.3.3 '@vueuse/core': specifier: 14.2.1 - version: 14.2.1(vue@3.5.31(typescript@5.9.3)) + version: 14.2.1(vue@3.5.33(typescript@5.9.3)) axios: - specifier: 1.13.6 - version: 1.13.6 + specifier: 1.15.2 + version: 1.15.2 fp-ts: specifier: 2.16.11 version: 2.16.11 lodash-es: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 vue: - specifier: 3.5.31 - version: 3.5.31(typescript@5.9.3) + specifier: 3.5.33 + version: 3.5.33(typescript@5.9.3) devDependencies: '@iconify-json/lucide': - specifier: 1.2.99 - version: 1.2.99 + specifier: 1.2.104 + version: 1.2.104 '@tauri-apps/cli': specifier: 2.9.3 version: 2.9.3 @@ -130,20 +117,20 @@ importers: specifier: 24.10.1 version: 24.10.1 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': - specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + specifier: 6.0.6 + version: 6.0.6(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) autoprefixer: - specifier: 10.4.27 - version: 10.4.27(postcss@8.5.8) + specifier: 10.5.0 + version: 10.5.0(postcss@8.5.10) cross-env: specifier: 10.1.0 version: 10.1.0 @@ -152,16 +139,16 @@ importers: version: 9.39.2(jiti@2.6.1) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) eslint-plugin-vue: - specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) + specifier: 10.9.0 + version: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) globals: specifier: 16.5.0 version: 16.5.0 postcss: - specifier: 8.5.8 - version: 8.5.8 + specifier: 8.5.10 + version: 8.5.10 tailwindcss: specifier: 3.4.16 version: 3.4.16(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) @@ -170,13 +157,13 @@ importers: version: 5.9.3 unplugin-icons: specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.31)(svelte@3.59.2)(vue-template-compiler@2.7.16) + version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.31(typescript@5.9.3)) + version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vue-tsc: specifier: 2.2.0 version: 2.2.0(typescript@5.9.3) @@ -185,55 +172,55 @@ importers: dependencies: '@apollo/server': specifier: 5.5.0 - version: 5.5.0(graphql@16.13.1) + version: 5.5.0(graphql@16.13.2) '@as-integrations/express5': specifier: 1.1.2 - version: 1.1.2(@apollo/server@5.5.0(graphql@16.13.1))(express@5.2.1) + version: 1.1.2(@apollo/server@5.5.0(graphql@16.13.2))(express@5.2.1) '@nestjs-modules/mailer': - specifier: 2.0.2 - version: 2.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(nodemailer@8.0.4)(terser@5.46.1)(typescript@5.9.3) + specifier: 2.3.4 + version: 2.3.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/terminus@11.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2))(chokidar@4.0.3)(nodemailer@8.0.7)(terser@5.46.1)(typescript@5.9.3) '@nestjs/apollo': - specifier: 13.2.4 - version: 13.2.4(@apollo/server@5.5.0(graphql@16.13.1))(@as-integrations/express5@1.1.2(@apollo/server@5.5.0(graphql@16.13.1))(express@5.2.1))(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/graphql@13.2.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.1)(reflect-metadata@0.2.2))(graphql@16.13.1) + specifier: 13.3.0 + version: 13.3.0(@apollo/server@5.5.0(graphql@16.13.2))(@as-integrations/express5@1.1.2(@apollo/server@5.5.0(graphql@16.13.2))(express@5.2.1))(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/graphql@13.3.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.2)(reflect-metadata@0.2.2))(graphql@16.13.2) '@nestjs/common': - specifier: 11.1.17 - version: 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: 11.1.19 + version: 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': - specifier: 4.0.3 - version: 4.0.3(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + specifier: 4.0.4 + version: 4.0.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': - specifier: 11.1.17 - version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: 11.1.19 + version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/graphql': - specifier: 13.2.4 - version: 13.2.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.1)(reflect-metadata@0.2.2) + specifier: 13.3.0 + version: 13.3.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.2)(reflect-metadata@0.2.2) '@nestjs/jwt': specifier: 11.0.2 - version: 11.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + version: 11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/passport': specifier: 11.0.0 - version: 11.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) + version: 11.0.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) '@nestjs/platform-express': - specifier: 11.1.17 - version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + specifier: 11.1.19 + version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) '@nestjs/schedule': - specifier: 6.1.1 - version: 6.1.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + specifier: 6.1.3 + version: 6.1.3(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) '@nestjs/swagger': - specifier: 11.2.6 - version: 11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) + specifier: 11.4.2 + version: 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) '@nestjs/terminus': specifier: 11.1.1 - version: 11.1.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@prisma/client@7.5.0(prisma@7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/throttler': specifier: 6.5.0 - version: 6.5.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(reflect-metadata@0.2.2) + version: 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) '@prisma/adapter-pg': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.8.0 + version: 7.8.0 '@prisma/client': - specifier: 7.5.0 - version: 7.5.0(prisma@7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) + specifier: 7.8.0 + version: 7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) argon2: specifier: 0.44.0 version: 0.44.0 @@ -253,29 +240,26 @@ importers: specifier: 1.4.7 version: 1.4.7 dotenv: - specifier: 17.3.1 - version: 17.3.1 + specifier: 17.4.2 + version: 17.4.2 express: specifier: 5.2.1 version: 5.2.1 - express-session: - specifier: 1.19.0 - version: 1.19.0 fp-ts: specifier: 2.16.11 version: 2.16.11 graphql: - specifier: 16.13.1 - version: 16.13.1 + specifier: 16.13.2 + version: 16.13.2 graphql-query-complexity: specifier: 1.1.0 - version: 1.1.0(graphql@16.13.1) + version: 1.1.0(graphql@16.13.2) graphql-redis-subscriptions: specifier: 2.7.0 - version: 2.7.0(graphql-subscriptions@3.0.0(graphql@16.13.1)) + version: 2.7.0(graphql-subscriptions@3.0.0(graphql@16.13.2)) graphql-subscriptions: specifier: 3.0.0 - version: 3.0.0(graphql@16.13.1) + version: 3.0.0(graphql@16.13.2) handlebars: specifier: 4.7.9 version: 4.7.9 @@ -286,8 +270,8 @@ importers: specifier: 1.10.1 version: 1.10.1 nodemailer: - specifier: 8.0.4 - version: 8.0.4 + specifier: 8.0.7 + version: 8.0.7 passport: specifier: 0.7.0 version: 0.7.0 @@ -310,11 +294,11 @@ importers: specifier: 8.20.0 version: 8.20.0 posthog-node: - specifier: 5.28.4 - version: 5.28.4(rxjs@7.8.2) + specifier: 5.30.6 + version: 5.30.6(rxjs@7.8.2) prisma: - specifier: 7.5.0 - version: 7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + specifier: 7.8.0 + version: 7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) reflect-metadata: specifier: 0.2.2 version: 0.2.2 @@ -330,16 +314,16 @@ importers: version: 3.3.5 '@eslint/js': specifier: 10.0.1 - version: 10.0.1(eslint@10.0.3(jiti@2.6.1)) + version: 10.0.1(eslint@10.2.1(jiti@2.6.1)) '@nestjs/cli': - specifier: 11.0.16 - version: 11.0.16(@types/node@25.5.0) + specifier: 11.0.21 + version: 11.0.21(@types/node@25.6.0)(prettier@3.8.3) '@nestjs/schematics': - specifier: 11.0.9 - version: 11.0.9(chokidar@4.0.3)(typescript@5.9.3) + specifier: 11.1.0 + version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) '@nestjs/testing': - specifier: 11.1.17 - version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17) + specifier: 11.1.19 + version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/platform-express@11.1.19) '@relmify/jest-fp-ts': specifier: 2.1.1 version: 2.1.1(fp-ts@2.16.11)(io-ts@2.2.22(fp-ts@2.16.11)) @@ -356,11 +340,11 @@ importers: specifier: 30.0.0 version: 30.0.0 '@types/node': - specifier: 25.5.0 - version: 25.5.0 + specifier: 25.6.0 + version: 25.6.0 '@types/nodemailer': - specifier: 7.0.11 - version: 7.0.11 + specifier: 8.0.0 + version: 8.0.0 '@types/passport-github2': specifier: 1.2.9 version: 1.2.9 @@ -377,35 +361,35 @@ importers: specifier: 7.2.0 version: 7.2.0 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.1 + version: 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.1 + version: 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) cross-env: specifier: 10.1.0 version: 10.1.0 eslint: - specifier: 10.0.3 - version: 10.0.3(jiti@2.6.1) + specifier: 10.2.1 + version: 10.2.1(jiti@2.6.1) eslint-config-prettier: specifier: 10.1.8 - version: 10.1.8(eslint@10.0.3(jiti@2.6.1)) + version: 10.1.8(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.3(jiti@2.6.1)))(eslint@10.0.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)))(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3) globals: - specifier: 17.4.0 - version: 17.4.0 + specifier: 17.5.0 + version: 17.5.0 jest: specifier: 30.3.0 - version: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + version: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) jest-mock-extended: - specifier: 4.0.0 - version: 4.0.0(@jest/globals@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3) + specifier: 4.0.1 + version: 4.0.1(@jest/globals@30.3.0)(jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)))(typescript@5.9.3) prettier: - specifier: 3.8.1 - version: 3.8.1 + specifier: 3.8.3 + version: 3.8.3 source-map-support: specifier: 0.5.21 version: 0.5.21 @@ -413,14 +397,14 @@ importers: specifier: 7.2.2 version: 7.2.2 ts-jest: - specifier: 29.4.6 - version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3) + specifier: 29.4.9 + version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)))(typescript@5.9.3) ts-loader: - specifier: 9.5.4 - version: 9.5.4(typescript@5.9.3)(webpack@5.104.1) + specifier: 9.5.7 + version: 9.5.7(typescript@5.9.3)(webpack@5.106.0) ts-node: specifier: 10.9.2 - version: 10.9.2(@types/node@25.5.0)(typescript@5.9.3) + version: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) tsconfig-paths: specifier: 4.2.0 version: 4.2.0 @@ -434,11 +418,11 @@ importers: specifier: 1.0.20 version: 1.0.20 axios: - specifier: 1.13.6 - version: 1.13.6 + specifier: 1.15.2 + version: 1.15.2 axios-cookiejar-support: specifier: 6.0.5 - version: 6.0.5(axios@1.13.6)(tough-cookie@6.0.1) + version: 6.0.5(axios@1.15.2)(tough-cookie@6.0.1) chalk: specifier: 5.6.2 version: 5.6.2 @@ -455,14 +439,14 @@ importers: specifier: 3.3.1 version: 3.3.1 lodash-es: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 papaparse: specifier: 5.5.3 version: 5.5.3 qs: - specifier: 6.15.0 - version: 6.15.0 + specifier: 6.15.1 + version: 6.15.1 tough-cookie: specifier: 6.0.1 version: 6.0.1 @@ -498,20 +482,20 @@ importers: specifier: 2.16.11 version: 2.16.11 prettier: - specifier: 3.8.1 - version: 3.8.1 + specifier: 3.8.3 + version: 3.8.3 semver: specifier: 7.7.4 version: 7.7.4 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 5.9.3 version: 5.9.3 vitest: - specifier: 4.1.2 - version: 4.1.2(@types/node@25.5.0)(jsdom@27.4.0(@noble/hashes@2.0.1))(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + specifier: 4.1.5 + version: 4.1.5(@types/node@25.6.0)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) packages/hoppscotch-common: dependencies: @@ -556,7 +540,7 @@ importers: version: 6.38.8 '@guolao/vue-monaco-editor': specifier: 1.6.0 - version: 1.6.0(monaco-editor@0.55.1)(vue@3.5.31(typescript@5.9.3)) + version: 1.6.0(monaco-editor@0.55.1)(vue@3.5.33(typescript@5.9.3)) '@hoppscotch/codemirror-lang-graphql': specifier: workspace:^ version: link:../codemirror-lang-graphql @@ -577,19 +561,19 @@ importers: version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/0d58d53be2bc75aeb5916bd0d77794fd209426af' '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@hoppscotch/vue-toasted': specifier: 0.1.0 - version: 0.1.0(vue@3.5.31(typescript@5.9.3)) + version: 0.1.0(vue@3.5.33(typescript@5.9.3)) '@lezer/highlight': specifier: 1.2.1 version: 1.2.1 '@noble/curves': - specifier: 2.0.1 - version: 2.0.1 + specifier: 2.2.0 + version: 2.2.0 '@scure/base': - specifier: 2.0.0 - version: 2.0.0 + specifier: 2.2.0 + version: 2.2.0 '@shopify/lang-jsonc': specifier: 1.0.1 version: 1.0.1 @@ -610,19 +594,19 @@ importers: version: 24.10.1 '@unhead/vue': specifier: 2.1.12 - version: 2.1.12(vue@3.5.31(typescript@5.9.3)) + version: 2.1.12(vue@3.5.33(typescript@5.9.3)) '@urql/core': specifier: 6.0.1 - version: 6.0.1(graphql@16.13.1) + version: 6.0.1(graphql@16.13.2) '@urql/devtools': specifier: 2.0.3 - version: 2.0.3(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1) + version: 2.0.3(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2) '@urql/exchange-auth': specifier: 3.0.0 - version: 3.0.0(@urql/core@6.0.1(graphql@16.13.1)) + version: 3.0.0(@urql/core@6.0.1(graphql@16.13.2)) '@vueuse/core': specifier: 14.2.1 - version: 14.2.1(vue@3.5.31(typescript@5.9.3)) + version: 14.2.1(vue@3.5.33(typescript@5.9.3)) acorn-walk: specifier: 8.3.5 version: 8.3.5 @@ -630,8 +614,8 @@ importers: specifier: 1.0.20 version: 1.0.20 axios: - specifier: 1.13.6 - version: 1.13.6 + specifier: 1.15.2 + version: 1.15.2 buffer: specifier: 6.0.3 version: 6.0.3 @@ -640,10 +624,10 @@ importers: version: 2.0.0 dioc: specifier: 3.0.2 - version: 3.0.2(vue@3.5.31(typescript@5.9.3)) + version: 3.0.2(vue@3.5.33(typescript@5.9.3)) dompurify: - specifier: 3.3.3 - version: 3.3.3 + specifier: 3.4.1 + version: 3.4.1 esprima: specifier: 4.0.1 version: 4.0.1 @@ -657,14 +641,14 @@ importers: specifier: 1.0.4 version: 1.0.4 graphql: - specifier: 16.13.1 - version: 16.13.1 + specifier: 16.13.2 + version: 16.13.2 graphql-language-service-interface: specifier: 2.10.2 - version: 2.10.2(@types/node@24.10.1)(graphql@16.13.1) + version: 2.10.2(@types/node@24.10.1)(graphql@16.13.2) graphql-tag: specifier: 2.12.6 - version: 2.12.6(graphql@16.13.1) + version: 2.12.6(graphql@16.13.2) hawk: specifier: 9.0.2 version: 9.0.2 @@ -693,8 +677,8 @@ importers: specifier: 3.3.1 version: 3.3.1 lodash-es: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 lossless-json: specifier: 4.3.0 version: 4.3.0 @@ -723,14 +707,14 @@ importers: specifier: 0.11.10 version: 0.11.10 qs: - specifier: 6.15.0 - version: 6.15.0 + specifier: 6.15.1 + version: 6.15.1 quicktype-core: specifier: 23.2.6 version: 23.2.6 rollup: - specifier: 4.59.0 - version: 4.59.0 + specifier: 4.60.2 + version: 4.60.2 rxjs: specifier: 7.8.2 version: 7.8.2 @@ -760,7 +744,7 @@ importers: version: 3.0.0 subscriptions-transport-ws: specifier: 0.11.0 - version: 0.11.0(graphql@16.13.1) + version: 0.11.0(graphql@16.13.2) superjson: specifier: 2.2.6 version: 2.2.6 @@ -786,26 +770,26 @@ importers: specifier: 0.4.0 version: 0.4.0(zod@3.25.32) vue: - specifier: 3.5.31 - version: 3.5.31(typescript@5.9.3) + specifier: 3.5.33 + version: 3.5.33(typescript@5.9.3) vue-i18n: - specifier: 11.3.0 - version: 11.3.0(vue@3.5.31(typescript@5.9.3)) + specifier: 11.4.0 + version: 11.4.0(vue@3.5.33(typescript@5.9.3)) vue-json-pretty: specifier: 2.6.0 - version: 2.6.0(vue@3.5.31(typescript@5.9.3)) + version: 2.6.0(vue@3.5.33(typescript@5.9.3)) vue-pdf-embed: specifier: 2.1.4 - version: 2.1.4(vue@3.5.31(typescript@5.9.3)) + version: 2.1.4(vue@3.5.33(typescript@5.9.3)) vue-router: specifier: 4.6.4 - version: 4.6.4(vue@3.5.31(typescript@5.9.3)) + version: 4.6.4(vue@3.5.33(typescript@5.9.3)) vue-tippy: specifier: 6.7.1 - version: 6.7.1(vue@3.5.31(typescript@5.9.3)) + version: 6.7.1(vue@3.5.33(typescript@5.9.3)) vuedraggable-es: specifier: 4.1.1 - version: 4.1.1(vue@3.5.31(typescript@5.9.3)) + version: 4.1.1(vue@3.5.33(typescript@5.9.3)) wonka: specifier: 6.3.6 version: 6.3.6 @@ -835,38 +819,38 @@ importers: specifier: 9.39.2 version: 9.39.2 '@graphql-codegen/add': - specifier: 6.0.0 - version: 6.0.0(graphql@16.13.1) + specifier: 6.0.1 + version: 6.0.1(graphql@16.13.2) '@graphql-codegen/cli': - specifier: 6.2.1 - version: 6.2.1(@parcel/watcher@2.5.6)(@types/node@24.10.1)(graphql@16.13.1)(typescript@5.9.3) + specifier: 6.3.1 + version: 6.3.1(@parcel/watcher@2.5.6)(@types/node@24.10.1)(graphql@16.13.2)(typescript@5.9.3) '@graphql-codegen/typed-document-node': - specifier: 6.1.7 - version: 6.1.7(graphql@16.13.1) + specifier: 6.1.8 + version: 6.1.8(graphql@16.13.2) '@graphql-codegen/typescript': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.0.10 + version: 5.0.10(graphql@16.13.2) '@graphql-codegen/typescript-operations': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.1.0 + version: 5.1.0(graphql@16.13.2) '@graphql-codegen/typescript-urql-graphcache': specifier: 3.1.1 - version: 3.1.1(@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1))(graphql-tag@2.12.6(graphql@16.13.1))(graphql@16.13.1) + version: 3.1.1(@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2))(graphql-tag@2.12.6(graphql@16.13.2))(graphql@16.13.2) '@graphql-codegen/urql-introspection': specifier: 3.0.1 - version: 3.0.1(graphql@16.13.1) + version: 3.0.1(graphql@16.13.2) '@graphql-typed-document-node/core': specifier: 3.2.0 - version: 3.2.0(graphql@16.13.1) + version: 3.2.0(graphql@16.13.2) '@iconify-json/lucide': - specifier: 1.2.99 - version: 1.2.99 + specifier: 1.2.104 + version: 1.2.104 '@import-meta-env/cli': specifier: 0.7.4 version: 0.7.4(@import-meta-env/unplugin@0.6.3) '@intlify/unplugin-vue-i18n': - specifier: 11.0.7 - version: 11.0.7(@vue/compiler-dom@3.5.31)(eslint@9.39.2(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) + specifier: 11.1.2 + version: 11.1.2(@vue/compiler-dom@3.5.33)(eslint@9.39.2(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) '@relmify/jest-fp-ts': specifier: 2.1.1 version: 2.1.1(fp-ts@2.16.11)(io-ts@2.2.22(fp-ts@2.16.11)) @@ -901,41 +885,41 @@ importers: specifier: 21.0.3 version: 21.0.3 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': - specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + specifier: 6.0.6 + version: 6.0.6(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@vue/compiler-sfc': - specifier: 3.5.31 - version: 3.5.31 + specifier: 3.5.33 + version: 3.5.33 '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vue/runtime-core': - specifier: 3.5.31 - version: 3.5.31 + specifier: 3.5.33 + version: 3.5.33 autoprefixer: - specifier: 10.4.27 - version: 10.4.27(postcss@8.5.8) + specifier: 10.5.0 + version: 10.5.0(postcss@8.5.10) cross-env: specifier: 10.1.0 version: 10.1.0 dotenv: - specifier: 17.3.1 - version: 17.3.1 + specifier: 17.4.2 + version: 17.4.2 eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) eslint-plugin-vue: - specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) + specifier: 10.9.0 + version: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) glob: specifier: 13.0.6 version: 13.0.6 @@ -944,7 +928,7 @@ importers: version: 16.5.0 jsdom: specifier: 27.4.0 - version: 27.4.0(@noble/hashes@2.0.1) + version: 27.4.0(@noble/hashes@2.2.0) npm-run-all: specifier: 4.1.5 version: 4.1.5 @@ -952,65 +936,65 @@ importers: specifier: 12.1.3 version: 12.1.3 postcss: - specifier: 8.5.8 - version: 8.5.8 + specifier: 8.5.10 + version: 8.5.10 prettier: - specifier: 3.8.1 - version: 3.8.1 + specifier: 3.8.3 + version: 3.8.3 prettier-plugin-tailwindcss: specifier: 0.7.2 - version: 0.7.2(prettier@3.8.1) + version: 0.7.2(prettier@3.8.3) rollup-plugin-polyfill-node: specifier: 0.13.0 - version: 0.13.0(rollup@4.59.0) + version: 0.13.0(rollup@4.60.2) sass: - specifier: 1.98.0 - version: 1.98.0 + specifier: 1.99.0 + version: 1.99.0 tailwindcss: specifier: 3.4.16 version: 3.4.16(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 5.9.3 version: 5.9.3 unplugin-fonts: specifier: 1.4.0 - version: 1.4.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 1.4.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) unplugin-icons: specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.31)(svelte@3.59.2)(vue-template-compiler@2.7.16) + version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.31(typescript@5.9.3)) + version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vite-plugin-checker: specifier: 0.12.0 - version: 0.12.0(eslint@9.39.2(jiti@2.6.1))(meow@13.2.0)(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-tsc@1.8.8(typescript@5.9.3)) + version: 0.12.0(eslint@9.39.2(jiti@2.6.1))(meow@13.2.0)(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-tsc@1.8.8(typescript@5.9.3)) vite-plugin-fonts: specifier: 0.7.0 - version: 0.7.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 0.7.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vite-plugin-html-config: specifier: 2.0.2 - version: 2.0.2(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 2.0.2(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vite-plugin-pages: specifier: 0.33.3 - version: 0.33.3(@vue/compiler-sfc@3.5.31)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3))) + version: 0.33.3(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))) vite-plugin-pages-sitemap: specifier: 1.7.1 version: 1.7.1 vite-plugin-pwa: specifier: 1.2.0 - version: 1.2.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) + version: 1.2.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) vite-plugin-vue-layouts: specifier: 0.11.0 - version: 0.11.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) + version: 0.11.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) vitest: - specifier: 4.1.2 - version: 4.1.2(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.0.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + specifier: 4.1.5 + version: 4.1.5(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vue-tsc: specifier: 1.8.8 version: 1.8.8(typescript@5.9.3) @@ -1027,8 +1011,8 @@ importers: specifier: 6.2.2 version: 6.2.2 lodash: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 parser-ts: specifier: 0.7.0 version: 0.7.0(fp-ts@2.16.11) @@ -1049,8 +1033,8 @@ importers: specifier: 5.9.3 version: 5.9.3 vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) packages/hoppscotch-desktop: dependencies: @@ -1058,8 +1042,8 @@ importers: specifier: 5.2.8 version: 5.2.8 '@fontsource-variable/material-symbols-rounded': - specifier: 5.2.38 - version: 5.2.38 + specifier: 5.2.43 + version: 5.2.43 '@fontsource-variable/roboto-mono': specifier: 5.2.8 version: 5.2.8 @@ -1074,7 +1058,7 @@ importers: version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/0d58d53be2bc75aeb5916bd0d77794fd209426af' '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@tauri-apps/api': specifier: 2.1.1 version: 2.1.1 @@ -1100,14 +1084,14 @@ importers: specifier: 7.8.2 version: 7.8.2 vue: - specifier: 3.5.31 - version: 3.5.31(typescript@5.9.3) + specifier: 3.5.33 + version: 3.5.33(typescript@5.9.3) vue-router: specifier: 4.6.4 - version: 4.6.4(vue@3.5.31(typescript@5.9.3)) + version: 4.6.4(vue@3.5.33(typescript@5.9.3)) vue-tippy: specifier: 6.7.1 - version: 6.7.1(vue@3.5.31(typescript@5.9.3)) + version: 6.7.1(vue@3.5.33(typescript@5.9.3)) zod: specifier: 3.25.32 version: 3.25.32 @@ -1119,8 +1103,8 @@ importers: specifier: 9.39.2 version: 9.39.2 '@iconify-json/lucide': - specifier: 1.2.99 - version: 1.2.99 + specifier: 1.2.104 + version: 1.2.104 '@rushstack/eslint-patch': specifier: 1.16.1 version: 1.16.1 @@ -1128,53 +1112,53 @@ importers: specifier: 2.9.3 version: 2.9.3 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': - specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + specifier: 6.0.6 + version: 6.0.6(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) autoprefixer: - specifier: 10.4.27 - version: 10.4.27(postcss@8.5.8) + specifier: 10.5.0 + version: 10.5.0(postcss@8.5.10) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) eslint-plugin-vue: - specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) + specifier: 10.9.0 + version: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) globals: specifier: 16.5.0 version: 16.5.0 postcss: - specifier: 8.5.8 - version: 8.5.8 + specifier: 8.5.10 + version: 8.5.10 sass: - specifier: 1.98.0 - version: 1.98.0 + specifier: 1.99.0 + version: 1.99.0 tailwindcss: specifier: 3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + version: 3.4.16(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) typescript: specifier: 5.9.3 version: 5.9.3 unplugin-icons: specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.31)(svelte@3.59.2)(vue-template-compiler@2.7.16) + version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.31(typescript@5.9.3)) + version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vue-tsc: specifier: 2.2.0 version: 2.2.0(typescript@5.9.3) @@ -1209,7 +1193,7 @@ importers: devDependencies: '@sveltejs/vite-plugin-svelte': specifier: ^1.0.1 - version: 1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1)) + version: 1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1)) '@tauri-apps/cli': specifier: ^2.0.0-alpha.17 version: 2.9.3 @@ -1218,7 +1202,7 @@ importers: version: 3.59.2 vite: specifier: ^3.0.2 - version: 3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1) + version: 3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1) packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay: dependencies: @@ -1260,11 +1244,11 @@ importers: specifier: 6.1.2 version: 6.1.2 lodash: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 lodash-es: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 devDependencies: '@digitak/esrun': specifier: 3.2.26 @@ -1291,11 +1275,11 @@ importers: specifier: 24.10.1 version: 24.10.1 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) @@ -1304,7 +1288,7 @@ importers: version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) globals: specifier: 16.5.0 version: 16.5.0 @@ -1312,23 +1296,23 @@ importers: specifier: 2.2.22 version: 2.2.22(fp-ts@2.16.11) prettier: - specifier: 3.8.1 - version: 3.8.1 + specifier: 3.8.3 + version: 3.8.3 typescript: specifier: 5.9.3 version: 5.9.3 vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vitest: - specifier: 4.1.2 - version: 4.1.2(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.0.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + specifier: 4.1.5 + version: 4.1.5(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) packages/hoppscotch-kernel: dependencies: '@hoppscotch/plugin-relay': - specifier: github:CuriousCorrelation/tauri-plugin-relay#7cf09c1ad31e228758738c2f4e1c8fe9cc141291 - version: '@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/7cf09c1ad31e228758738c2f4e1c8fe9cc141291' + specifier: github:CuriousCorrelation/tauri-plugin-relay#42f449e1c5657679fecf0374b0ce5047ad03c069 + version: '@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/42f449e1c5657679fecf0374b0ce5047ad03c069' '@tauri-apps/api': specifier: 2.1.1 version: 2.1.1 @@ -1348,8 +1332,8 @@ importers: specifier: 1.0.20 version: 1.0.20 axios: - specifier: 1.13.6 - version: 1.13.6 + specifier: 1.15.2 + version: 1.15.2 fp-ts: specifier: 2.16.11 version: 2.16.11 @@ -1367,17 +1351,17 @@ importers: specifier: 24.9.1 version: 24.9.1 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) globals: specifier: 16.5.0 version: 16.5.0 @@ -1385,8 +1369,8 @@ importers: specifier: 5.9.3 version: 5.9.3 vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@24.9.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@24.9.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) packages/hoppscotch-selfhost-web: dependencies: @@ -1394,8 +1378,8 @@ importers: specifier: 5.2.8 version: 5.2.8 '@fontsource-variable/material-symbols-rounded': - specifier: 5.2.38 - version: 5.2.38 + specifier: 5.2.43 + version: 5.2.43 '@fontsource-variable/roboto-mono': specifier: 5.2.8 version: 5.2.8 @@ -1413,7 +1397,7 @@ importers: version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/0d58d53be2bc75aeb5916bd0d77794fd209426af' '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@import-meta-env/unplugin': specifier: 0.6.3 version: 0.6.3 @@ -1431,16 +1415,16 @@ importers: version: 2.3.3 '@vueuse/core': specifier: 14.2.1 - version: 14.2.1(vue@3.5.31(typescript@5.9.3)) + version: 14.2.1(vue@3.5.33(typescript@5.9.3)) axios: - specifier: 1.13.6 - version: 1.13.6 + specifier: 1.15.2 + version: 1.15.2 buffer: specifier: 6.0.3 version: 6.0.3 dioc: specifier: 3.0.2 - version: 3.0.2(vue@3.5.31(typescript@5.9.3)) + version: 3.0.2(vue@3.5.33(typescript@5.9.3)) fp-ts: specifier: 2.16.11 version: 2.16.11 @@ -1460,8 +1444,8 @@ importers: specifier: 0.4.0 version: 0.4.0(zod@3.25.32) vue: - specifier: 3.5.31 - version: 3.5.31(typescript@5.9.3) + specifier: 3.5.33 + version: 3.5.33(typescript@5.9.3) workbox-window: specifier: 7.4.0 version: 7.4.0 @@ -1476,71 +1460,71 @@ importers: specifier: 9.39.2 version: 9.39.2 '@graphql-codegen/add': - specifier: 6.0.0 - version: 6.0.0(graphql@16.13.1) + specifier: 6.0.1 + version: 6.0.1(graphql@16.13.2) '@graphql-codegen/cli': - specifier: 6.2.1 - version: 6.2.1(@parcel/watcher@2.5.6)(@types/node@25.5.0)(graphql@16.13.1)(typescript@5.9.3) + specifier: 6.3.1 + version: 6.3.1(@parcel/watcher@2.5.6)(@types/node@25.6.0)(graphql@16.13.2)(typescript@5.9.3) '@graphql-codegen/typed-document-node': - specifier: 6.1.7 - version: 6.1.7(graphql@16.13.1) + specifier: 6.1.8 + version: 6.1.8(graphql@16.13.2) '@graphql-codegen/typescript': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.0.10 + version: 5.0.10(graphql@16.13.2) '@graphql-codegen/typescript-operations': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.1.0 + version: 5.1.0(graphql@16.13.2) '@graphql-codegen/typescript-urql-graphcache': specifier: 3.1.1 - version: 3.1.1(@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1))(graphql-tag@2.12.6(graphql@16.13.1))(graphql@16.13.1) + version: 3.1.1(@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2))(graphql-tag@2.12.6(graphql@16.13.2))(graphql@16.13.2) '@graphql-codegen/urql-introspection': specifier: 3.0.1 - version: 3.0.1(graphql@16.13.1) + version: 3.0.1(graphql@16.13.2) '@graphql-typed-document-node/core': specifier: 3.2.0 - version: 3.2.0(graphql@16.13.1) + version: 3.2.0(graphql@16.13.2) '@iconify-json/lucide': - specifier: 1.2.99 - version: 1.2.99 + specifier: 1.2.104 + version: 1.2.104 '@intlify/unplugin-vue-i18n': - specifier: 11.0.7 - version: 11.0.7(@vue/compiler-dom@3.5.31)(eslint@9.39.2(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) + specifier: 11.1.2 + version: 11.1.2(@vue/compiler-dom@3.5.33)(eslint@9.39.2(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) '@rushstack/eslint-patch': specifier: 1.16.1 version: 1.16.1 '@typescript-eslint/eslint-plugin': - specifier: 8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.2 - version: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.59.0 + version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-legacy': specifier: 7.2.1 - version: 7.2.1(terser@5.46.1)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 7.2.1(terser@5.46.1)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) '@vitejs/plugin-vue': - specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + specifier: 6.0.6 + version: 6.0.6(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) autoprefixer: - specifier: 10.4.27 - version: 10.4.27(postcss@8.5.8) + specifier: 10.5.0 + version: 10.5.0(postcss@8.5.10) cross-env: specifier: 10.1.0 version: 10.1.0 dotenv: - specifier: 17.3.1 - version: 17.3.1 + specifier: 17.4.2 + version: 17.4.2 eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) eslint-plugin-prettier: specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) eslint-plugin-vue: - specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) + specifier: 10.9.0 + version: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) globals: specifier: 16.5.0 version: 16.5.0 @@ -1548,53 +1532,53 @@ importers: specifier: 4.1.5 version: 4.1.5 postcss: - specifier: 8.5.8 - version: 8.5.8 + specifier: 8.5.10 + version: 8.5.10 prettier-plugin-tailwindcss: specifier: 0.7.2 - version: 0.7.2(prettier@3.8.1) + version: 0.7.2(prettier@3.8.3) tailwindcss: specifier: 3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + version: 3.4.16(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) typescript: specifier: 5.9.3 version: 5.9.3 unplugin-fonts: specifier: 1.4.0 - version: 1.4.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 1.4.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) unplugin-icons: specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.31)(svelte@3.59.2)(vue-template-compiler@2.7.16) + version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.31(typescript@5.9.3)) + version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vite-plugin-fonts: specifier: 0.7.0 - version: 0.7.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 0.7.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vite-plugin-html-config: specifier: 2.0.2 - version: 2.0.2(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 2.0.2(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vite-plugin-inspect: specifier: 11.3.3 - version: 11.3.3(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 11.3.3(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vite-plugin-pages: specifier: 0.33.3 - version: 0.33.3(@vue/compiler-sfc@3.5.31)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3))) + version: 0.33.3(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))) vite-plugin-pages-sitemap: specifier: 1.7.1 version: 1.7.1 vite-plugin-pwa: specifier: 1.2.0 - version: 1.2.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) + version: 1.2.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) vite-plugin-static-copy: specifier: 3.3.0 - version: 3.3.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 3.3.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) vite-plugin-vue-layouts: specifier: 0.11.0 - version: 0.11.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) + version: 0.11.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) vue-tsc: specifier: 2.1.6 version: 2.1.6(typescript@5.9.3) @@ -1605,38 +1589,38 @@ importers: specifier: 5.2.8 version: 5.2.8 '@fontsource-variable/material-symbols-rounded': - specifier: 5.2.38 - version: 5.2.38 + specifier: 5.2.43 + version: 5.2.43 '@fontsource-variable/roboto-mono': specifier: 5.2.8 version: 5.2.8 '@graphql-typed-document-node/core': specifier: 3.2.0 - version: 3.2.0(graphql@16.13.1) + version: 3.2.0(graphql@16.13.2) '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@10.0.3(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + version: 0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@hoppscotch/vue-toasted': specifier: 0.1.0 - version: 0.1.0(vue@3.5.31(typescript@5.9.3)) + version: 0.1.0(vue@3.5.33(typescript@5.9.3)) '@intlify/unplugin-vue-i18n': - specifier: 11.0.7 - version: 11.0.7(@vue/compiler-dom@3.5.31)(eslint@10.0.3(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) + specifier: 11.1.2 + version: 11.1.2(@vue/compiler-dom@3.5.33)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) '@types/cors': specifier: 2.8.19 version: 2.8.19 '@urql/exchange-auth': specifier: 3.0.0 - version: 3.0.0(@urql/core@6.0.1(graphql@16.13.1)) + version: 3.0.0(@urql/core@6.0.1(graphql@16.13.2)) '@urql/vue': - specifier: 2.0.0 - version: 2.0.0(@urql/core@6.0.1(graphql@16.13.1))(vue@3.5.31(typescript@5.9.3)) + specifier: 2.1.0 + version: 2.1.0(@urql/core@6.0.1(graphql@16.13.2))(vue@3.5.33(typescript@5.9.3)) '@vueuse/core': specifier: 14.2.1 - version: 14.2.1(vue@3.5.31(typescript@5.9.3)) + version: 14.2.1(vue@3.5.33(typescript@5.9.3)) axios: - specifier: 1.13.6 - version: 1.13.6 + specifier: 1.15.2 + version: 1.15.2 cors: specifier: 2.8.6 version: 2.8.6 @@ -1647,75 +1631,75 @@ importers: specifier: 2.16.11 version: 2.16.11 graphql: - specifier: 16.13.1 - version: 16.13.1 + specifier: 16.13.2 + version: 16.13.2 io-ts: specifier: 2.2.22 version: 2.2.22(fp-ts@2.16.11) lodash-es: - specifier: 4.17.23 - version: 4.17.23 + specifier: 4.18.1 + version: 4.18.1 postcss: - specifier: 8.5.8 - version: 8.5.8 + specifier: 8.5.10 + version: 8.5.10 prettier-plugin-tailwindcss: specifier: 0.7.1 - version: 0.7.1(prettier@3.8.1) + version: 0.7.1(prettier@3.8.3) rxjs: specifier: 7.8.2 version: 7.8.2 tailwindcss: specifier: 3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + version: 3.4.16(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) tippy.js: specifier: 6.3.7 version: 6.3.7 ts-node-dev: specifier: 2.0.0 - version: 2.0.0(@types/node@25.5.0)(typescript@5.9.3) + version: 2.0.0(@types/node@25.6.0)(typescript@5.9.3) unplugin-vue-components: specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.31(typescript@5.9.3)) + version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) vue: - specifier: 3.5.31 - version: 3.5.31(typescript@5.9.3) + specifier: 3.5.33 + version: 3.5.33(typescript@5.9.3) vue-i18n: - specifier: 11.3.0 - version: 11.3.0(vue@3.5.31(typescript@5.9.3)) + specifier: 11.4.0 + version: 11.4.0(vue@3.5.33(typescript@5.9.3)) vue-router: specifier: 4.6.4 - version: 4.6.4(vue@3.5.31(typescript@5.9.3)) + version: 4.6.4(vue@3.5.33(typescript@5.9.3)) vue-tippy: specifier: 6.7.1 - version: 6.7.1(vue@3.5.31(typescript@5.9.3)) + version: 6.7.1(vue@3.5.33(typescript@5.9.3)) devDependencies: '@graphql-codegen/cli': - specifier: 6.2.1 - version: 6.2.1(@parcel/watcher@2.5.6)(@types/node@25.5.0)(graphql@16.13.1)(typescript@5.9.3) + specifier: 6.3.1 + version: 6.3.1(@parcel/watcher@2.5.6)(@types/node@25.6.0)(graphql@16.13.2)(typescript@5.9.3) '@graphql-codegen/client-preset': - specifier: 5.2.4 - version: 5.2.4(graphql@16.13.1) + specifier: 5.3.0 + version: 5.3.0(graphql@16.13.2) '@graphql-codegen/introspection': - specifier: 5.0.1 - version: 5.0.1(graphql@16.13.1) + specifier: 5.0.2 + version: 5.0.2(graphql@16.13.2) '@graphql-codegen/typed-document-node': - specifier: 6.1.7 - version: 6.1.7(graphql@16.13.1) + specifier: 6.1.8 + version: 6.1.8(graphql@16.13.2) '@graphql-codegen/typescript': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.0.10 + version: 5.0.10(graphql@16.13.2) '@graphql-codegen/typescript-document-nodes': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.0.10 + version: 5.0.10(graphql@16.13.2) '@graphql-codegen/typescript-operations': - specifier: 5.0.9 - version: 5.0.9(graphql@16.13.1) + specifier: 5.1.0 + version: 5.1.0(graphql@16.13.2) '@graphql-codegen/urql-introspection': specifier: 3.0.1 - version: 3.0.1(graphql@16.13.1) + version: 3.0.1(graphql@16.13.2) '@iconify-json/lucide': - specifier: 1.2.99 - version: 1.2.99 + specifier: 1.2.104 + version: 1.2.104 '@import-meta-env/cli': specifier: 0.7.4 version: 0.7.4(@import-meta-env/unplugin@0.6.3) @@ -1726,20 +1710,20 @@ importers: specifier: 4.17.12 version: 4.17.12 '@vitejs/plugin-vue': - specifier: 6.0.5 - version: 6.0.5(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3)) + specifier: 6.0.6 + version: 6.0.6(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@vue/compiler-sfc': - specifier: 3.5.31 - version: 3.5.31 + specifier: 3.5.33 + version: 3.5.33 autoprefixer: - specifier: 10.4.27 - version: 10.4.27(postcss@8.5.8) + specifier: 10.5.0 + version: 10.5.0(postcss@8.5.10) dotenv: - specifier: 17.3.1 - version: 17.3.1 + specifier: 17.4.2 + version: 17.4.2 graphql-tag: specifier: 2.12.6 - version: 2.12.6(graphql@16.13.1) + version: 2.12.6(graphql@16.13.2) hoppscotch-backend: specifier: workspace:^ version: link:../hoppscotch-backend @@ -1747,29 +1731,29 @@ importers: specifier: 4.1.5 version: 4.1.5 sass: - specifier: 1.98.0 - version: 1.98.0 + specifier: 1.99.0 + version: 1.99.0 ts-node: specifier: 10.9.2 - version: 10.9.2(@types/node@25.5.0)(typescript@5.9.3) + version: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) typescript: specifier: 5.9.3 version: 5.9.3 unplugin-fonts: specifier: 1.4.0 - version: 1.4.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + version: 1.4.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) unplugin-icons: specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.31)(svelte@3.59.2)(vue-template-compiler@2.7.16) + version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) vite: - specifier: 7.3.1 - version: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vite-plugin-pages: specifier: 0.33.2 - version: 0.33.2(@vue/compiler-sfc@3.5.31)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3))) + version: 0.33.2(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))) vite-plugin-vue-layouts: specifier: 0.11.0 - version: 0.11.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) + version: 0.11.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) vue-tsc: specifier: 2.1.6 version: 2.1.6(typescript@5.9.3) @@ -1788,8 +1772,8 @@ packages: resolution: {tarball: https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/0d58d53be2bc75aeb5916bd0d77794fd209426af} version: 0.1.0 - '@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/7cf09c1ad31e228758738c2f4e1c8fe9cc141291': - resolution: {tarball: https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/7cf09c1ad31e228758738c2f4e1c8fe9cc141291} + '@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/42f449e1c5657679fecf0374b0ce5047ad03c069': + resolution: {tarball: https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/42f449e1c5657679fecf0374b0ce5047ad03c069} version: 0.1.0 '@acemir/cssom@0.9.31': @@ -1799,17 +1783,8 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@angular-devkit/core@19.2.17': - resolution: {integrity: sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - peerDependencies: - chokidar: ^4.0.0 - peerDependenciesMeta: - chokidar: - optional: true - - '@angular-devkit/core@19.2.19': - resolution: {integrity: sha512-JbLL+4IMLMBgjLZlnPG4lYDfz4zGrJ/s6Aoon321NJKuw1Kb1k5KpFu9dUY0BqLIe8xPQ2UJBpI+xXdK5MXMHQ==} + '@angular-devkit/core@19.2.24': + resolution: {integrity: sha512-Kd49warf6U/EyWe5BszF/eebN3zQ3bk7tgfEljAw8q/rX95UUtriJubWvp6pgzHfzBA4jwq8f+QiNZB8eBEXPA==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^4.0.0 @@ -1817,24 +1792,20 @@ packages: chokidar: optional: true - '@angular-devkit/schematics-cli@19.2.19': - resolution: {integrity: sha512-7q9UY6HK6sccL9F3cqGRUwKhM7b/XfD2YcVaZ2WD7VMaRlRm85v6mRjSrfKIAwxcQU0UK27kMc79NIIqaHjzxA==} + '@angular-devkit/schematics-cli@19.2.24': + resolution: {integrity: sha512-bsStZQG67J1HBqTmWxtIcobvgrn32L4UOdL7hGyOru5VxDWPNA8pRnDYavT3hnJeBkJYPoQIw8u7Dm0ecoQprw==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true - '@angular-devkit/schematics@19.2.17': - resolution: {integrity: sha512-ADfbaBsrG8mBF6Mfs+crKA/2ykB8AJI50Cv9tKmZfwcUcyAdmTr+vVvhsBCfvUAEokigSsgqgpYxfkJVxhJYeg==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - - '@angular-devkit/schematics@19.2.19': - resolution: {integrity: sha512-J4Jarr0SohdrHcb40gTL4wGPCQ952IMWF1G/MSAQfBAPvA9ZKApYhpxcY7PmehVePve+ujpus1dGsJ7dPxz8Kg==} + '@angular-devkit/schematics@19.2.24': + resolution: {integrity: sha512-lnw+ZM1Io+cJAkReC0NPDjqObL8NtKzKIkdgEEKC8CUmkhurYhedbicN8Y8NYHgG1uLd2GozW3+/QqPRZaN+Lw==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - '@apideck/better-ajv-errors@0.3.6': - resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} + '@apideck/better-ajv-errors@0.3.7': + resolution: {integrity: sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==} engines: {node: '>=10'} peerDependencies: ajv: '>=8' @@ -1967,8 +1938,8 @@ packages: peerDependencies: graphql: '*' - '@ardatan/relay-compiler@13.0.0': - resolution: {integrity: sha512-ite4+xng5McO8MflWCi0un0YmnorTujsDnfPfhzYzAgoJ+jkI1pZj6jtmTl8Jptyi1H+Pa0zlatJIsxDD++ETA==} + '@ardatan/relay-compiler@13.0.1': + resolution: {integrity: sha512-afG3YPwuSA0E5foouZusz5GlXKs74dObv4cuWyLyfKsYFj2r7oGRNB28v18HvwuLSQtQFCi+DpIe0TZkgQDYyg==} peerDependencies: graphql: '*' @@ -2623,19 +2594,7 @@ packages: '@boringer-avatars/vue3@0.2.1': resolution: {integrity: sha512-KzAfh31SDXToTvFL0tBNG5Ur+VzfD1PP4jmY5/GS+eIuObGTIAiUu9eiht0LjuAGI+0xCgnaEgsTrOx8H3vLOQ==} peerDependencies: - vue: 3.5.31 - - '@chevrotain/cst-dts-gen@10.5.0': - resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==} - - '@chevrotain/gast@10.5.0': - resolution: {integrity: sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==} - - '@chevrotain/types@10.5.0': - resolution: {integrity: sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==} - - '@chevrotain/utils@10.5.0': - resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==} + vue: 3.5.33 '@codemirror/autocomplete@6.20.0': resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} @@ -2677,8 +2636,8 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@commitlint/cli@20.5.0': - resolution: {integrity: sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==} + '@commitlint/cli@20.5.2': + resolution: {integrity: sha512-IXr5xd3IX8SEG936P8gcpozRplkDeDSwJlt8UvoY1winwIy2udTbQ/cOCgbaaxcjdDqVoS29VUcz/wkwnSozbA==} engines: {node: '>=v18'} hasBin: true @@ -2710,8 +2669,8 @@ packages: resolution: {integrity: sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==} engines: {node: '>=v18'} - '@commitlint/load@20.5.0': - resolution: {integrity: sha512-sLhhYTL/KxeOTZjjabKDhwidGZan84XKK1+XFkwDYL/4883kIajcz/dZFAhBJmZPtL8+nBx6bnkzA95YxPeDPw==} + '@commitlint/load@20.5.2': + resolution: {integrity: sha512-zmr0RGDz7vThxW1I8ohb9yBjnGuH9mqwJpn21hInjGla+IlLOkS9ey0+dD5HlkzFlY0lX2NYdA2lDW6/0rO7Gw==} engines: {node: '>=v18'} '@commitlint/message@20.4.3': @@ -2726,8 +2685,8 @@ packages: resolution: {integrity: sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==} engines: {node: '>=v18'} - '@commitlint/resolve-extends@20.5.0': - resolution: {integrity: sha512-3SHPWUW2v0tyspCTcfSsYml0gses92l6TlogwzvM2cbxDgmhSRc+fldDjvGkCXJrjSM87BBaWYTPWwwyASZRrg==} + '@commitlint/resolve-extends@20.5.2': + resolution: {integrity: sha512-8EhSCU9eNos/5cI1yg64GW79UH1c64O69AfStCsj4zqy6An/qIphVEXj4/+2M6056T8coz00f+UXFn4WUUP1HQ==} engines: {node: '>=v18'} '@commitlint/rules@20.5.0': @@ -2746,12 +2705,12 @@ packages: resolution: {integrity: sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==} engines: {node: '>=v18'} - '@conventional-changelog/git-client@2.6.0': - resolution: {integrity: sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==} + '@conventional-changelog/git-client@2.7.0': + resolution: {integrity: sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==} engines: {node: '>=18'} peerDependencies: conventional-commits-filter: ^5.0.0 - conventional-commits-parser: ^6.3.0 + conventional-commits-parser: ^6.4.0 peerDependenciesMeta: conventional-commits-filter: optional: true @@ -2762,72 +2721,78 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@css-inline/css-inline-android-arm-eabi@0.14.1': - resolution: {integrity: sha512-LNUR8TY4ldfYi0mi/d4UNuHJ+3o8yLQH9r2Nt6i4qeg1i7xswfL3n/LDLRXvGjBYqeEYNlhlBQzbPwMX1qrU6A==} + '@css-inline/css-inline-android-arm-eabi@0.20.0': + resolution: {integrity: sha512-w1+cicyd2xGzuOcFYxL9Yp3E/KT6opGpdhaKo1vFAepyn8zHrpAR3c1DHH1RWSWK3ZVcD3ne1naqJXQa4k/9uw==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@css-inline/css-inline-android-arm64@0.14.1': - resolution: {integrity: sha512-tH5us0NYGoTNBHOUHVV7j9KfJ4DtFOeTLA3cM0XNoMtArNu2pmaaBMFJPqECzavfXkLc7x5Z22UPZYjoyHfvCA==} + '@css-inline/css-inline-android-arm64@0.20.0': + resolution: {integrity: sha512-V6ELV+DEjhYPqRcyCezUcMDSrXINMSCL4RBseEqWG18WhOZ9GoGd5XFpZzciQhHq/2MQS+06Jcc6RX59k7QS5g==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@css-inline/css-inline-darwin-arm64@0.14.1': - resolution: {integrity: sha512-QE5W1YRIfRayFrtrcK/wqEaxNaqLULPI0gZB4ArbFRd3d56IycvgBasDTHPre5qL2cXCO3VyPx+80XyHOaVkag==} + '@css-inline/css-inline-darwin-arm64@0.20.0': + resolution: {integrity: sha512-hT8Mtwp4PJ9mMYFDG/xg7KCa7nPqseJdXaajxXVjXB8+6oemxgx+7TUO7HSfmeY4Ox7X2vaNfaIfti4ySgNvyg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@css-inline/css-inline-darwin-x64@0.14.1': - resolution: {integrity: sha512-mAvv2sN8awNFsbvBzlFkZPbCNZ6GCWY5/YcIz7V5dPYw+bHHRbjnlkNTEZq5BsDxErVrMIGvz05PGgzuNvZvdQ==} + '@css-inline/css-inline-darwin-x64@0.20.0': + resolution: {integrity: sha512-caFvVySabHZG4N1QUysbhWp2+VstMlYLysZYfAX0I6c9QfWcr+OZThoGOO2gC9lYy6QMCTBSD+9t+iceH9oBQw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@css-inline/css-inline-linux-arm-gnueabihf@0.14.1': - resolution: {integrity: sha512-AWC44xL0X7BgKvrWEqfSqkT2tJA5kwSGrAGT+m0gt11wnTYySvQ6YpX0fTY9i3ppYGu4bEdXFjyK2uY1DTQMHA==} + '@css-inline/css-inline-linux-arm-gnueabihf@0.20.0': + resolution: {integrity: sha512-9/TdB6cHgJ285uL7Y+1XjdJGjIQOeF9/YNq47N+azf2SiYdA3ahGYBmZhCGtYG7aBTJly9iJCxjP9ZZN8+Lajw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@css-inline/css-inline-linux-arm64-gnu@0.14.1': - resolution: {integrity: sha512-drj0ciiJgdP3xKXvNAt4W+FH4KKMs8vB5iKLJ3HcH07sNZj58Sx++2GxFRS1el3p+GFp9OoYA6dgouJsGEqt0Q==} + '@css-inline/css-inline-linux-arm64-gnu@0.20.0': + resolution: {integrity: sha512-umcG26teSSUxWGQm7sECI8KweUgBgq9Cqd6yNMTNzqC1K56ZhW3Iwi7QewVNGOpVPXoGsywIIwIuY9lyed1Jdw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@css-inline/css-inline-linux-arm64-musl@0.14.1': - resolution: {integrity: sha512-FzknI+st8eA8YQSdEJU9ykcM0LZjjigBuynVF5/p7hiMm9OMP8aNhWbhZ8LKJpKbZrQsxSGS4g9Vnr6n6FiSdQ==} + '@css-inline/css-inline-linux-arm64-musl@0.20.0': + resolution: {integrity: sha512-wHQykZw3pX2R5Yp5VChOWzVXXO3XPdgWkQH1B9QBmft926EOkZpwxvubeAYy9I89qJzzdGNqiRl26+AUP88J3A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@css-inline/css-inline-linux-x64-gnu@0.14.1': - resolution: {integrity: sha512-yubbEye+daDY/4vXnyASAxH88s256pPati1DfVoZpU1V0+KP0BZ1dByZOU1ktExurbPH3gZOWisAnBE9xon0Uw==} + '@css-inline/css-inline-linux-x64-gnu@0.20.0': + resolution: {integrity: sha512-lHQZ+31CN3XJTn5MMFv1NYjyvuhAWEvul0fAYyppw4haA1TM+9UuA9jXdjqWXp26ItmainUnDMBlNLYQwMYt7g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@css-inline/css-inline-linux-x64-musl@0.14.1': - resolution: {integrity: sha512-6CRAZzoy1dMLPC/tns2rTt1ZwPo0nL/jYBEIAsYTCWhfAnNnpoLKVh5Nm+fSU3OOwTTqU87UkGrFJhObD/wobQ==} + '@css-inline/css-inline-linux-x64-musl@0.20.0': + resolution: {integrity: sha512-DO/cba/zndTY3s86nNNfeHx7DvrvLb+IxhkQWTr29IQeiUgbawCH9X3B/4Li2eo/sEx/imOOnYDdXYu8PeX2Fg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@css-inline/css-inline-win32-x64-msvc@0.14.1': - resolution: {integrity: sha512-nzotGiaiuiQW78EzsiwsHZXbxEt6DiMUFcDJ6dhiliomXxnlaPyBfZb6/FMBgRJOf6sknDt/5695OttNmbMYzg==} + '@css-inline/css-inline-win32-arm64-msvc@0.20.0': + resolution: {integrity: sha512-1o8xla5ljVHS7SguH6nTV6uoAIMRZv+2MrcxfLRObpkUtCO7oKXDeWnia7XlmnLhDX8Ncx5bDOenZb1N35kCiA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@css-inline/css-inline-win32-x64-msvc@0.20.0': + resolution: {integrity: sha512-pdO/QXLRwuq/RxO5PSFMhmWGJSQOvkiDyV4RrewEkE7SOCY8HAYNhx1T0y0pj2WzxuVdbNQbpwiCHAdQNplUJw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@css-inline/css-inline@0.14.1': - resolution: {integrity: sha512-u4eku+hnPqqHIGq/ZUQcaP0TrCbYeLIYBaK7qClNRGZbnh8RC4gVxLEIo8Pceo1nOK9E5G4Lxzlw5KnXcvflfA==} + '@css-inline/css-inline@0.20.0': + resolution: {integrity: sha512-WABsvMSBs/DDadwhAUDw6uXwUE6w4DC/bnC4E2Y2rqbCTw5E1PPfj6VksnSCALkv9ynZfYGYYO4+Rvhmn5kgpw==} engines: {node: '>= 10'} '@csstools/color-helpers@6.0.2': @@ -2874,19 +2839,19 @@ packages: '@digitak/grubber@3.1.4': resolution: {integrity: sha512-pqsnp2BUYlDoTXWG34HWgEJse/Eo1okRgNex8IG84wHrJp8h3SakeR5WhB4VxSA2+/D+frNYJ0ch3yXzsfNDoA==} - '@electric-sql/pglite-socket@0.0.20': - resolution: {integrity: sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==} + '@electric-sql/pglite-socket@0.1.1': + resolution: {integrity: sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==} hasBin: true peerDependencies: - '@electric-sql/pglite': 0.3.15 + '@electric-sql/pglite': 0.4.1 - '@electric-sql/pglite-tools@0.2.20': - resolution: {integrity: sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A==} + '@electric-sql/pglite-tools@0.3.1': + resolution: {integrity: sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==} peerDependencies: - '@electric-sql/pglite': 0.3.15 + '@electric-sql/pglite': 0.4.1 - '@electric-sql/pglite@0.3.15': - resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==} + '@electric-sql/pglite@0.4.1': + resolution: {integrity: sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==} '@emnapi/core@1.9.1': resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} @@ -3392,24 +3357,24 @@ packages: resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-array@0.23.3': - resolution: {integrity: sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/config-helpers@0.4.2': resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-helpers@0.5.3': - resolution: {integrity: sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==} + '@eslint/config-helpers@0.5.5': + resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/core@0.17.0': resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@1.1.1': - resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/eslintrc@3.3.5': @@ -3433,16 +3398,16 @@ packages: resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@3.0.3': - resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/plugin-kit@0.4.1': resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.6.1': - resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} + '@eslint/plugin-kit@0.7.1': + resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@exodus/bytes@1.15.0': @@ -3470,20 +3435,23 @@ packages: '@fontsource-variable/material-symbols-rounded@5.2.38': resolution: {integrity: sha512-4wVg+r/2+rQ/ldoXVAanwyAHD4zkCWKrhm0YvRxUJg6CvEHeDdml/UZSaD2GvIYKrgwqbJ0lJccitGUy9GLiKw==} + '@fontsource-variable/material-symbols-rounded@5.2.43': + resolution: {integrity: sha512-3cTOh6uHYIUyplM9a8L/FdRuXA6UOP3Q0dVyXCmViZuzW19o3mMhh39AxFdP8hV1suCldC6YvizBDhVh3Bddjw==} + '@fontsource-variable/roboto-mono@5.2.8': resolution: {integrity: sha512-6M2U3wGIUxYNKRrUoKls8BRRIPDA57T8J0agqwyDkiEHrLEEAqptsxcUl3eTm6tnRNEn6yEm4pCefvtnujebDA==} '@glideapps/ts-necessities@2.2.3': resolution: {integrity: sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==} - '@graphql-codegen/add@6.0.0': - resolution: {integrity: sha512-biFdaURX0KTwEJPQ1wkT6BRgNasqgQ5KbCI1a3zwtLtO7XTo7/vKITPylmiU27K5DSOWYnY/1jfSqUAEBuhZrQ==} + '@graphql-codegen/add@6.0.1': + resolution: {integrity: sha512-MSylSekjpVWbOBw2A/2ssk1fPY54sYb6Qk2C4AX5u7s2R+2pMQ9ws7DTXo8VU9qwTgWwVp6vGfdQ0AMpAn4Iug==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/cli@6.2.1': - resolution: {integrity: sha512-E1B+5nBda2l89Pci5M0HcEj2Hmx2yhORFX+1T3rmwpQjdOiulo+h9JifWxKomUpjfbmU1YkBSd47CCGLFPU10A==} + '@graphql-codegen/cli@6.3.1': + resolution: {integrity: sha512-I5KkyX1SgQZPojMeQTRydB6fml4cysZq/mIdhNW4rmqdoOcTgdMPq1Tl+wtRp1VpBAOrBazJUJh1nAqJMMSPIQ==} engines: {node: '>=16'} hasBin: true peerDependencies: @@ -3493,8 +3461,8 @@ packages: '@parcel/watcher': optional: true - '@graphql-codegen/client-preset@5.2.4': - resolution: {integrity: sha512-k4f9CoepkVznXRReCHBVnG/FeQVQgIOhgtkaJ6I9FcQRzUkrm9ASmQjOdNdMlZt0DHTU4nbVxIBGZW7gk1RavA==} + '@graphql-codegen/client-preset@5.3.0': + resolution: {integrity: sha512-K9FON+j7qyxAUDuSGqI3ofb7lWTBs16oPTYpu14lhdL4DKZQSHLyc8EMYU9e3KcyQ/13gU/d6culOppzAuexLA==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -3503,20 +3471,20 @@ packages: graphql-sock: optional: true - '@graphql-codegen/core@5.0.1': - resolution: {integrity: sha512-eQD7aXpKkKvaydMv5Bu0FnKCPnNMAhZ3vZW+K4Rl9IAC2w5PDv9lJhs3YTWM9W58zNOZpGQGT2F0ekS3QNIiKw==} + '@graphql-codegen/core@5.0.2': + resolution: {integrity: sha512-7RX0wwjoWPlLG/tUmpaTK91ZZqHcACNWpRL0nGnnJaJrORie9pgmX8JPrcwBgYiHSC+3ERo9xY91RFPem/VrpQ==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/gql-tag-operations@5.1.4': - resolution: {integrity: sha512-tDj/0a1U7rDH3PQgLeA+PlgBNb593MIJ43oAOKMRgJPwIQ9T7p2oqBRLxwfFZFTDLwnwsGZ7xIKqIcGgyAIj5Q==} + '@graphql-codegen/gql-tag-operations@5.2.0': + resolution: {integrity: sha512-B9gtJ4ziqpIv+7mHqwjtpYLFOuv0GmmRGpNDoWKM2VIx4OQqgI84d6OHKYCVeO7yu3mUr0QPvUgkSyuLVrdukA==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/introspection@5.0.1': - resolution: {integrity: sha512-dX6U8o0Sddhuw491e5DTE1Vf8h4SN+8bldQ+XcK6imS7eVqduond1uZjLNgFejQFWfd7x0KWldKqyy/9Ilwtlw==} + '@graphql-codegen/introspection@5.0.2': + resolution: {integrity: sha512-2Y1xC4A/6yudxvpyHLF6wcrZSm1BBGsaxabbZJCWebImXdYNU+yAdbiiaHfYrHMUEVgPnjo/qo4gt0m8JqeRHQ==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -3526,32 +3494,32 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/plugin-helpers@6.2.0': - resolution: {integrity: sha512-TKm0Q0+wRlg354Qt3PyXc+sy6dCKxmNofBsgmHoFZNVHtzMQSSgNT+rUWdwBwObQ9bFHiUVsDIv8QqxKMiKmpw==} + '@graphql-codegen/plugin-helpers@6.3.0': + resolution: {integrity: sha512-Auc+/B7okDx9+pVgLVliZtZLYh6iltWXlnzzM+bRE+zh1T4r3hKbnr8xAmtT937ArfSgk5GHcQHr8LfPYnrRBg==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/schema-ast@5.0.1': - resolution: {integrity: sha512-svLffXddnXxq1qFXQqqh+zYrxdiMnIKm+CXCUv0MYhLh0R4L5vpnaTzIUCk3icHNNXhKRm2uBD70+K8VY0xiCg==} + '@graphql-codegen/schema-ast@5.0.2': + resolution: {integrity: sha512-jl1F/9IjRkJisEb9B0ayG4QGqYlPldLRy8ojDdmL9NE1NsdB5ROfxQnSqyC3g+wuvBhWX7kZgMRQYn3RU1I5bA==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/typed-document-node@6.1.7': - resolution: {integrity: sha512-VLL9hB+YPigc/W2QYCkSNMZrkKv42nTchb9mJ0h5VY98YmW/zWb6NeYM80iHSpk8ZvHsuUT5geA53/s1phO2NQ==} + '@graphql-codegen/typed-document-node@6.1.8': + resolution: {integrity: sha512-+qDdiJSQ7Ol+vpLMAH8ZJok50CvlYxA6seQ7cwEa3emXt8MmH5hh3zdc9unQlPc7bynoJHRCgoKk7E0B7hry0w==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/typescript-document-nodes@5.0.9': - resolution: {integrity: sha512-hHdxmT2jgK/Cobbc7Fk1mryIozHYgmXIGvWtGHnOv250/iVDRQgvk1zFxHrphdx7O8etm65GU4FdgZdFQw5DhQ==} + '@graphql-codegen/typescript-document-nodes@5.0.10': + resolution: {integrity: sha512-GwvQFw1cP1kDYL7p0CoXkqfcMqbweKSrqcWzpw0LIomz0QrrwkZJQeQjhlfFe2DjRTtRzRpS/jd+Prg4mJ6QbQ==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/typescript-operations@5.0.9': - resolution: {integrity: sha512-jJFdJKMS5Cqisb5QMi7xXHPsJH9yHBMYOxBc8laFkFjHk/AOqJK90qCKbO9lwwTMPZUDe6N/HslmA0ax4J0zsg==} + '@graphql-codegen/typescript-operations@5.1.0': + resolution: {integrity: sha512-JlmjbFl0EnsfMDIYvTE1Q0kAOrntVEZ+ZfBqWTP91g4e0F/TzuwJ/V4tiFmeDf5dx/rf9AK4VkPehIdxu7TYhw==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -3568,8 +3536,8 @@ packages: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 graphql-tag: ^2.0.0 - '@graphql-codegen/typescript@5.0.9': - resolution: {integrity: sha512-YlIZ4nqdFdzr5vxuNtQtZnnMYuZ5cLYB2HaGhGI2zvqHxCmkBjIRpu/5sfccawKy23wetV+aoWvoNqxGKIryig==} + '@graphql-codegen/typescript@5.0.10': + resolution: {integrity: sha512-Pa8OFmL9TdhEYnLYJLYA9EhP8eEeivP/YDYq4Nb8LQaL7GXm4TGX8zELYaCM9Fu8M3iZb7iQGMt7qc+1lXz8XQ==} engines: {node: '>=16'} peerDependencies: graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -3585,8 +3553,8 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@graphql-codegen/visitor-plugin-common@6.2.4': - resolution: {integrity: sha512-iwiVCc7Mv8/XAa3K35AdFQ9chJSDv/gYEnBeQFF/Sq/W8EyJoHypOGOTTLk7OSrWO4xea65ggv0e7fGt7rPJjQ==} + '@graphql-codegen/visitor-plugin-common@6.3.0': + resolution: {integrity: sha512-vGBoE+4huzZyNhyGSAhXAkdROHlwKxxuziZm4XtP1mxe7nuI+VgyOmXebafLijbmuDsptPXQN0C/htL54O8hrg==} engines: {node: '>=16'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -3595,14 +3563,14 @@ packages: resolution: {integrity: sha512-Pz8wB3K0iU6ae9S1fWfsmJX24CcGeTo6hE7T44ucmV/ALKRj+bxClmqrYcDT7v3f0d12Rh4FAXBb6gon+WkDpQ==} engines: {node: '>=20.0.0'} - '@graphql-tools/apollo-engine-loader@8.0.28': - resolution: {integrity: sha512-MzgDrUuoxp6dZeo54zLBL3cEJKJtM3N/2RqK0rbPxPq5X2z6TUA7EGg8vIFTUkt5xelAsUrm8/4ai41ZDdxOng==} + '@graphql-tools/apollo-engine-loader@8.0.30': + resolution: {integrity: sha512-hUydKGGECrWloERMmfoMzHZi12X99AM9geCGF5XVsv4iMRl/Iyuet24th4kC9bZ8MlAdCwAwtUsCyv9uRfYwSA==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/batch-execute@10.0.7': - resolution: {integrity: sha512-vKo9XUiy2sc5tzMupXoxZbu5afVY/9yJ0+yLrM5Dhh38yHYULf3z9VC1eAwW0kj8pWpOo8d8CV3jpleGwv83PA==} + '@graphql-tools/batch-execute@10.0.8': + resolution: {integrity: sha512-Kobt37qrVTFhX4HUK5/vPgMXFw/5f97AzmAlfmDBSRh/GnoAmLKCb48FrEI3gdeIwZB2fEhVHJyDqsojldnLQA==} engines: {node: '>=20.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3612,14 +3580,14 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/code-file-loader@8.1.28': - resolution: {integrity: sha512-BL3Ft/PFlXDE5nNuqA36hYci7Cx+8bDrPDc8X3VSpZy9iKFBY+oQ+IwqnEHCkt8OSp2n2V0gqTg4u3fcQP1Kwg==} + '@graphql-tools/code-file-loader@8.1.32': + resolution: {integrity: sha512-gR5mNQjn0BugDL8a4A+ovS2KEvU52RNOGnbwiq9oWAEHiSv7iqJu77bpWARTzlE1ZFPK5MSQe9218+1t5PbXmQ==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/delegate@12.0.12': - resolution: {integrity: sha512-/vgLWhIwm+Mgo5VUOJQj6EOpaxXRQmA7mk8j6/8vBbPi56LoYA/UPRygcpEnm9EuXTspFKCTBil+xqThU3EmqQ==} + '@graphql-tools/delegate@12.0.14': + resolution: {integrity: sha512-/xCDM8zlCk1Lccww9asOIpxna9IFpIlol4yGsBD9Y2+3/Zu5k4/HzDC8LKJtw5MxdG+uJN1l9nRepr4GeBC4kA==} engines: {node: '>=20.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3657,8 +3625,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/executor-http@3.1.1': - resolution: {integrity: sha512-Le57fMdN7nGBp8XddkpGreCzcPGCZ+uHs1kPw/xMKPJMsn/vZUHbWJ0FY0cb0jfE3OVhbMIjjSe/OHlG3Mm3zw==} + '@graphql-tools/executor-http@3.2.1': + resolution: {integrity: sha512-53i0TYO0cznIlZDJcnq4gQ6SOZ8efGgCDV33MYh6oqEapcp36tCMEVnVGVxcX5qRRyNHkqTY6hkA+/AyK9kicQ==} engines: {node: '>=20.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3668,8 +3636,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/executor-legacy-ws@1.1.25': - resolution: {integrity: sha512-6uf4AEXO0QMxJ7AWKVPqEZXgYBJaiz5vf29X0boG8QtcqWy8mqkXKWLND2Swdx0SbEx0efoGFcjuKufUcB0ASQ==} + '@graphql-tools/executor-legacy-ws@1.1.28': + resolution: {integrity: sha512-O4uj93GG9iUb3s32eyhUohvyfA8mLhN8FvGzEdK628hFQPhZN75yurtVFrR08DHex71mQ3wYCCFkErpwdJbDDQ==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3679,20 +3647,20 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/executor@1.5.1': - resolution: {integrity: sha512-n94Qcu875Mji9GQ52n5UbgOTxlgvFJicBPYD+FRks9HKIQpdNPjkkrKZUYNG51XKa+bf03rxNflm4+wXhoHHrA==} + '@graphql-tools/executor@1.5.3': + resolution: {integrity: sha512-mgBFC0bsrZPZLu9EnydpMnAuQ8Iiq0CEbUcsmvXsm2/iYektGHDN/+bmb7hicA6dWZtdPfklYJmr21WD0GnOfA==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/git-loader@8.0.32': - resolution: {integrity: sha512-H5HTp2vevv0rRMEnCJBVmVF8md3LpJI1C1+d6OtzvmuONJ8mOX2mkf9rtoqwiztynVegaDUekvMFsc9k5iE2WA==} + '@graphql-tools/git-loader@8.0.36': + resolution: {integrity: sha512-PDDakesRu8FJYHJLf9/gkTweh8M19Bymz9i+vOlk9OTs9XmNcCqKM+1S610KX2AodvuBFz/xbesjTtTJIppLPg==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/github-loader@9.0.6': - resolution: {integrity: sha512-hhlt2MMkRcvDva/qyzqFddXzaMmRnriJ0Ts+/LcNeYnB8hcEqRMpF9RCsHYjo1mFRaiu8i4PSIpXyyFu3To7Ow==} + '@graphql-tools/github-loader@9.1.2': + resolution: {integrity: sha512-jhRJncj9Wkr1Cd8Mo3QI2oG6fTw5ILr1/OXcHIqx744NBj8pPwQBXmQzZqh7MXxbekl2EAcum7SJIjq1HpYcPA==} engines: {node: '>=20.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3702,14 +3670,14 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/graphql-file-loader@8.1.12': - resolution: {integrity: sha512-Nma7gBgJoUbqXWTmdHjouo36tjzewA8MptVcHoH7widzkciaUVzBhriHzqICFB/dVxig//g9MX8s1XawZo7UAg==} + '@graphql-tools/graphql-file-loader@8.1.14': + resolution: {integrity: sha512-CfAcsSEVkkHfEXLFzrd5rUYpcQEGWNV8lfc1Tb1p5m9HnYICzDDH08I5V33iMrEDza3GuujjjRBYqplBkqwIow==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/graphql-tag-pluck@8.3.27': - resolution: {integrity: sha512-CJ0WVXhGYsfFngpRrAAcjRHyxSDHx4dEz2W15bkwvt9he/AWhuyXm07wuGcoLrl0q0iQp1BiRjU7D8SxWZo3JQ==} + '@graphql-tools/graphql-tag-pluck@8.3.31': + resolution: {integrity: sha512-ema2RRPZGj8TKruNElyDBHVCNFMxioGIVfLBuiA+GdfmRGt95b/i7Uksnj4EwItA6MCmhxokxZoa/fl6mJt3tw==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3719,8 +3687,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/import@7.1.12': - resolution: {integrity: sha512-QSsdPsdJ7yCgQ5XODyKYpC7NlB9R1Koi0R3418PT7GiRm+9O8gYXSs/23dumcOnpiLrnf4qR2aytBn1+JOAhnA==} + '@graphql-tools/import@7.1.14': + resolution: {integrity: sha512-aqLcu04aEidszbXM6M0PWWL8bP17eX9sxXwjYWpglLvIRd4NFqb3C9QzBY8pleqXNMtWqXktlm9BQjevgSrirQ==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3730,8 +3698,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/json-file-loader@8.0.26': - resolution: {integrity: sha512-kwy9IFi5QtXXTLBgWkvA1RqsZeJDn0CxsTbhNlziCzmga9fNo7qtZ18k9FYIq3EIoQQlok+b7W7yeyJATA2xhw==} + '@graphql-tools/json-file-loader@8.0.28': + resolution: {integrity: sha512-qgCsSkPArnjlNkcYpgGKiXxCTNkrAT9E+l1LhR+Por2jTlKBBeZ8stortkQ/PNDDjuL0WPrLQmHKhNPHabnB3A==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3741,8 +3709,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/load@8.1.8': - resolution: {integrity: sha512-gxO662b64qZSToK3N6XUxWG5E6HOUjlg5jEnmGvD4bMtGJ0HwEe/BaVZbBQemCfLkxYjwRIBiVfOY9o0JyjZJg==} + '@graphql-tools/load@8.1.10': + resolution: {integrity: sha512-hjcvfEFtwtc8vGi46wtpmGWadNzfEhzbjqinyFIZuIZPlR4aYdWQtqWtY/RMM4Ew4t1USkMNm6xrqC2TH1vCSA==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3758,6 +3726,18 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@graphql-tools/merge@9.1.8': + resolution: {integrity: sha512-25V7WDrODo1cPrmuUCrqf5qlMA4a/Ow4aHaqJ1MnTUaluwsV3UiqzCHWux3HSLb0H63mkoZiuOrU5xJhxRcoCg==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/merge@9.1.9': + resolution: {integrity: sha512-iHUWNjRHeQRYdgIMIuChThOwoKzA9vrzYeslgfBo5eUYEyHGZCoDPjAavssoYXLwstYt1dZj2J22jSzc2DrN0Q==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@graphql-tools/optimize@1.4.0': resolution: {integrity: sha512-dJs/2XvZp+wgHH8T5J2TqptT9/6uVzIYvA6uFACha+ufvdMBedkfR4b4GbT8jAKLRARiqRTxy3dctnwkTM2tdw==} peerDependencies: @@ -3774,8 +3754,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/relay-operation-optimizer@7.1.1': - resolution: {integrity: sha512-va+ZieMlz6Fj18xUbwyQkZ34PsnzIdPT6Ccy1BNOQw1iclQwk52HejLMZeE/4fH+4cu80Q2HXi5+FjCKpmnJCg==} + '@graphql-tools/relay-operation-optimizer@7.1.4': + resolution: {integrity: sha512-cwOD/GEo/R//1uGCP0/urIxsMFoUgzkJVyMt9BDM2HhQhU6rSgH5l6lFukAFTJyPJVdyeOdYm2i0Jj5vYWbHTw==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3786,6 +3766,18 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@graphql-tools/schema@10.0.32': + resolution: {integrity: sha512-kJ1Qn20MPnlaEVH37639E6rzQ1tEtr6XTUhNdR4EKydl+FijtLhWX2WLZbGnvrYuG8XUcMxsZU9mRRYYNvK02w==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/schema@10.0.33': + resolution: {integrity: sha512-O6P3RIftO0jafnSsFAqpjurUuUxJ43s/AdPVLQsBkI6y4Ic/tKm4C1Qm1KKQsCDTOxXPJClh/v3g7k7yLKCFBQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@graphql-tools/schema@9.0.19': resolution: {integrity: sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==} peerDependencies: @@ -3796,8 +3788,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/url-loader@9.0.6': - resolution: {integrity: sha512-QdJI3f7ANDMYfYazRgJzzybznjOrQAOuDXweC9xmKgPZoTqNxEAsatiy69zcpTf6092taJLyrqRH6R7xUTzf4A==} + '@graphql-tools/url-loader@9.1.2': + resolution: {integrity: sha512-pVSiPrfWQKb3jq23Pl7EjbB2uv3tgZLnWo/axkmg4itAEZ5s/vV/jKa8P1HZzUnSVUTR+8tcEZVeNsUbzFCbkg==} engines: {node: '>=20.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3808,13 +3800,25 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@graphql-tools/utils@11.0.1': + resolution: {integrity: sha512-pNyCOb95ab/z3zkkiPwIPYxigX7IcpyFVcgD1XACDEvg/7yGnKCESx3k/XHEeneKYx/aWKGzEh/uuf6M6Q8HOw==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/utils@11.1.0': + resolution: {integrity: sha512-PtFVG4r8Z2LEBSaPYQMusBiB3o6kjLVJyjCLbnWem/SpSuM21v6LTmgpkXfYU1qpBV2UGsFyuEnSJInl8fR1Ag==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@graphql-tools/utils@9.2.1': resolution: {integrity: sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/wrap@11.1.12': - resolution: {integrity: sha512-PJ0tuiGbEOOZAJk2/pTKyzMEbwBncPBfO7Z84tCPzM/CAR4ZlAXbXjaXOw4fdi0ReUDyOG06Z8DGgEQjr68dKw==} + '@graphql-tools/wrap@11.1.14': + resolution: {integrity: sha512-ebSVT7apxr+88q3Wy0i4AyRmJ42I0SuMqjPIn1fqW14yCTQRZG8YLuIALG1gKR936+GkfMLOrADh6egJvdlN6Q==} engines: {node: '>=20.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -3834,7 +3838,7 @@ packages: peerDependencies: '@vue/composition-api': ^1.7.2 monaco-editor: '>=0.43.0' - vue: 3.5.31 + vue: 3.5.33 peerDependenciesMeta: '@vue/composition-api': optional: true @@ -3852,11 +3856,11 @@ packages: '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} - '@hono/node-server@1.19.10': - resolution: {integrity: sha512-hZ7nOssGqRgyV3FVVQdfi+U4q02uB23bpnYpdvNXkYTRRyWx84b7yf1ans+dnJ/7h41sGL3CeQTfO+ZGxuO+Iw==} + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} engines: {node: '>=18.14.1'} peerDependencies: - hono: 4.12.7 + hono: ^4 '@hoppscotch/httpsnippet@3.0.9': resolution: {integrity: sha512-XTs2SYxOItC7Go38VsFYtnxEk6C5JhscEpZHgd9+klyah+Iy2uKLFaBFq9M/10YLhwfPNVP3UpGsL/jY50zQgQ==} @@ -3867,7 +3871,7 @@ packages: resolution: {integrity: sha512-EiWODKPBxvx/BoylxbyrlBIzC3iZR9XmxYAyL3Oi5cEl+RBuhoV+A0UiGiBYbqNLUUWigZTpiftcYcJ9S3IMCg==} engines: {node: '>=16'} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 '@hoppscotch/vue-sonner@1.2.3': resolution: {integrity: sha512-P1gyvHHLsPeB8lsLP5SrqwQatuwOKtbsP83sKhyIV3WL2rJj3+DiFfqo2ErNBa+Sl0gM68o1V+wuOS7zbR//6g==} @@ -3875,7 +3879,7 @@ packages: '@hoppscotch/vue-toasted@0.1.0': resolution: {integrity: sha512-DIgmeTHxWwX5UeaHLEqDYNLJFGRosx/5N1fCHkaO8zt+sZv8GrHlkrIpjfKF2drmA3kKw5cY42Cw7WuCoabR3g==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -3893,8 +3897,8 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@iconify-json/lucide@1.2.99': - resolution: {integrity: sha512-XE2Pg8uax2uN3ZbvvnO0C5ADgZOyUgEPiwnhD/xrJwz/bfpWwL3mbDwxntEWB2G1mwo2OqKMF50/jp6ia2QzKw==} + '@iconify-json/lucide@1.2.104': + resolution: {integrity: sha512-Vh4VPA/UNFhSPzEdDnSuOPA1xO6b/kI1w4SLBEiKnsFYPWimq2tVDynMgKnwddz6iZpuZfZU4PXR6kn0hJayKw==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -4063,8 +4067,8 @@ packages: '@types/node': optional: true - '@intlify/bundle-utils@11.0.7': - resolution: {integrity: sha512-fEO3CJGPymxieGh8BHox7d6stgajDQae7wgpH6YYw7WX+cdW6jTTXyljZqz7OV3JcwlS9M9UHSoO+YwiO56IhA==} + '@intlify/bundle-utils@11.1.2': + resolution: {integrity: sha512-/Cd1MKb7L0SFnIvyhZO0YF4W+jSIY4BQ2PgiT0jP+tc1PO/W2mAOOx4/GecjA21oPhtSxyZd13vFAZnGGeZYVQ==} engines: {node: '>= 20'} peerDependencies: petite-vue-i18n: '*' @@ -4075,32 +4079,35 @@ packages: vue-i18n: optional: true - '@intlify/core-base@11.3.0': - resolution: {integrity: sha512-NNX5jIwF4TJBe7RtSKDMOA6JD9mp2mRcBHAwt2X+Q8PvnZub0yj5YYXlFu2AcESdgQpEv/5Yx2uOCV/yh7YkZg==} + '@intlify/core-base@11.4.0': + resolution: {integrity: sha512-nlxFOnmjJgVkL1PsuSMagyh3qIHTwc2KlO2R3qQQV1ydrcwh1XpM7opWUGqvGaLlktttopDzbLBpr/k5tvbNmA==} engines: {node: '>= 16'} - '@intlify/devtools-types@11.3.0': - resolution: {integrity: sha512-G9CNL4WpANWVdUjubOIIS7/D2j/0j+1KJmhBJxHilWNKr9mmt3IjFV3Hq4JoBP23uOoC5ynxz/FHZ42M+YxfGw==} + '@intlify/devtools-types@11.4.0': + resolution: {integrity: sha512-LtQ04kG8/2Nv6AbuINpkjODuhKHdd+MGLlXKW3I0GTCeDsDIBZUot82nnyK7D6+qersF08FqSvoN/eGPcL3c7Q==} engines: {node: '>= 16'} - '@intlify/message-compiler@11.3.0': - resolution: {integrity: sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw==} + '@intlify/message-compiler@11.4.0': + resolution: {integrity: sha512-v455gVZqMb0er63Wd/akX8DXTnwSubgrgQaRigLB60V3xpnq3B99oPvGXW+N4G/5QFt8Ls84FJ8qHJUVnRCs1A==} engines: {node: '>= 16'} - '@intlify/shared@11.3.0': - resolution: {integrity: sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ==} + '@intlify/shared@11.4.0': + resolution: {integrity: sha512-r9qUeLeO0TMZmUZ+mXS6IGQ6xwzZJaVMK6j4CdoA3eQP8xp3JtCfwkZ30gB4+knlN40pmBdDXgx85SWhMCzHng==} engines: {node: '>= 16'} - '@intlify/unplugin-vue-i18n@11.0.7': - resolution: {integrity: sha512-wswKprS1D8VfnxxVhKxug5wa3MbDSOcCoXOBjnzhMK+6NfP6h6UI8pFqSBIvcW8nPDuzweTc0Sk3PeBCcubfoQ==} + '@intlify/unplugin-vue-i18n@11.1.2': + resolution: {integrity: sha512-3RUsT7ss+dzl12bu0MW6sWdy8fZ2rsysH+4fZnMF+ANK5UQ2nhGSw1795YoHtH0rZTDI198PdfodZfyrdt4KYw==} engines: {node: '>= 20'} peerDependencies: petite-vue-i18n: '*' - vue: 3.5.31 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: 3.5.33 vue-i18n: '*' peerDependenciesMeta: petite-vue-i18n: optional: true + vite: + optional: true vue-i18n: optional: true @@ -4110,7 +4117,7 @@ packages: peerDependencies: '@intlify/shared': ^9.0.0 || ^10.0.0 || ^11.0.0 '@vue/compiler-dom': ^3.0.0 - vue: 3.5.31 + vue: 3.5.33 vue-i18n: ^9.0.0 || ^10.0.0 || ^11.0.0 peerDependenciesMeta: '@intlify/shared': @@ -4278,6 +4285,9 @@ packages: '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@kurkle/color@0.3.4': + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + '@lezer/common@1.5.1': resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==} @@ -4313,10 +4323,6 @@ packages: '@monaco-editor/loader@1.7.0': resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} - '@mrleebo/prisma-ast@0.13.1': - resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==} - engines: {node: '>=16'} - '@napi-rs/canvas-android-arm64@0.1.97': resolution: {integrity: sha512-V1c/WVw+NzH8vk7ZK/O8/nyBSCQimU8sfMsB/9qeSvdkGKNU7+mxy/bIF0gTgeBFmHpj30S4E9WHMSrxXGQuVQ==} engines: {node: '>= 10'} @@ -4395,15 +4401,25 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@nestjs-modules/mailer@2.0.2': - resolution: {integrity: sha512-+z4mADQasg0H1ZaGu4zZTuKv2pu+XdErqx99PLFPzCDNTN/q9U59WPgkxVaHnsvKHNopLj5Xap7G4ZpptduoYw==} + '@nestjs-modules/mailer@2.3.4': + resolution: {integrity: sha512-0vPNAuXGFHERFphokC5RVDgRoqwUXvI3OTPNXonw74e4QQyntp25OKzS59EaXmQOCBiIuRglmWQaFPvEpP5tuw==} peerDependencies: '@nestjs/common': '>=7.0.9' '@nestjs/core': '>=7.0.9' + '@nestjs/event-emitter': '>=2.0.0' + '@nestjs/terminus': '>=10.0.0' + bullmq: '>=4.0.0' nodemailer: '>=6.4.6' + peerDependenciesMeta: + '@nestjs/event-emitter': + optional: true + '@nestjs/terminus': + optional: true + bullmq: + optional: true - '@nestjs/apollo@13.2.4': - resolution: {integrity: sha512-5gKyDQDm+E+AIYofFxXXUhi/4z9YgSjXtjlXUixCj+n6oVcJOilQ7zxlnu3vHiBZz8kEn2ZvVZTJ+i5V2xQ+ew==} + '@nestjs/apollo@13.3.0': + resolution: {integrity: sha512-UXuqkGj96dne68/9lPQ+Yh0z4a5ON7QH3LPNFerStxn9YCCp0/LpI0wn/oxhJNWLechC7ZiSmQDhytfdJT4p8A==} peerDependencies: '@apollo/gateway': ^2.0.0 '@apollo/server': ^5.0.0 @@ -4424,12 +4440,12 @@ packages: '@as-integrations/fastify': optional: true - '@nestjs/cli@11.0.16': - resolution: {integrity: sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==} + '@nestjs/cli@11.0.21': + resolution: {integrity: sha512-F8mV0Sj/zVEouzR3NxBuJy08YHTUOmC5Xdcx3qIIaJWzrm8Vw86CHkhkaPBJ5ewRMHPDCShPmhsfwhpCcjts3A==} engines: {node: '>= 20.11'} hasBin: true peerDependencies: - '@swc/cli': ^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 + '@swc/cli': ^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 '@swc/core': ^1.3.62 peerDependenciesMeta: '@swc/cli': @@ -4437,8 +4453,8 @@ packages: '@swc/core': optional: true - '@nestjs/common@11.1.17': - resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} + '@nestjs/common@11.1.19': + resolution: {integrity: sha512-qeiTt2tv+e5QyDKqG8HlVZb2wx64FEaSGFJouqTSRs+kG44iTfl3xlz1XqVped+rihx4hmjWgL5gkhtdK3E6+Q==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -4450,14 +4466,14 @@ packages: class-validator: optional: true - '@nestjs/config@4.0.3': - resolution: {integrity: sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==} + '@nestjs/config@4.0.4': + resolution: {integrity: sha512-CJPjNitr0bAufSEnRe2N+JbnVmMmDoo6hvKCPzXgZoGwJSmp/dZPk9f/RMbuD/+Q1ZJPjwsRpq0vxna++Knwow==} peerDependencies: '@nestjs/common': ^10.0.0 || ^11.0.0 rxjs: ^7.1.0 - '@nestjs/core@11.1.17': - resolution: {integrity: sha512-lD5mAYekTTurF3vDaa8C2OKPnjiz4tsfxIc5XlcSUzOhkwWf6Ay3HKvt6FmvuWQam6uIIHX52Clg+e6tAvf/cg==} + '@nestjs/core@11.1.19': + resolution: {integrity: sha512-6nJkWa2efrYi+XlU686J9y5L7OvxpLVjT0T/sxRKE7Jvpffiihelup4WSvLvRhdHDjj/5SuoWEwqReXAaaeHmw==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -4474,8 +4490,8 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/graphql@13.2.4': - resolution: {integrity: sha512-UXtsY4o1gsSG8tlY2HI3NuWyW15eOSG7IX1nG92T5/VtsEsafhtYOnc0H9Z7zFzUn0tPBCcRte1NgVNEIgAAdw==} + '@nestjs/graphql@13.3.0': + resolution: {integrity: sha512-oGPGi8el+96h8MS3S2SgE7oidMrmm41rwzudP/OO72ij8R+4YmvO27keZPDbSCK2a5IySoGZQMb7C81vwfN2vQ==} peerDependencies: '@apollo/subgraph': ^2.9.3 '@nestjs/common': ^11.0.1 @@ -4484,7 +4500,7 @@ packages: class-validator: '*' graphql: ^16.11.0 reflect-metadata: ^0.1.13 || ^0.2.0 - ts-morph: ^20.0.0 || ^21.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 + ts-morph: ^20.0.0 || ^21.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 peerDependenciesMeta: '@apollo/subgraph': optional: true @@ -4500,12 +4516,12 @@ packages: peerDependencies: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 - '@nestjs/mapped-types@2.1.0': - resolution: {integrity: sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==} + '@nestjs/mapped-types@2.1.1': + resolution: {integrity: sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==} peerDependencies: '@nestjs/common': ^10.0.0 || ^11.0.0 class-transformer: ^0.4.0 || ^0.5.0 - class-validator: ^0.13.0 || ^0.14.0 + class-validator: ^0.13.0 || ^0.14.0 || ^0.15.0 reflect-metadata: ^0.1.12 || ^0.2.0 peerDependenciesMeta: class-transformer: @@ -4519,25 +4535,29 @@ packages: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 passport: ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 - '@nestjs/platform-express@11.1.17': - resolution: {integrity: sha512-mAf4eOsSBsTOn/VbrUO1gsjW6dVh91qqXPMXun4dN8SnNjf7PTQagM9o8d6ab8ZBpNe6UdZftdrZoDetU+n4Qg==} + '@nestjs/platform-express@11.1.19': + resolution: {integrity: sha512-Vpdv8jyCQdThfoTx+UTn+DRYr6H6X02YUqcpZ3qP6G3ZUwtVp7eS+hoQPGd4UuCnlnFG8Wqr2J9bGEzQdi1rIg==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 - '@nestjs/schedule@6.1.1': - resolution: {integrity: sha512-kQl1RRgi02GJ0uaUGCrXHCcwISsCsJDciCKe38ykJZgnAeeoeVWs8luWtBo4AqAAXm4nS5K8RlV0smHUJ4+2FA==} + '@nestjs/schedule@6.1.3': + resolution: {integrity: sha512-RflMFOpR16Dwd1jAUbeB4mfGTCh65fvEdL4mSjQPJChpkRGRjIXjb+6YQcK2faQrVT60c9DmLmoVR7/ONCtuYQ==} peerDependencies: '@nestjs/common': ^10.0.0 || ^11.0.0 '@nestjs/core': ^10.0.0 || ^11.0.0 - '@nestjs/schematics@11.0.9': - resolution: {integrity: sha512-0NfPbPlEaGwIT8/TCThxLzrlz3yzDNkfRNpbL7FiplKq3w4qXpJg0JYwqgMEJnLQZm3L/L/5XjoyfJHUO3qX9g==} + '@nestjs/schematics@11.1.0': + resolution: {integrity: sha512-lVxGZ46tcdItFMoXr6vyKWlnOsm1SZm/GUqAEDvy2RL4Q4O+3bkziAhrO7Y8JLssFUUvNFEGqAizI52WAxhjDw==} peerDependencies: + prettier: ^3.0.0 typescript: '>=4.8.2' + peerDependenciesMeta: + prettier: + optional: true - '@nestjs/swagger@11.2.6': - resolution: {integrity: sha512-oiXOxMQqDFyv1AKAqFzSo6JPvMEs4uA36Eyz/s2aloZLxUjcLfUMELSLSNQunr61xCPTpwEOShfmO7NIufKXdA==} + '@nestjs/swagger@11.4.2': + resolution: {integrity: sha512-aBihEogDMj/bLEcaqhkvyX/ZVWUw/bmnhKzR0zwUoyGJikvZyaq7rOPYl/H7Lxkkr3c90SJxyuv1AX2UT1WKlw==} peerDependencies: '@fastify/static': ^8.0.0 || ^9.0.0 '@nestjs/common': ^11.0.1 @@ -4601,8 +4621,8 @@ packages: typeorm: optional: true - '@nestjs/testing@11.1.17': - resolution: {integrity: sha512-lNffw+z+2USewmw4W0tsK+Rq94A2N4PiHbcqoRUu5y8fnqxQeIWGHhjo5BFCqj7eivqJBhT7WdRydxVq4rAHzg==} + '@nestjs/testing@11.1.19': + resolution: {integrity: sha512-/UFNWXvPEdu4v4DlC5oWLbGKmD27LehLK06b8oLzs6D6lf4vAQTdST8LRAXBadyMUQnVEQWMuBo3CtAVtlfXtQ==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -4621,16 +4641,16 @@ packages: '@nestjs/core': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 reflect-metadata: ^0.1.13 || ^0.2.0 - '@noble/curves@2.0.1': - resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} + '@noble/curves@2.2.0': + resolution: {integrity: sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==} engines: {node: '>= 20.19.0'} '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@noble/hashes@2.0.1': - resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + '@noble/hashes@2.2.0': + resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} engines: {node: '>= 20.19.0'} '@nodelib/fs.scandir@2.1.5': @@ -4786,17 +4806,20 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@posthog/core@1.24.0': - resolution: {integrity: sha512-Wkp9mgNfgdf6+G4C1VMKakm2RXKQFf4bb5/CPQRAjpqv9l6BY36zZrD1+X5Y2XIAzZqbMKRxsDu3V1r6uKu7/A==} + '@posthog/core@1.27.7': + resolution: {integrity: sha512-6rzOZajUkhuezgPeF+ReMMly0D9oiwIZtMQrsJtZcS/mwi5OtvuYgxeaohgP9PKOhkK1c7cvGskX0Y2YUtBYCw==} - '@prisma/adapter-pg@7.5.0': - resolution: {integrity: sha512-EJx7OLULahcC3IjJgdx2qRDNCT+ToY2v66UkeETMCLhNOTgqVzRzYvOEphY7Zp0eHyzfkC33Edd/qqeadf9R4A==} + '@posthog/types@1.372.3': + resolution: {integrity: sha512-4mkXC9AhsquJnvogWtWsCi+ReODj/jbK0d3fkwCNLLTOpaiAF125FJ6OJyRFax2u+dEKXAPA/dCTGx1S2WF0nw==} - '@prisma/client-runtime-utils@7.5.0': - resolution: {integrity: sha512-KnJ2b4Si/pcWEtK68uM+h0h1oh80CZt2suhLTVuLaSKg4n58Q9jBF/A42Kw6Ma+aThy1yAhfDeTC0JvEmeZnFQ==} + '@prisma/adapter-pg@7.8.0': + resolution: {integrity: sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==} - '@prisma/client@7.5.0': - resolution: {integrity: sha512-h4hF9ctp+kSRs7ENHGsFQmHAgHcfkOCxbYt6Ti9Xi8x7D+kP4tTi9x51UKmiTH/OqdyJAO+8V+r+JA5AWdav7w==} + '@prisma/client-runtime-utils@7.8.0': + resolution: {integrity: sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==} + + '@prisma/client@7.8.0': + resolution: {integrity: sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==} engines: {node: ^20.19 || ^22.12 || >=24.0} peerDependencies: prisma: '*' @@ -4807,42 +4830,46 @@ packages: typescript: optional: true - '@prisma/config@7.5.0': - resolution: {integrity: sha512-1J/9YEX7A889xM46PYg9e8VAuSL1IUmXJW3tEhMv7XQHDWlfC9YSkIw9sTYRaq5GswGlxZ+GnnyiNsUZ9JJhSQ==} + '@prisma/config@7.8.0': + resolution: {integrity: sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==} '@prisma/debug@7.2.0': resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} - '@prisma/debug@7.5.0': - resolution: {integrity: sha512-163+nffny0JoPEkDhfNco0vcuT3ymIJc9+WX7MHSQhfkeKUmKe9/wqvGk5SjppT93DtBjVwr5HPJYlXbzm6qtg==} + '@prisma/debug@7.8.0': + resolution: {integrity: sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==} - '@prisma/dev@0.20.0': - resolution: {integrity: sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==} + '@prisma/dev@0.24.3': + resolution: {integrity: sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==} - '@prisma/driver-adapter-utils@7.5.0': - resolution: {integrity: sha512-B79N/amgV677mFesFDBAdrW0OIaqawap9E0sjgLBtzIz2R3hIMS1QB8mLZuUEiS4q5Y8Oh3I25Kw4SLxMypk9Q==} + '@prisma/driver-adapter-utils@7.8.0': + resolution: {integrity: sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==} - '@prisma/engines-version@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': - resolution: {integrity: sha512-E+iRV/vbJLl8iGjVr6g/TEWokA+gjkV/doZkaQN1i/ULVdDwGnPJDfLUIFGS3BVwlG/m6L8T4x1x5isl8hGMxA==} + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': + resolution: {integrity: sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==} - '@prisma/engines@7.5.0': - resolution: {integrity: sha512-ondGRhzoaVpRWvFaQ5wH5zS1BIbhzbKqczKjCn6j3L0Zfe/LInjcEg8+xtB49AuZBX30qyx1ZtGoootUohz2pw==} + '@prisma/engines@7.8.0': + resolution: {integrity: sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==} - '@prisma/fetch-engine@7.5.0': - resolution: {integrity: sha512-kZCl2FV54qnyrVdnII8MI6qvt7HfU6Cbiz8dZ8PXz4f4lbSw45jEB9/gEMK2SGdiNhBKyk/Wv95uthoLhGMLYA==} + '@prisma/fetch-engine@7.8.0': + resolution: {integrity: sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==} '@prisma/get-platform@7.2.0': resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} - '@prisma/get-platform@7.5.0': - resolution: {integrity: sha512-7I+2y1nu/gkEKSiHHbcZ1HPe/euGdEqJZxEEMT0246q4De1+hla0ZzlTgvaT9dHcVCgLSuCG8v39db5qUUWNgw==} + '@prisma/get-platform@7.8.0': + resolution: {integrity: sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==} '@prisma/query-plan-executor@7.2.0': resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} - '@prisma/studio-core@0.21.1': - resolution: {integrity: sha512-bOGqG/eMQtKC0XVvcVLRmhWWzm/I+0QUWqAEhEBtetpuS3k3V4IWqKGUONkAIT223DNXJMxMtZp36b1FmcdPeg==} - engines: {node: ^20.19 || ^22.12 || ^24.0, pnpm: '8'} + '@prisma/streams-local@0.1.2': + resolution: {integrity: sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==} + engines: {bun: '>=1.3.6', node: '>=22.0.0'} + + '@prisma/studio-core@0.27.3': + resolution: {integrity: sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==} + engines: {node: ^20.19 || ^22.12 || >=24.0, pnpm: '8'} peerDependencies: '@types/react': ^18.0.0 || ^19.0.0 react: ^18.0.0 || ^19.0.0 @@ -4878,6 +4905,80 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-toggle@1.1.10': + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@relmify/jest-fp-ts@2.1.1': resolution: {integrity: sha512-ljNGMAINGa8YjIjbkufx6qV0+1HRoX3yNJi92A/RSZifYJpaztqjNtYm9jvKPBmQuZtnkWv+Vik+zMa2rZI0TQ==} peerDependencies: @@ -4890,8 +4991,8 @@ packages: '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} - '@rolldown/pluginutils@1.0.0-rc.2': - resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} + '@rolldown/pluginutils@1.0.0-rc.13': + resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==} '@rollup/plugin-babel@5.3.1': resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} @@ -4908,7 +5009,7 @@ packages: resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true @@ -4917,7 +5018,7 @@ packages: resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^2.78.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true @@ -4931,7 +5032,7 @@ packages: resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true @@ -4940,7 +5041,7 @@ packages: resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^2.14.0||^3.0.0||^4.0.0 tslib: '*' typescript: '>=3.7.0' peerDependenciesMeta: @@ -4953,7 +5054,7 @@ packages: resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^2.14.0||^3.0.0||^4.0.0 tslib: '*' typescript: '>=3.7.0' peerDependenciesMeta: @@ -4966,7 +5067,7 @@ packages: resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^2.14.0||^3.0.0||^4.0.0 tslib: '*' typescript: '>=3.7.0' peerDependenciesMeta: @@ -4989,7 +5090,7 @@ packages: resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: 4.59.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true @@ -4999,147 +5100,285 @@ packages: cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.60.2': + resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.59.0': resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.60.2': + resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.59.0': resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.60.2': + resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.59.0': resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.60.2': + resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.59.0': resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.60.2': + resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.59.0': resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.60.2': + resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] libc: [glibc] + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} + cpu: [arm] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-arm-musleabihf@4.59.0': resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] libc: [musl] + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} + cpu: [arm] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-arm64-gnu@4.59.0': resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-arm64-gnu@4.60.2': + resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-arm64-musl@4.59.0': resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] libc: [musl] + '@rollup/rollup-linux-arm64-musl@4.60.2': + resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-loong64-gnu@4.59.0': resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-loong64-gnu@4.60.2': + resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} + cpu: [loong64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-loong64-musl@4.59.0': resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] libc: [musl] + '@rollup/rollup-linux-loong64-musl@4.60.2': + resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} + cpu: [loong64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-ppc64-gnu@4.59.0': resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-ppc64-musl@4.59.0': resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} cpu: [ppc64] os: [linux] libc: [musl] + '@rollup/rollup-linux-ppc64-musl@4.60.2': + resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} + cpu: [ppc64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-riscv64-gnu@4.59.0': resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-riscv64-musl@4.59.0': resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] libc: [musl] + '@rollup/rollup-linux-riscv64-musl@4.60.2': + resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-s390x-gnu@4.59.0': resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] libc: [glibc] + '@rollup/rollup-linux-s390x-gnu@4.60.2': + resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-x64-gnu@4.59.0': resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-x64-gnu@4.60.2': + resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-x64-musl@4.59.0': resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] libc: [musl] + '@rollup/rollup-linux-x64-musl@4.60.2': + resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} + cpu: [x64] + os: [linux] + libc: [musl] + '@rollup/rollup-openbsd-x64@4.59.0': resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} cpu: [x64] os: [openbsd] + '@rollup/rollup-openbsd-x64@4.60.2': + resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} + cpu: [x64] + os: [openbsd] + '@rollup/rollup-openharmony-arm64@4.59.0': resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] + '@rollup/rollup-openharmony-arm64@4.60.2': + resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} + cpu: [arm64] + os: [openharmony] + '@rollup/rollup-win32-arm64-msvc@4.59.0': resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.60.2': + resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.59.0': resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.60.2': + resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} + cpu: [ia32] + os: [win32] + '@rollup/rollup-win32-x64-gnu@4.59.0': resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-gnu@4.60.2': + resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} + cpu: [x64] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.59.0': resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.60.2': + resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} + cpu: [x64] + os: [win32] + '@rushstack/eslint-patch@1.16.1': resolution: {integrity: sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==} '@scarf/scarf@1.4.0': resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - '@scure/base@2.0.0': - resolution: {integrity: sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==} + '@scure/base@2.2.0': + resolution: {integrity: sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==} '@selderee/plugin-htmlparser2@0.11.0': resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} @@ -5457,11 +5696,11 @@ packages: '@types/node@24.9.1': resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==} - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} - '@types/nodemailer@7.0.11': - resolution: {integrity: sha512-E+U4RzR2dKrx+u3N4DlsmLaDC6mMZOM/TPROxA0UAPiTgI0y4CEFBmZE+coGWTjakDriRsXG368lNk1u9Q0a2g==} + '@types/nodemailer@8.0.0': + resolution: {integrity: sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==} '@types/nprogress@0.2.3': resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} @@ -5496,8 +5735,8 @@ packages: '@types/passport@1.0.17': resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==} - '@types/pg@8.11.11': - resolution: {integrity: sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==} + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} '@types/postman-collection@3.5.11': resolution: {integrity: sha512-BZgBJDdX6jyy9hzSTIMRhCsxhF0IlzPr1i98q2wdkDo8rZrbNoBvs+3/Vw+LOIIAFH1G+FyXo5Fjf8qbawGeHg==} @@ -5582,6 +5821,22 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/eslint-plugin@8.59.0': + resolution: {integrity: sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.59.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/eslint-plugin@8.59.1': + resolution: {integrity: sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.59.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/parser@8.57.2': resolution: {integrity: sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5589,22 +5844,68 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser@8.59.0': + resolution: {integrity: sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.59.1': + resolution: {integrity: sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.57.2': resolution: {integrity: sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.59.0': + resolution: {integrity: sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.59.1': + resolution: {integrity: sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/scope-manager@8.57.2': resolution: {integrity: sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.59.0': + resolution: {integrity: sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/scope-manager@8.59.1': + resolution: {integrity: sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.57.2': resolution: {integrity: sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.59.0': + resolution: {integrity: sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/tsconfig-utils@8.59.1': + resolution: {integrity: sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.57.2': resolution: {integrity: sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5612,16 +5913,50 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.57.2': - resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} + '@typescript-eslint/type-utils@8.59.0': + resolution: {integrity: sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/typescript-estree@8.57.2': - resolution: {integrity: sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==} + '@typescript-eslint/type-utils@8.59.1': + resolution: {integrity: sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.57.2': + resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/types@8.59.0': + resolution: {integrity: sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/types@8.59.1': + resolution: {integrity: sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.57.2': + resolution: {integrity: sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.59.0': + resolution: {integrity: sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/typescript-estree@8.59.1': + resolution: {integrity: sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.57.2': resolution: {integrity: sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5629,17 +5964,39 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.59.0': + resolution: {integrity: sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.59.1': + resolution: {integrity: sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/visitor-keys@8.57.2': resolution: {integrity: sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.59.0': + resolution: {integrity: sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/visitor-keys@8.59.1': + resolution: {integrity: sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} '@unhead/vue@2.1.12': resolution: {integrity: sha512-zEWqg0nZM8acpuTZE40wkeUl8AhIe0tU0OkilVi1D4fmVjACrwoh5HP6aNqJ8kUnKsoy6D+R3Vi/O+fmdNGO7g==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} @@ -5768,11 +6125,11 @@ packages: peerDependencies: graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - '@urql/vue@2.0.0': - resolution: {integrity: sha512-9eW8IfEPwnGHxvqfH2t8cBSI5eKPyLq2dizFVYIRGHi4ydMw5Q+vuMD+VP0I9zo0818zZ9b8TGLiyAmOzvyoAQ==} + '@urql/vue@2.1.0': + resolution: {integrity: sha512-fRsMOSJze7d9y2NUd31ekZMUWDoc+HYv/jFcO9iPpRFCFlqcuqto5r0v54jDB6C7MEo+xLsqRQGuxe0NM0J8YA==} peerDependencies: '@urql/core': ^6.0.0 - vue: 3.5.31 + vue: 3.5.33 '@vitejs/plugin-legacy@2.3.1': resolution: {integrity: sha512-J5KaGBlSt2tEYPVjM/C8dA6DkRzkFkbPe+Xb4IX5G+XOV5OGbVAfkMjKywdrkO3gGynO8S98i71Lmsff4cWkCQ==} @@ -5788,18 +6145,18 @@ packages: terser: ^5.16.0 vite: ^7.0.0 - '@vitejs/plugin-vue@6.0.5': - resolution: {integrity: sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==} + '@vitejs/plugin-vue@6.0.6': + resolution: {integrity: sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - vue: 3.5.31 + vue: 3.5.33 - '@vitest/expect@4.1.2': - resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==} + '@vitest/expect@4.1.5': + resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} - '@vitest/mocker@4.1.2': - resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==} + '@vitest/mocker@4.1.5': + resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -5809,20 +6166,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.2': - resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} + '@vitest/pretty-format@4.1.5': + resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} - '@vitest/runner@4.1.2': - resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==} + '@vitest/runner@4.1.5': + resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} - '@vitest/snapshot@4.1.2': - resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==} + '@vitest/snapshot@4.1.5': + resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} - '@vitest/spy@4.1.2': - resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==} + '@vitest/spy@4.1.5': + resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} - '@vitest/utils@4.1.2': - resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} + '@vitest/utils@4.1.5': + resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} '@volar/language-core@1.10.10': resolution: {integrity: sha512-nsV1o3AZ5n5jaEAObrS3MWLBWaGwUj/vAsc15FVNIv+DbpizQRISg9wzygsHBr56ELRH8r4K75vkYNMtsSNNWw==} @@ -5845,14 +6202,20 @@ packages: '@vue/compiler-core@3.5.31': resolution: {integrity: sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==} + '@vue/compiler-core@3.5.33': + resolution: {integrity: sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==} + '@vue/compiler-dom@3.5.31': resolution: {integrity: sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==} - '@vue/compiler-sfc@3.5.31': - resolution: {integrity: sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==} + '@vue/compiler-dom@3.5.33': + resolution: {integrity: sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==} - '@vue/compiler-ssr@3.5.31': - resolution: {integrity: sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==} + '@vue/compiler-sfc@3.5.33': + resolution: {integrity: sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==} + + '@vue/compiler-ssr@3.5.33': + resolution: {integrity: sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==} '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} @@ -5898,33 +6261,39 @@ packages: '@vue/reactivity@3.5.31': resolution: {integrity: sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==} - '@vue/runtime-core@3.5.31': - resolution: {integrity: sha512-AZPmIHXEAyhpkmN7aWlqjSfYynmkWlluDNPHMCZKFHH+lLtxP/30UJmoVhXmbDoP1Ng0jG0fyY2zCj1PnSSA6Q==} + '@vue/reactivity@3.5.33': + resolution: {integrity: sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==} + + '@vue/runtime-core@3.5.33': + resolution: {integrity: sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==} - '@vue/runtime-dom@3.5.31': - resolution: {integrity: sha512-xQJsNRmGPeDCJq/u813tyonNgWBFjzfVkBwDREdEWndBnGdHLHgkwNBQxLtg4zDrzKTEcnikUy1UUNecb3lJ6g==} + '@vue/runtime-dom@3.5.33': + resolution: {integrity: sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==} - '@vue/server-renderer@3.5.31': - resolution: {integrity: sha512-GJuwRvMcdZX/CriUnyIIOGkx3rMV3H6sOu0JhdKbduaeCji6zb60iOGMY7tFoN24NfsUYoFBhshZtGxGpxO4iA==} + '@vue/server-renderer@3.5.33': + resolution: {integrity: sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 '@vue/shared@3.5.31': resolution: {integrity: sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==} + '@vue/shared@3.5.33': + resolution: {integrity: sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==} + '@vue/typescript@1.8.8': resolution: {integrity: sha512-jUnmMB6egu5wl342eaUH236v8tdcEPXXkPgj+eI/F6JwW/lb+yAU6U07ZbQ3MVabZRlupIlPESB7ajgAGixhow==} '@vueuse/core@14.2.1': resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 '@vueuse/core@8.9.4': resolution: {integrity: sha512-B/Mdj9TK1peFyWaPof+Zf/mP9XuGAngaJZBwPaXBvU3aCTZlx3ltlrFFFyMV4iGBwsjSCeUCgZrtkEj9dS2Y3Q==} peerDependencies: '@vue/composition-api': ^1.1.0 - vue: 3.5.31 + vue: 3.5.33 peerDependenciesMeta: '@vue/composition-api': optional: true @@ -5940,13 +6309,13 @@ packages: '@vueuse/shared@14.2.1': resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 '@vueuse/shared@8.9.4': resolution: {integrity: sha512-wt+T30c4K6dGRMVqPddexEVLa28YwxW5OFIPmzUHICjphfAuBFTTdDoyqREZNDOFJZ44ARH1WWQNCUK8koJ+Ag==} peerDependencies: '@vue/composition-api': ^1.1.0 - vue: 3.5.31 + vue: 3.5.33 peerDependenciesMeta: '@vue/composition-api': optional: true @@ -6023,8 +6392,8 @@ packages: resolution: {integrity: sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==} engines: {node: '>=16.0.0'} - '@xmldom/xmldom@0.8.11': - resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} + '@xmldom/xmldom@0.8.13': + resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} '@xtuc/ieee754@1.2.0': @@ -6036,6 +6405,9 @@ packages: '@zone-eu/mailsplit@5.4.8': resolution: {integrity: sha512-eEyACj4JZ7sjzRvy26QhLgKEMWwQbsw1+QZnlLX+/gihcNH07lVPOcnwf5U6UAL7gkc//J3jVd76o/WS+taUiA==} + a-sync-waterfall@1.0.1: + resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -6126,12 +6498,12 @@ packages: ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + alce@1.2.0: resolution: {integrity: sha512-XppPf2S42nO2WhvKzlwzlfcApcXHzjlod30pKmcWjRgLOtqoe5DMuqdiYoM6AgyXksc6A6pV4v1L/WW217e57w==} engines: {node: '>=0.8.0'} @@ -6268,8 +6640,8 @@ packages: resolution: {integrity: sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==} engines: {node: '>=8'} - autoprefixer@10.4.27: - resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + autoprefixer@10.5.0: + resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -6293,8 +6665,8 @@ packages: axios: '>=0.20.0' tough-cookie: '>=4.0.0' - axios@1.13.6: - resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} + axios@1.15.2: + resolution: {integrity: sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==} babel-jest@30.3.0: resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} @@ -6379,6 +6751,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + baseline-browser-mapping@2.10.23: + resolution: {integrity: sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g==} + engines: {node: '>=6.0.0'} + hasBin: true + basic-auth@2.0.1: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} @@ -6387,6 +6764,9 @@ packages: resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==} engines: {node: '>= 18'} + better-result@2.8.2: + resolution: {integrity: sha512-YOf0VSj5nUPI27doTtXF+BBnsiRq3qY7avHqfIWnppxTLGyvkLq1QV2RTxkwoZwJ60ywLfZ0raFF4J/G886i7A==} + bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -6417,6 +6797,9 @@ packages: brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} @@ -6443,6 +6826,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} engines: {node: '>= 6'} @@ -6483,10 +6871,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - c12@3.1.0: - resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: - magicast: ^0.3.5 + magicast: '*' peerDependenciesMeta: magicast: optional: true @@ -6503,6 +6891,10 @@ packages: resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} @@ -6535,6 +6927,9 @@ packages: caniuse-lite@1.0.30001781: resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} + caniuse-lite@1.0.30001791: + resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==} + capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -6578,6 +6973,10 @@ packages: resolution: {integrity: sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==} engines: {node: '>=4.0.0'} + chart.js@4.5.1: + resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} + engines: {pnpm: '>=8'} + check-disk-space@3.4.0: resolution: {integrity: sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==} engines: {node: '>=16'} @@ -6589,9 +6988,6 @@ packages: resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} engines: {node: '>= 6'} - chevrotain@10.5.0: - resolution: {integrity: sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -6600,6 +6996,10 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -6612,12 +7012,6 @@ packages: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - - citty@0.2.1: - resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} - cjs-module-lexer@2.2.0: resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} @@ -6726,6 +7120,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + commander@6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} engines: {node: '>= 6'} @@ -6738,8 +7136,8 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} - comment-json@4.4.1: - resolution: {integrity: sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==} + comment-json@5.0.0: + resolution: {integrity: sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==} engines: {node: '>= 6'} common-tags@1.8.2: @@ -6792,8 +7190,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - conventional-changelog-angular@8.3.0: - resolution: {integrity: sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==} + conventional-changelog-angular@8.3.1: + resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} conventional-changelog-conventionalcommits@9.3.0: @@ -6805,6 +7203,11 @@ packages: engines: {node: '>=18'} hasBin: true + conventional-commits-parser@6.4.0: + resolution: {integrity: sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==} + engines: {node: '>=18'} + hasBin: true + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -6818,9 +7221,6 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie-signature@1.0.7: - resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -6857,8 +7257,8 @@ packages: resolution: {integrity: sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==} engines: {node: '>= 0.4.0'} - cosmiconfig-typescript-loader@6.2.0: - resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==} + cosmiconfig-typescript-loader@6.3.0: + resolution: {integrity: sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==} engines: {node: '>=v18'} peerDependencies: '@types/node': '*' @@ -7102,8 +7502,8 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -7168,7 +7568,7 @@ packages: dioc@3.0.2: resolution: {integrity: sha512-D8S1vMTtBeXeUW2dR0rJ7xiPHxp1zm1NzO2B4Aj4RAJB6E6urA0/xD/CnGs6J1JkgUZvUgaC+oedx/k5NrT+/g==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 peerDependenciesMeta: vue: optional: true @@ -7208,8 +7608,11 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.3.3: - resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + + dompurify@3.4.1: + resolution: {integrity: sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==} domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -7236,12 +7639,12 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} - dotenv@17.2.3: - resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + dotenv@17.4.1: + resolution: {integrity: sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==} engines: {node: '>=12'} - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} dset@3.1.4: @@ -7275,9 +7678,17 @@ packages: engines: {node: '>=0.10.0'} hasBin: true + ejs@5.0.2: + resolution: {integrity: sha512-IpbUaI/CAW86l3f+T8zN0iggSc0LmMZLcIW5eRVStLVNCoTXkE0YlncbbH50fp8Cl6zHIky0sW2uUbhBqGw0Jw==} + engines: {node: '>=0.12.18'} + hasBin: true + electron-to-chromium@1.5.325: resolution: {integrity: sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==} + electron-to-chromium@1.5.344: + resolution: {integrity: sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==} + emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} @@ -7357,6 +7768,10 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -7375,6 +7790,10 @@ packages: resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} engines: {node: '>= 0.4'} + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -7593,8 +8012,8 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-vue@10.8.0: - resolution: {integrity: sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==} + eslint-plugin-vue@10.9.0: + resolution: {integrity: sha512-EFNNzu4HqtTRb5DJINpyd+u3bDdzETWDMpCzG+UBHz1tpsnMDCeOcf61u4Wy/cbXnMymK+MT9bjH7KcG1fItSw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -7631,8 +8050,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.0.3: - resolution: {integrity: sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==} + eslint@10.2.1: + resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -7761,10 +8180,6 @@ packages: resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - express-session@1.19.0: - resolution: {integrity: sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==} - engines: {node: '>= 0.8.0'} - express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -7853,8 +8268,8 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - file-type@21.3.2: - resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} file-type@3.9.0: @@ -7898,8 +8313,8 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -8033,8 +8448,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - giget@2.0.0: - resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + giget@3.2.0: + resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} hasBin: true git-raw-commits@5.0.1: @@ -8064,10 +8479,6 @@ packages: 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 hasBin: true - glob@13.0.0: - resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} - engines: {node: 20 || >=22} - glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -8076,9 +8487,9 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 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 - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} - engines: {node: '>=18'} + global-directory@5.0.0: + resolution: {integrity: sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==} + engines: {node: '>=20'} globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} @@ -8088,8 +8499,8 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} - globals@17.4.0: - resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} + globals@17.5.0: + resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} engines: {node: '>=18'} globalthis@1.0.4: @@ -8184,8 +8595,8 @@ packages: peerDependencies: graphql: '>=0.11 <=16' - graphql-ws@6.0.7: - resolution: {integrity: sha512-yoLRW+KRlDmnnROdAu7sX77VNLC0bsFoZyGQJLy1cF+X/SkLg/fWkRGrEEYQK8o2cafJ2wmEaMqMEZB3U3DYDg==} + graphql-ws@6.0.8: + resolution: {integrity: sha512-m3EOaNsUBXwAnkBWbzPfe0Nq8pXUfxsWnolC54sru3FzHvhTZL0Ouf/BoQsaGAXqM+YPerXOJ47BUnmgmoupCw==} engines: {node: '>=20'} peerDependencies: '@fastify/websocket': ^10 || ^11 @@ -8200,8 +8611,8 @@ packages: ws: optional: true - graphql@16.13.1: - resolution: {integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==} + graphql@16.13.2: + resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} handlebars@4.7.9: @@ -8249,6 +8660,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + hawk@9.0.2: resolution: {integrity: sha512-EJMLBZAWg+EoI/aAJWDhrYGvucWYvY37CdGXolkol0ITGswkDHtDnjbFcPBaIv3jbtpfWqYjXMm4KhfXPOLCRg==} @@ -8266,8 +8681,8 @@ packages: highlightjs-curl@1.3.0: resolution: {integrity: sha512-50UEfZq1KR0Lfk2Tr6xb/MUIZH3h10oNC0OTy9g7WELcs5Fgy/mKN1vEhuKTkKbdo8vr5F9GXstu2eLhApfQ3A==} - hono@4.12.7: - resolution: {integrity: sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==} + hono@4.12.15: + resolution: {integrity: sha512-qM0jDhFEaCBb4TxoW7f53Qrpv9RBiayUHo0S52JudprkhvpjIrGoU1mnnr29Fvd1U335ZFPZQY1wlkqgfGXyLg==} engines: {node: '>=16.9.0'} hookable@6.1.0: @@ -8449,9 +8864,9 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} insomnia-importers@3.6.0: resolution: {integrity: sha512-42FvUCwQcHg8OSr2EtppkfByPVQFhBgaxhpu7zslnvQXtf/tLU568xmAxI6fMIY0S69u2J2SyIli3x7qm+9r2w==} @@ -8856,12 +9271,12 @@ packages: resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-mock-extended@4.0.0: - resolution: {integrity: sha512-7BZpfuvLam+/HC+NxifIi9b+5VXj/utUDMPUqrDJehGWVuXPtLS9Jqlob2mJLrI/pg2k1S8DMfKDvEB88QNjaQ==} + jest-mock-extended@4.0.1: + resolution: {integrity: sha512-Q/4k/yefiv/Al3n755V9xDEwMiL+7LwkjRKjaORkgCdovZv00hF/D0QypLoqO+MVfrYkzCYa4BYlcEKA74iOgQ==} peerDependencies: '@jest/globals': ^28.0.0 || ^29.0.0 || ^30.0.0 jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 || ^30.0.0 - typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 + typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 jest-mock@30.3.0: resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} @@ -9005,9 +9420,6 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -9030,6 +9442,9 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + jsonpointer@5.0.1: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} @@ -9088,10 +9503,6 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -9111,8 +9522,8 @@ packages: resolution: {integrity: sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==} engines: {node: '>=4'} - liquidjs@10.25.0: - resolution: {integrity: sha512-XpO7AiGULTG4xcTlwkcTI5JreFG7b6esLCLp+aUSh7YuQErJZEoUXre9u9rbdb0057pfWG4l0VursvLd5Q/eAw==} + liquidjs@10.25.7: + resolution: {integrity: sha512-rPCjJLiD4eDhQjvv964AeXFC+HbeYBbZrd7Z82Q6hqv1lX7G+5w4SJcKLn9CAAAwHI4aS3dTdo083UB79K3pDA==} engines: {node: '>=16'} hasBin: true @@ -9148,8 +9559,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.23: - resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -9201,9 +9612,8 @@ packages: lodash.mergewith@4.6.2: resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - lodash.omit@4.5.0: - resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==} - deprecated: This package is deprecated. Use destructuring assignment syntax instead. + lodash.omit@4.18.0: + resolution: {integrity: sha512-hZXIupXdHtocTnvIJ2aCd2vxKYtxex6gbiGuPvgBRnFQO9yu3AtmDAbVuCXcSsQx3INo/1g71OktlFFA/ES8Xg==} lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} @@ -9223,8 +9633,8 @@ packages: lodash.upperfirst@4.3.1: resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} @@ -9441,6 +9851,14 @@ packages: resolution: {integrity: sha512-0htgU9jHBKHj95GPRwJaz73vT2ABPD7ge+OYBarvKbNtKkVQtxlIJb12LIl5ImbKqh1zcreY2fwKc8FnemLy5A==} engines: {node: '>=10'} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -9646,9 +10064,6 @@ packages: resolution: {integrity: sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==} engines: {node: 4.x || >=6.0.0} - node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -9675,12 +10090,15 @@ packages: node-releases@2.0.36: resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + node-releases@2.0.38: + resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} + nodemailer@7.0.13: resolution: {integrity: sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw==} engines: {node: '>=6.0.0'} - nodemailer@8.0.4: - resolution: {integrity: sha512-k+jf6N8PfQJ0Fe8ZhJlgqU5qJU44Lpvp2yvidH3vp1lPnVQMgi4yEEMPXg5eJS1gFIJTVq1NHBk7Ia9ARdSBdQ==} + nodemailer@8.0.7: + resolution: {integrity: sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==} engines: {node: '>=6.0.0'} normalize-package-data@2.5.0: @@ -9720,10 +10138,15 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - nypm@0.6.5: - resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} - engines: {node: '>=18'} + nunjucks@3.2.4: + resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} + engines: {node: '>= 6.9.0'} hasBin: true + peerDependencies: + chokidar: ^3.3.0 + peerDependenciesMeta: + chokidar: + optional: true oas-kit-common@1.0.8: resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==} @@ -9764,9 +10187,6 @@ packages: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} - obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -10013,6 +10433,9 @@ packages: path-to-regexp@8.4.0: resolution: {integrity: sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} engines: {node: '>=4'} @@ -10043,9 +10466,6 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - perfect-debounce@2.1.0: resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} @@ -10059,10 +10479,6 @@ packages: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-numeric@1.0.2: - resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} - engines: {node: '>=4'} - pg-pool@3.13.0: resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} peerDependencies: @@ -10075,10 +10491,6 @@ packages: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg-types@4.1.0: - resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==} - engines: {node: '>=10'} - pg@8.20.0: resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} engines: {node: '>= 16.0.0'} @@ -10098,10 +10510,6 @@ packages: resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} @@ -10366,8 +10774,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -10382,35 +10790,20 @@ packages: resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} engines: {node: '>=0.10.0'} - postgres-bytea@3.0.0: - resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} - engines: {node: '>= 6'} - postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} - postgres-date@2.1.0: - resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} - engines: {node: '>=12'} - postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} - postgres-interval@3.0.0: - resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} - engines: {node: '>=12'} - - postgres-range@1.1.4: - resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - postgres@3.4.7: resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} engines: {node: '>=12'} - posthog-node@5.28.4: - resolution: {integrity: sha512-j8JBDNuSwUWR0TBZNuCwNRHQ+OReVz1UwDYMDol+iqFTbYrIKZnyC05oyGtSBRGntrYBiaIWFbH9N3kZuxfVdg==} + posthog-node@5.30.6: + resolution: {integrity: sha512-deZuSiLkpdEipiywkww1FhQoKpVVFmJP6SAVQcZcMbugTLwJRYSGjgm+qV0Y91xghf2yP6Nr5Plfl52i9Qj15Q==} engines: {node: ^20.20.0 || >=22.22.0} peerDependencies: rxjs: ^7.0.0 @@ -10556,8 +10949,8 @@ packages: prettier-plugin-svelte: optional: true - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true @@ -10581,8 +10974,8 @@ packages: resolution: {integrity: sha512-nrdhnt+E9ClJ4khk9rNzqgsxubH7xSJSKoqXx/7aed2eghegNGNWkSGOelNgFgUtMz3LmKGks0waH2NuXWWmPg==} engines: {node: '>=14'} - prisma@7.5.0: - resolution: {integrity: sha512-n30qZpWehaYQzigLjmuPisyEsvOzHt7bZeRyg8gZ5DvJo9FGjD+gNaY59Ns3hlLD5/jZH5GBeftIss0jDbUoLg==} + prisma@7.8.0: + resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} engines: {node: ^20.19 || ^22.12 || >=24.0} hasBin: true peerDependencies: @@ -10611,8 +11004,9 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -10684,6 +11078,10 @@ packages: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} + qs@6.15.1: + resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -10709,13 +11107,6 @@ packages: ramda@0.27.2: resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==} - random-bytes@1.0.0: - resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} - engines: {node: '>= 0.8'} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -10724,8 +11115,8 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} @@ -10769,6 +11160,10 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} @@ -10800,9 +11195,6 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regexp-to-ast@0.5.0: - resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==} - regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -10868,6 +11260,11 @@ packages: engines: {node: '>= 0.4'} hasBin: true + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -10911,7 +11308,7 @@ packages: rollup-plugin-polyfill-node@0.13.0: resolution: {integrity: sha512-FYEvpCaD5jGtyBuBFcQImEGmTxDTPbiHjJdrYIp+mFIwgXiXabxvKUK7ZT9P31ozu2Tqm9llYQMRWsfvTMTAOw==} peerDependencies: - rollup: 4.59.0 + rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} @@ -10926,6 +11323,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.60.2: + resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -10951,6 +11353,10 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -10968,8 +11374,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.98.0: - resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} + sass@1.99.0: + resolution: {integrity: sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==} engines: {node: '>=14.0.0'} hasBin: true @@ -11026,8 +11432,9 @@ packages: seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.0.3: + resolution: {integrity: sha512-h+cZ/XXarqDgCjo+YSyQU/ulDEESGGf8AMK9pPNmhNSl/FzPl6L8pMp1leca5z6NuG6tvV/auC8/43tmovowww==} + engines: {node: '>=20.0.0'} serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} @@ -11443,8 +11850,8 @@ packages: resolution: {integrity: sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==} engines: {node: '>=10'} - swagger-ui-dist@5.31.0: - resolution: {integrity: sha512-zSUTIck02fSga6rc0RZP3b7J7wgHXwLea8ZjgLA3Vgnb8QeOl3Wou2/j5QkzSGeoz6HusP/coYuJl33aQxQZpg==} + swagger-ui-dist@5.32.4: + resolution: {integrity: sha512-0AADFFQNJzExEN49SrD/34Nn9cxNxVLiydYl2MBwSZFPVXNkVwC/EFAjoezGGqE8oDegiDC+p47t8lKObCinMQ==} swagger2openapi@7.0.8: resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} @@ -11558,10 +11965,18 @@ packages: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} @@ -11647,8 +12062,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-jest@29.4.6: - resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} + ts-jest@29.4.9: + resolution: {integrity: sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -11659,7 +12074,7 @@ packages: esbuild: '*' jest: ^29.0.0 || ^30.0.0 jest-util: ^29.0.0 || ^30.0.0 - typescript: '>=4.3 <6' + typescript: '>=4.3 <7' peerDependenciesMeta: '@babel/core': optional: true @@ -11674,8 +12089,8 @@ packages: jest-util: optional: true - ts-loader@9.5.4: - resolution: {integrity: sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==} + ts-loader@9.5.7: + resolution: {integrity: sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==} engines: {node: '>=12.0.0'} peerDependencies: typescript: '*' @@ -11723,9 +12138,6 @@ packages: tslib@2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - tslib@2.6.3: - resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -11831,10 +12243,6 @@ packages: engines: {node: '>=0.8.0'} hasBin: true - 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==} @@ -11857,8 +12265,8 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} unhead@2.1.12: resolution: {integrity: sha512-iTHdWD9ztTunOErtfUFk6Wr11BxvzumcYJ0CzaSCBUOEtg+DUZ9+gnE99i8QkLFT2q1rZD48BYYGXpOZVDLYkA==} @@ -11951,7 +12359,7 @@ packages: peerDependencies: '@babel/parser': ^7.15.8 '@nuxt/kit': ^3.2.2 || ^4.0.0 - vue: 3.5.31 + vue: 3.5.33 peerDependenciesMeta: '@babel/parser': optional: true @@ -12213,7 +12621,7 @@ packages: resolution: {integrity: sha512-uh6NW7lt+aOXujK4eHfiNbeo55K9OTuB7fnv+5RVc4OBn/cZull6ThXdYH03JzKanUfgt6QZ37NbbtJ0og59qw==} peerDependencies: vite: ^4.0.0 || ^5.0.0 - vue: 3.5.31 + vue: 3.5.33 vue-router: ^4.0.11 vite@3.2.11: @@ -12241,8 +12649,8 @@ packages: terser: optional: true - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@7.3.2: + resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -12289,18 +12697,20 @@ packages: vite: optional: true - vitest@4.1.2: - resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} + vitest@4.1.5: + resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.2 - '@vitest/browser-preview': 4.1.2 - '@vitest/browser-webdriverio': 4.1.2 - '@vitest/ui': 4.1.2 + '@vitest/browser-playwright': 4.1.5 + '@vitest/browser-preview': 4.1.5 + '@vitest/browser-webdriverio': 4.1.5 + '@vitest/coverage-istanbul': 4.1.5 + '@vitest/coverage-v8': 4.1.5 + '@vitest/ui': 4.1.5 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -12317,6 +12727,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -12340,7 +12754,7 @@ packages: hasBin: true peerDependencies: '@vue/composition-api': ^1.0.0-rc.1 - vue: 3.5.31 + vue: 3.5.33 peerDependenciesMeta: '@vue/composition-api': optional: true @@ -12351,22 +12765,22 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-i18n@11.3.0: - resolution: {integrity: sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA==} + vue-i18n@11.4.0: + resolution: {integrity: sha512-gxLVtcwdvOgwKSzkdb7nHKlW0N85A6aDNmHLnq6V+3w2/BXy/os5l71P7TIlgIQTxX0zJjiz89iImoHi51GieQ==} engines: {node: '>= 16'} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 vue-json-pretty@2.6.0: resolution: {integrity: sha512-glz1aBVS35EO8+S9agIl3WOQaW2cJZW192UVKTuGmryx01ZvOVWc4pR3t+5UcyY4jdOfBUgVHjcpRpcnjRhCAg==} engines: {node: '>= 10.0.0', npm: '>= 5.0.0'} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 vue-pdf-embed@2.1.4: resolution: {integrity: sha512-rZuRpQ4kJXKXCdZBCg3WZcYfrhDMJElcJQsS1V8KlJICDtFzzAzeDDSJwQU89Dx447Dv018P3zj/4UiAjBwvyg==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 vue-promise-modals@0.1.0: resolution: {integrity: sha512-LmPejeqvZSkxj4KkJe6ZUEJmCUQXVeEAj9ihTX+BRFfZftVCZSZd3B4uuZSKF0iCeQUemkodXUZFxcsNT/2dmg==} @@ -12374,7 +12788,7 @@ packages: vue-router@4.6.4: resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 vue-template-compiler@2.7.16: resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} @@ -12382,7 +12796,7 @@ packages: vue-tippy@6.7.1: resolution: {integrity: sha512-gdHbBV5/Vc8gH87hQHLA7TN1K4BlLco3MAPrTb70ZYGXxx+55rAU4a4mt0fIoP+gB3etu1khUZ6c29Br1n0CiA==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 vue-tsc@1.8.8: resolution: {integrity: sha512-bSydNFQsF7AMvwWsRXD7cBIXaNs/KSjvzWLymq/UtKE36697sboX4EccSHFVxvgdBlI1frYPc/VMKJNB7DFeDQ==} @@ -12402,8 +12816,8 @@ packages: peerDependencies: typescript: '>=5.0.0' - vue@3.5.31: - resolution: {integrity: sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==} + vue@3.5.33: + resolution: {integrity: sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -12413,7 +12827,7 @@ packages: vuedraggable-es@4.1.1: resolution: {integrity: sha512-F35pjSwC8HS/lnaOd+B59nYR4FZmwuhWAzccK9xftRuWds8SU1TZh5myKVM86j5dFOI7S26O64Kwe7LUHnXjlA==} peerDependencies: - vue: 3.5.31 + vue: 3.5.33 w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -12464,8 +12878,8 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.104.1: - resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} + webpack@5.106.0: + resolution: {integrity: sha512-Pkx5joZ9RrdgO5LBkyX1L2ZAJeK/Taz3vqZ9CbcP0wS5LEMx5QkKsEwLl29QJfihZ+DKRBFldzy1O30pJ1MDpA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -12778,15 +13192,15 @@ packages: snapshots: - '@0no-co/graphql.web@1.2.0(graphql@16.13.1)': + '@0no-co/graphql.web@1.2.0(graphql@16.13.2)': optionalDependencies: - graphql: 16.13.1 + graphql: 16.13.2 '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/0d58d53be2bc75aeb5916bd0d77794fd209426af': dependencies: '@tauri-apps/api': 2.9.1 - '@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/7cf09c1ad31e228758738c2f4e1c8fe9cc141291': + '@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/42f449e1c5657679fecf0374b0ce5047ad03c069': dependencies: '@tauri-apps/api': 2.1.1 @@ -12794,33 +13208,22 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@angular-devkit/core@19.2.17(chokidar@4.0.3)': + '@angular-devkit/core@19.2.24(chokidar@4.0.3)': dependencies: - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - jsonc-parser: 3.3.1 - picomatch: 4.0.2 - rxjs: 7.8.1 - source-map: 0.7.4 - optionalDependencies: - chokidar: 4.0.3 - - '@angular-devkit/core@19.2.19(chokidar@4.0.3)': - dependencies: - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) jsonc-parser: 3.3.1 - picomatch: 4.0.2 + picomatch: 4.0.4 rxjs: 7.8.1 source-map: 0.7.4 optionalDependencies: chokidar: 4.0.3 - '@angular-devkit/schematics-cli@19.2.19(@types/node@25.5.0)(chokidar@4.0.3)': + '@angular-devkit/schematics-cli@19.2.24(@types/node@25.6.0)(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 19.2.19(chokidar@4.0.3) - '@angular-devkit/schematics': 19.2.19(chokidar@4.0.3) - '@inquirer/prompts': 7.3.2(@types/node@25.5.0) + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + '@inquirer/prompts': 7.3.2(@types/node@25.6.0) ansi-colors: 4.1.3 symbol-observable: 4.0.0 yargs-parser: 21.1.1 @@ -12828,19 +13231,9 @@ snapshots: - '@types/node' - chokidar - '@angular-devkit/schematics@19.2.17(chokidar@4.0.3)': - dependencies: - '@angular-devkit/core': 19.2.17(chokidar@4.0.3) - jsonc-parser: 3.3.1 - magic-string: 0.30.17 - ora: 5.4.1 - rxjs: 7.8.1 - transitivePeerDependencies: - - chokidar - - '@angular-devkit/schematics@19.2.19(chokidar@4.0.3)': + '@angular-devkit/schematics@19.2.24(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 19.2.19(chokidar@4.0.3) + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) jsonc-parser: 3.3.1 magic-string: 0.30.17 ora: 5.4.1 @@ -12853,10 +13246,9 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.4 - '@apideck/better-ajv-errors@0.3.6(ajv@8.18.0)': + '@apideck/better-ajv-errors@0.3.7(ajv@8.20.0)': dependencies: - ajv: 8.18.0 - json-schema: 0.4.0 + ajv: 8.20.0 jsonpointer: 5.0.1 leven: 3.1.0 @@ -12906,9 +13298,9 @@ snapshots: call-me-maybe: 1.0.2 openapi-types: 12.1.3 - '@apollo/cache-control-types@1.0.3(graphql@16.13.1)': + '@apollo/cache-control-types@1.0.3(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 '@apollo/protobufjs@1.2.7': dependencies: @@ -12925,38 +13317,38 @@ snapshots: '@types/long': 4.0.2 long: 4.0.0 - '@apollo/server-gateway-interface@2.0.0(graphql@16.13.1)': + '@apollo/server-gateway-interface@2.0.0(graphql@16.13.2)': dependencies: '@apollo/usage-reporting-protobuf': 4.1.1 '@apollo/utils.fetcher': 3.1.0 '@apollo/utils.keyvaluecache': 4.0.0 '@apollo/utils.logger': 3.0.0 - graphql: 16.13.1 + graphql: 16.13.2 - '@apollo/server-plugin-landing-page-graphql-playground@4.0.1(@apollo/server@5.5.0(graphql@16.13.1))': + '@apollo/server-plugin-landing-page-graphql-playground@4.0.1(@apollo/server@5.5.0(graphql@16.13.2))': dependencies: - '@apollo/server': 5.5.0(graphql@16.13.1) + '@apollo/server': 5.5.0(graphql@16.13.2) '@apollographql/graphql-playground-html': 1.6.29 - '@apollo/server@5.5.0(graphql@16.13.1)': + '@apollo/server@5.5.0(graphql@16.13.2)': dependencies: - '@apollo/cache-control-types': 1.0.3(graphql@16.13.1) - '@apollo/server-gateway-interface': 2.0.0(graphql@16.13.1) + '@apollo/cache-control-types': 1.0.3(graphql@16.13.2) + '@apollo/server-gateway-interface': 2.0.0(graphql@16.13.2) '@apollo/usage-reporting-protobuf': 4.1.1 '@apollo/utils.createhash': 3.0.1 '@apollo/utils.fetcher': 3.1.0 '@apollo/utils.isnodelike': 3.0.0 '@apollo/utils.keyvaluecache': 4.0.0 '@apollo/utils.logger': 3.0.0 - '@apollo/utils.usagereporting': 2.1.0(graphql@16.13.1) + '@apollo/utils.usagereporting': 2.1.0(graphql@16.13.2) '@apollo/utils.withrequired': 3.0.0 - '@graphql-tools/schema': 10.0.31(graphql@16.13.1) + '@graphql-tools/schema': 10.0.31(graphql@16.13.2) async-retry: 1.3.3 body-parser: 2.2.1 content-type: 1.0.5 cors: 2.8.6 finalhandler: 2.1.1 - graphql: 16.13.1 + graphql: 16.13.2 loglevel: 1.9.2 lru-cache: 11.2.7 negotiator: 1.0.0 @@ -12974,9 +13366,9 @@ snapshots: '@apollo/utils.isnodelike': 3.0.0 sha.js: 2.4.12 - '@apollo/utils.dropunuseddefinitions@2.0.1(graphql@16.13.1)': + '@apollo/utils.dropunuseddefinitions@2.0.1(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 '@apollo/utils.fetcher@3.1.0': {} @@ -12989,32 +13381,32 @@ snapshots: '@apollo/utils.logger@3.0.0': {} - '@apollo/utils.printwithreducedwhitespace@2.0.1(graphql@16.13.1)': + '@apollo/utils.printwithreducedwhitespace@2.0.1(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - '@apollo/utils.removealiases@2.0.1(graphql@16.13.1)': + '@apollo/utils.removealiases@2.0.1(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - '@apollo/utils.sortast@2.0.1(graphql@16.13.1)': + '@apollo/utils.sortast@2.0.1(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 lodash.sortby: 4.7.0 - '@apollo/utils.stripsensitiveliterals@2.0.1(graphql@16.13.1)': + '@apollo/utils.stripsensitiveliterals@2.0.1(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - '@apollo/utils.usagereporting@2.1.0(graphql@16.13.1)': + '@apollo/utils.usagereporting@2.1.0(graphql@16.13.2)': dependencies: '@apollo/usage-reporting-protobuf': 4.1.1 - '@apollo/utils.dropunuseddefinitions': 2.0.1(graphql@16.13.1) - '@apollo/utils.printwithreducedwhitespace': 2.0.1(graphql@16.13.1) - '@apollo/utils.removealiases': 2.0.1(graphql@16.13.1) - '@apollo/utils.sortast': 2.0.1(graphql@16.13.1) - '@apollo/utils.stripsensitiveliterals': 2.0.1(graphql@16.13.1) - graphql: 16.13.1 + '@apollo/utils.dropunuseddefinitions': 2.0.1(graphql@16.13.2) + '@apollo/utils.printwithreducedwhitespace': 2.0.1(graphql@16.13.2) + '@apollo/utils.removealiases': 2.0.1(graphql@16.13.2) + '@apollo/utils.sortast': 2.0.1(graphql@16.13.2) + '@apollo/utils.stripsensitiveliterals': 2.0.1(graphql@16.13.2) + graphql: 16.13.2 '@apollo/utils.withrequired@3.0.0': {} @@ -13022,7 +13414,7 @@ snapshots: dependencies: xss: 1.0.15 - '@ardatan/relay-compiler@12.0.0(graphql@16.13.1)': + '@ardatan/relay-compiler@12.0.0(graphql@16.13.2)': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -13035,7 +13427,7 @@ snapshots: fb-watchman: 2.0.2 fbjs: 3.0.5 glob: 7.2.3 - graphql: 16.13.1 + graphql: 16.13.2 immutable: 3.7.6 invariant: 2.2.4 nullthrows: 1.1.1 @@ -13046,10 +13438,10 @@ snapshots: - encoding - supports-color - '@ardatan/relay-compiler@13.0.0(graphql@16.13.1)': + '@ardatan/relay-compiler@13.0.1(graphql@16.13.2)': dependencies: '@babel/runtime': 7.29.2 - graphql: 16.13.1 + graphql: 16.13.2 immutable: 5.1.5 invariant: 2.2.4 @@ -13059,9 +13451,9 @@ snapshots: transitivePeerDependencies: - encoding - '@as-integrations/express5@1.1.2(@apollo/server@5.5.0(graphql@16.13.1))(express@5.2.1)': + '@as-integrations/express5@1.1.2(@apollo/server@5.5.0(graphql@16.13.2))(express@5.2.1)': dependencies: - '@apollo/server': 5.5.0(graphql@16.13.1) + '@apollo/server': 5.5.0(graphql@16.13.2) express: 5.2.1 '@asamuzakjp/css-color@4.1.2': @@ -13866,24 +14258,9 @@ snapshots: '@borewit/text-codec@0.2.2': {} - '@boringer-avatars/vue3@0.2.1(vue@3.5.31(typescript@5.9.3))': - dependencies: - vue: 3.5.31(typescript@5.9.3) - - '@chevrotain/cst-dts-gen@10.5.0': + '@boringer-avatars/vue3@0.2.1(vue@3.5.33(typescript@5.9.3))': dependencies: - '@chevrotain/gast': 10.5.0 - '@chevrotain/types': 10.5.0 - lodash: 4.17.23 - - '@chevrotain/gast@10.5.0': - dependencies: - '@chevrotain/types': 10.5.0 - lodash: 4.17.23 - - '@chevrotain/types@10.5.0': {} - - '@chevrotain/utils@10.5.0': {} + vue: 3.5.33(typescript@5.9.3) '@codemirror/autocomplete@6.20.0': dependencies: @@ -13970,14 +14347,14 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@commitlint/cli@20.5.0(@types/node@24.10.1)(conventional-commits-parser@6.3.0)(typescript@5.9.3)': + '@commitlint/cli@20.5.2(@types/node@24.10.1)(conventional-commits-parser@6.4.0)(typescript@5.9.3)': dependencies: '@commitlint/format': 20.5.0 '@commitlint/lint': 20.5.0 - '@commitlint/load': 20.5.0(@types/node@24.10.1)(typescript@5.9.3) - '@commitlint/read': 20.5.0(conventional-commits-parser@6.3.0) + '@commitlint/load': 20.5.2(@types/node@24.10.1)(typescript@5.9.3) + '@commitlint/read': 20.5.0(conventional-commits-parser@6.4.0) '@commitlint/types': 20.5.0 - tinyexec: 1.0.4 + tinyexec: 1.1.1 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' @@ -13993,7 +14370,7 @@ snapshots: '@commitlint/config-validator@20.5.0': dependencies: '@commitlint/types': 20.5.0 - ajv: 8.18.0 + ajv: 8.20.0 '@commitlint/ensure@20.5.0': dependencies: @@ -14023,14 +14400,14 @@ snapshots: '@commitlint/rules': 20.5.0 '@commitlint/types': 20.5.0 - '@commitlint/load@20.5.0(@types/node@24.10.1)(typescript@5.9.3)': + '@commitlint/load@20.5.2(@types/node@24.10.1)(typescript@5.9.3)': dependencies: '@commitlint/config-validator': 20.5.0 '@commitlint/execute-rule': 20.0.0 - '@commitlint/resolve-extends': 20.5.0 + '@commitlint/resolve-extends': 20.5.2 '@commitlint/types': 20.5.0 cosmiconfig: 9.0.1(typescript@5.9.3) - cosmiconfig-typescript-loader: 6.2.0(@types/node@24.10.1)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3) + cosmiconfig-typescript-loader: 6.3.0(@types/node@24.10.1)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3) is-plain-obj: 4.1.0 lodash.mergewith: 4.6.2 picocolors: 1.1.1 @@ -14043,25 +14420,25 @@ snapshots: '@commitlint/parse@20.5.0': dependencies: '@commitlint/types': 20.5.0 - conventional-changelog-angular: 8.3.0 - conventional-commits-parser: 6.3.0 + conventional-changelog-angular: 8.3.1 + conventional-commits-parser: 6.4.0 - '@commitlint/read@20.5.0(conventional-commits-parser@6.3.0)': + '@commitlint/read@20.5.0(conventional-commits-parser@6.4.0)': dependencies: '@commitlint/top-level': 20.4.3 '@commitlint/types': 20.5.0 - git-raw-commits: 5.0.1(conventional-commits-parser@6.3.0) + git-raw-commits: 5.0.1(conventional-commits-parser@6.4.0) minimist: 1.2.8 - tinyexec: 1.0.4 + tinyexec: 1.1.1 transitivePeerDependencies: - conventional-commits-filter - conventional-commits-parser - '@commitlint/resolve-extends@20.5.0': + '@commitlint/resolve-extends@20.5.2': dependencies: '@commitlint/config-validator': 20.5.0 '@commitlint/types': 20.5.0 - global-directory: 4.0.1 + global-directory: 5.0.0 import-meta-resolve: 4.2.0 lodash.mergewith: 4.6.2 resolve-from: 5.0.0 @@ -14084,60 +14461,64 @@ snapshots: conventional-commits-parser: 6.3.0 picocolors: 1.1.1 - '@conventional-changelog/git-client@2.6.0(conventional-commits-parser@6.3.0)': + '@conventional-changelog/git-client@2.7.0(conventional-commits-parser@6.4.0)': dependencies: '@simple-libs/child-process-utils': 1.0.2 '@simple-libs/stream-utils': 1.2.0 semver: 7.7.4 optionalDependencies: - conventional-commits-parser: 6.3.0 + conventional-commits-parser: 6.4.0 '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@css-inline/css-inline-android-arm-eabi@0.14.1': + '@css-inline/css-inline-android-arm-eabi@0.20.0': + optional: true + + '@css-inline/css-inline-android-arm64@0.20.0': optional: true - '@css-inline/css-inline-android-arm64@0.14.1': + '@css-inline/css-inline-darwin-arm64@0.20.0': optional: true - '@css-inline/css-inline-darwin-arm64@0.14.1': + '@css-inline/css-inline-darwin-x64@0.20.0': optional: true - '@css-inline/css-inline-darwin-x64@0.14.1': + '@css-inline/css-inline-linux-arm-gnueabihf@0.20.0': optional: true - '@css-inline/css-inline-linux-arm-gnueabihf@0.14.1': + '@css-inline/css-inline-linux-arm64-gnu@0.20.0': optional: true - '@css-inline/css-inline-linux-arm64-gnu@0.14.1': + '@css-inline/css-inline-linux-arm64-musl@0.20.0': optional: true - '@css-inline/css-inline-linux-arm64-musl@0.14.1': + '@css-inline/css-inline-linux-x64-gnu@0.20.0': optional: true - '@css-inline/css-inline-linux-x64-gnu@0.14.1': + '@css-inline/css-inline-linux-x64-musl@0.20.0': optional: true - '@css-inline/css-inline-linux-x64-musl@0.14.1': + '@css-inline/css-inline-win32-arm64-msvc@0.20.0': optional: true - '@css-inline/css-inline-win32-x64-msvc@0.14.1': + '@css-inline/css-inline-win32-x64-msvc@0.20.0': optional: true - '@css-inline/css-inline@0.14.1': + '@css-inline/css-inline@0.20.0': optionalDependencies: - '@css-inline/css-inline-android-arm-eabi': 0.14.1 - '@css-inline/css-inline-android-arm64': 0.14.1 - '@css-inline/css-inline-darwin-arm64': 0.14.1 - '@css-inline/css-inline-darwin-x64': 0.14.1 - '@css-inline/css-inline-linux-arm-gnueabihf': 0.14.1 - '@css-inline/css-inline-linux-arm64-gnu': 0.14.1 - '@css-inline/css-inline-linux-arm64-musl': 0.14.1 - '@css-inline/css-inline-linux-x64-gnu': 0.14.1 - '@css-inline/css-inline-linux-x64-musl': 0.14.1 - '@css-inline/css-inline-win32-x64-msvc': 0.14.1 + '@css-inline/css-inline-android-arm-eabi': 0.20.0 + '@css-inline/css-inline-android-arm64': 0.20.0 + '@css-inline/css-inline-darwin-arm64': 0.20.0 + '@css-inline/css-inline-darwin-x64': 0.20.0 + '@css-inline/css-inline-linux-arm-gnueabihf': 0.20.0 + '@css-inline/css-inline-linux-arm64-gnu': 0.20.0 + '@css-inline/css-inline-linux-arm64-musl': 0.20.0 + '@css-inline/css-inline-linux-x64-gnu': 0.20.0 + '@css-inline/css-inline-linux-x64-musl': 0.20.0 + '@css-inline/css-inline-win32-arm64-msvc': 0.20.0 + '@css-inline/css-inline-win32-x64-msvc': 0.20.0 '@csstools/color-helpers@6.0.2': {} @@ -14171,15 +14552,15 @@ snapshots: '@digitak/grubber@3.1.4': {} - '@electric-sql/pglite-socket@0.0.20(@electric-sql/pglite@0.3.15)': + '@electric-sql/pglite-socket@0.1.1(@electric-sql/pglite@0.4.1)': dependencies: - '@electric-sql/pglite': 0.3.15 + '@electric-sql/pglite': 0.4.1 - '@electric-sql/pglite-tools@0.2.20(@electric-sql/pglite@0.3.15)': + '@electric-sql/pglite-tools@0.3.1(@electric-sql/pglite@0.4.1)': dependencies: - '@electric-sql/pglite': 0.3.15 + '@electric-sql/pglite': 0.4.1 - '@electric-sql/pglite@0.3.15': {} + '@electric-sql/pglite@0.4.1': {} '@emnapi/core@1.9.1': dependencies: @@ -14454,9 +14835,9 @@ snapshots: '@esbuild/win32-x64@0.27.4': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.3(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))': dependencies: - eslint: 10.0.3(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': @@ -14474,9 +14855,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-array@0.23.3': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 3.0.3 + '@eslint/object-schema': 3.0.5 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.4 transitivePeerDependencies: @@ -14486,15 +14867,15 @@ snapshots: dependencies: '@eslint/core': 0.17.0 - '@eslint/config-helpers@0.5.3': + '@eslint/config-helpers@0.5.5': dependencies: - '@eslint/core': 1.1.1 + '@eslint/core': 1.2.1 '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@1.1.1': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 @@ -14512,29 +14893,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@10.0.1(eslint@10.0.3(jiti@2.6.1))': + '@eslint/js@10.0.1(eslint@10.2.1(jiti@2.6.1))': optionalDependencies: - eslint: 10.0.3(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) '@eslint/js@9.39.2': {} '@eslint/object-schema@2.1.7': {} - '@eslint/object-schema@3.0.3': {} + '@eslint/object-schema@3.0.5': {} '@eslint/plugin-kit@0.4.1': dependencies: '@eslint/core': 0.17.0 levn: 0.4.1 - '@eslint/plugin-kit@0.6.1': + '@eslint/plugin-kit@0.7.1': dependencies: - '@eslint/core': 1.1.1 + '@eslint/core': 1.2.1 levn: 0.4.1 - '@exodus/bytes@1.15.0(@noble/hashes@2.0.1)': + '@exodus/bytes@1.15.0(@noble/hashes@2.2.0)': optionalDependencies: - '@noble/hashes': 2.0.1 + '@noble/hashes': 2.2.0 '@exodus/schemasafe@1.3.0': {} @@ -14546,42 +14927,44 @@ snapshots: '@fontsource-variable/material-symbols-rounded@5.2.38': {} + '@fontsource-variable/material-symbols-rounded@5.2.43': {} + '@fontsource-variable/roboto-mono@5.2.8': {} '@glideapps/ts-necessities@2.2.3': {} - '@graphql-codegen/add@6.0.0(graphql@16.13.1)': + '@graphql-codegen/add@6.0.1(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - graphql: 16.13.1 - tslib: 2.6.3 + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/cli@6.2.1(@parcel/watcher@2.5.6)(@types/node@24.10.1)(graphql@16.13.1)(typescript@5.9.3)': + '@graphql-codegen/cli@6.3.1(@parcel/watcher@2.5.6)(@types/node@24.10.1)(graphql@16.13.2)(typescript@5.9.3)': dependencies: '@babel/generator': 7.29.1 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@graphql-codegen/client-preset': 5.2.4(graphql@16.13.1) - '@graphql-codegen/core': 5.0.1(graphql@16.13.1) - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-tools/apollo-engine-loader': 8.0.28(graphql@16.13.1) - '@graphql-tools/code-file-loader': 8.1.28(graphql@16.13.1) - '@graphql-tools/git-loader': 8.0.32(graphql@16.13.1) - '@graphql-tools/github-loader': 9.0.6(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/graphql-file-loader': 8.1.12(graphql@16.13.1) - '@graphql-tools/json-file-loader': 8.0.26(graphql@16.13.1) - '@graphql-tools/load': 8.1.8(graphql@16.13.1) - '@graphql-tools/merge': 9.1.7(graphql@16.13.1) - '@graphql-tools/url-loader': 9.0.6(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-codegen/client-preset': 5.3.0(graphql@16.13.2) + '@graphql-codegen/core': 5.0.2(graphql@16.13.2) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-tools/apollo-engine-loader': 8.0.30(graphql@16.13.2) + '@graphql-tools/code-file-loader': 8.1.32(graphql@16.13.2) + '@graphql-tools/git-loader': 8.0.36(graphql@16.13.2) + '@graphql-tools/github-loader': 9.1.2(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/graphql-file-loader': 8.1.14(graphql@16.13.2) + '@graphql-tools/json-file-loader': 8.0.28(graphql@16.13.2) + '@graphql-tools/load': 8.1.10(graphql@16.13.2) + '@graphql-tools/merge': 9.1.9(graphql@16.13.2) + '@graphql-tools/url-loader': 9.1.2(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@inquirer/prompts': 7.10.1(@types/node@24.10.1) '@whatwg-node/fetch': 0.10.13 chalk: 4.1.2 cosmiconfig: 9.0.1(typescript@5.9.3) debounce: 2.2.0 detect-indent: 6.1.0 - graphql: 16.13.1 - graphql-config: 5.1.6(@types/node@24.10.1)(graphql@16.13.1)(typescript@5.9.3) + graphql: 16.13.2 + graphql-config: 5.1.6(@types/node@24.10.1)(graphql@16.13.2)(typescript@5.9.3) is-glob: 4.0.3 jiti: 2.6.1 json-to-pretty-yaml: 1.2.2 @@ -14607,32 +14990,32 @@ snapshots: - typescript - utf-8-validate - '@graphql-codegen/cli@6.2.1(@parcel/watcher@2.5.6)(@types/node@25.5.0)(graphql@16.13.1)(typescript@5.9.3)': + '@graphql-codegen/cli@6.3.1(@parcel/watcher@2.5.6)(@types/node@25.6.0)(graphql@16.13.2)(typescript@5.9.3)': dependencies: '@babel/generator': 7.29.1 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@graphql-codegen/client-preset': 5.2.4(graphql@16.13.1) - '@graphql-codegen/core': 5.0.1(graphql@16.13.1) - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-tools/apollo-engine-loader': 8.0.28(graphql@16.13.1) - '@graphql-tools/code-file-loader': 8.1.28(graphql@16.13.1) - '@graphql-tools/git-loader': 8.0.32(graphql@16.13.1) - '@graphql-tools/github-loader': 9.0.6(@types/node@25.5.0)(graphql@16.13.1) - '@graphql-tools/graphql-file-loader': 8.1.12(graphql@16.13.1) - '@graphql-tools/json-file-loader': 8.0.26(graphql@16.13.1) - '@graphql-tools/load': 8.1.8(graphql@16.13.1) - '@graphql-tools/merge': 9.1.7(graphql@16.13.1) - '@graphql-tools/url-loader': 9.0.6(@types/node@25.5.0)(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - '@inquirer/prompts': 7.10.1(@types/node@25.5.0) + '@graphql-codegen/client-preset': 5.3.0(graphql@16.13.2) + '@graphql-codegen/core': 5.0.2(graphql@16.13.2) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-tools/apollo-engine-loader': 8.0.30(graphql@16.13.2) + '@graphql-tools/code-file-loader': 8.1.32(graphql@16.13.2) + '@graphql-tools/git-loader': 8.0.36(graphql@16.13.2) + '@graphql-tools/github-loader': 9.1.2(@types/node@25.6.0)(graphql@16.13.2) + '@graphql-tools/graphql-file-loader': 8.1.14(graphql@16.13.2) + '@graphql-tools/json-file-loader': 8.0.28(graphql@16.13.2) + '@graphql-tools/load': 8.1.10(graphql@16.13.2) + '@graphql-tools/merge': 9.1.9(graphql@16.13.2) + '@graphql-tools/url-loader': 9.1.2(@types/node@25.6.0)(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + '@inquirer/prompts': 7.10.1(@types/node@25.6.0) '@whatwg-node/fetch': 0.10.13 chalk: 4.1.2 cosmiconfig: 9.0.1(typescript@5.9.3) debounce: 2.2.0 detect-indent: 6.1.0 - graphql: 16.13.1 - graphql-config: 5.1.6(@types/node@25.5.0)(graphql@16.13.1)(typescript@5.9.3) + graphql: 16.13.2 + graphql-config: 5.1.6(@types/node@25.6.0)(graphql@16.13.2)(typescript@5.9.3) is-glob: 4.0.3 jiti: 2.6.1 json-to-pretty-yaml: 1.2.2 @@ -14658,240 +15041,239 @@ snapshots: - typescript - utf-8-validate - '@graphql-codegen/client-preset@5.2.4(graphql@16.13.1)': + '@graphql-codegen/client-preset@5.3.0(graphql@16.13.2)': dependencies: '@babel/helper-plugin-utils': 7.28.6 '@babel/template': 7.28.6 - '@graphql-codegen/add': 6.0.0(graphql@16.13.1) - '@graphql-codegen/gql-tag-operations': 5.1.4(graphql@16.13.1) - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/typed-document-node': 6.1.7(graphql@16.13.1) - '@graphql-codegen/typescript': 5.0.9(graphql@16.13.1) - '@graphql-codegen/typescript-operations': 5.0.9(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) - '@graphql-tools/documents': 1.0.1(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.1) - graphql: 16.13.1 - tslib: 2.6.3 - - '@graphql-codegen/core@5.0.1(graphql@16.13.1)': - dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-tools/schema': 10.0.31(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 - tslib: 2.6.3 - - '@graphql-codegen/gql-tag-operations@5.1.4(graphql@16.13.1)': - dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-codegen/add': 6.0.1(graphql@16.13.2) + '@graphql-codegen/gql-tag-operations': 5.2.0(graphql@16.13.2) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/typed-document-node': 6.1.8(graphql@16.13.2) + '@graphql-codegen/typescript': 5.0.10(graphql@16.13.2) + '@graphql-codegen/typescript-operations': 5.1.0(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) + '@graphql-tools/documents': 1.0.1(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-codegen/core@5.0.2(graphql@16.13.2)': + dependencies: + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-tools/schema': 10.0.33(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-codegen/gql-tag-operations@5.2.0(graphql@16.13.2)': + dependencies: + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) auto-bind: 4.0.0 - graphql: 16.13.1 - tslib: 2.6.3 + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/introspection@5.0.1(graphql@16.13.1)': + '@graphql-codegen/introspection@5.0.2(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) - graphql: 16.13.1 - tslib: 2.6.3 + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/plugin-helpers@3.1.2(graphql@16.13.1)': + '@graphql-codegen/plugin-helpers@3.1.2(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) change-case-all: 1.0.15 common-tags: 1.8.2 - graphql: 16.13.1 + graphql: 16.13.2 import-from: 4.0.0 - lodash: 4.17.23 + lodash: 4.18.1 tslib: 2.4.1 - '@graphql-codegen/plugin-helpers@6.2.0(graphql@16.13.1)': + '@graphql-codegen/plugin-helpers@6.3.0(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/utils': 11.0.1(graphql@16.13.2) change-case-all: 1.0.15 common-tags: 1.8.2 - graphql: 16.13.1 + graphql: 16.13.2 import-from: 4.0.0 - lodash: 4.17.23 - tslib: 2.6.3 + tslib: 2.8.1 - '@graphql-codegen/schema-ast@5.0.1(graphql@16.13.1)': + '@graphql-codegen/schema-ast@5.0.2(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 - tslib: 2.6.3 + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/typed-document-node@6.1.7(graphql@16.13.1)': + '@graphql-codegen/typed-document-node@6.1.8(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) auto-bind: 4.0.0 change-case-all: 1.0.15 - graphql: 16.13.1 - tslib: 2.6.3 + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/typescript-document-nodes@5.0.9(graphql@16.13.1)': + '@graphql-codegen/typescript-document-nodes@5.0.10(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) auto-bind: 4.0.0 - graphql: 16.13.1 - tslib: 2.6.3 + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/typescript-operations@5.0.9(graphql@16.13.1)': + '@graphql-codegen/typescript-operations@5.1.0(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/typescript': 5.0.9(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/typescript': 5.0.10(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) auto-bind: 4.0.0 - graphql: 16.13.1 - tslib: 2.6.3 + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/typescript-urql-graphcache@3.1.1(@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1))(graphql-tag@2.12.6(graphql@16.13.1))(graphql@16.13.1)': + '@graphql-codegen/typescript-urql-graphcache@3.1.1(@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2))(graphql-tag@2.12.6(graphql@16.13.2))(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 2.13.8(graphql@16.13.1) - '@urql/exchange-graphcache': 7.2.4(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 2.13.8(graphql@16.13.2) + '@urql/exchange-graphcache': 7.2.4(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2) auto-bind: 4.0.0 change-case-all: 1.0.15 - graphql: 16.13.1 - graphql-tag: 2.12.6(graphql@16.13.1) + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) tslib: 2.8.1 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/typescript@5.0.9(graphql@16.13.1)': + '@graphql-codegen/typescript@5.0.10(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-codegen/schema-ast': 5.0.1(graphql@16.13.1) - '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-codegen/schema-ast': 5.0.2(graphql@16.13.2) + '@graphql-codegen/visitor-plugin-common': 6.3.0(graphql@16.13.2) auto-bind: 4.0.0 - graphql: 16.13.1 - tslib: 2.6.3 + graphql: 16.13.2 + tslib: 2.8.1 - '@graphql-codegen/urql-introspection@3.0.1(graphql@16.13.1)': + '@graphql-codegen/urql-introspection@3.0.1(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.13.1) - '@urql/introspection': 0.3.3(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.13.2) + '@urql/introspection': 0.3.3(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-codegen/visitor-plugin-common@2.13.8(graphql@16.13.1)': + '@graphql-codegen/visitor-plugin-common@2.13.8(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.13.1) - '@graphql-tools/optimize': 1.4.0(graphql@16.13.1) - '@graphql-tools/relay-operation-optimizer': 6.5.18(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.13.2) + '@graphql-tools/optimize': 1.4.0(graphql@16.13.2) + '@graphql-tools/relay-operation-optimizer': 6.5.18(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) auto-bind: 4.0.0 change-case-all: 1.0.15 dependency-graph: 0.11.0 - graphql: 16.13.1 - graphql-tag: 2.12.6(graphql@16.13.1) + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) parse-filepath: 1.0.2 tslib: 2.4.1 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/visitor-plugin-common@6.2.4(graphql@16.13.1)': + '@graphql-codegen/visitor-plugin-common@6.3.0(graphql@16.13.2)': dependencies: - '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.1) - '@graphql-tools/optimize': 2.0.0(graphql@16.13.1) - '@graphql-tools/relay-operation-optimizer': 7.1.1(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-codegen/plugin-helpers': 6.3.0(graphql@16.13.2) + '@graphql-tools/optimize': 2.0.0(graphql@16.13.2) + '@graphql-tools/relay-operation-optimizer': 7.1.4(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) auto-bind: 4.0.0 change-case-all: 1.0.15 dependency-graph: 1.0.0 - graphql: 16.13.1 - graphql-tag: 2.12.6(graphql@16.13.1) + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) parse-filepath: 1.0.2 - tslib: 2.6.3 + tslib: 2.8.1 '@graphql-hive/signal@2.0.0': {} - '@graphql-tools/apollo-engine-loader@8.0.28(graphql@16.13.1)': + '@graphql-tools/apollo-engine-loader@8.0.30(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@whatwg-node/fetch': 0.10.13 - graphql: 16.13.1 + graphql: 16.13.2 sync-fetch: 0.6.0 tslib: 2.8.1 - '@graphql-tools/batch-execute@10.0.7(graphql@16.13.1)': + '@graphql-tools/batch-execute@10.0.8(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@whatwg-node/promise-helpers': 1.3.2 dataloader: 2.2.3 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/batch-execute@8.5.22(graphql@16.13.1)': + '@graphql-tools/batch-execute@8.5.22(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) dataloader: 2.2.3 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 value-or-promise: 1.0.12 - '@graphql-tools/code-file-loader@8.1.28(graphql@16.13.1)': + '@graphql-tools/code-file-loader@8.1.32(graphql@16.13.2)': dependencies: - '@graphql-tools/graphql-tag-pluck': 8.3.27(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/graphql-tag-pluck': 8.3.31(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) globby: 11.1.0 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 unixify: 1.0.0 transitivePeerDependencies: - supports-color - '@graphql-tools/delegate@12.0.12(graphql@16.13.1)': + '@graphql-tools/delegate@12.0.14(graphql@16.13.2)': dependencies: - '@graphql-tools/batch-execute': 10.0.7(graphql@16.13.1) - '@graphql-tools/executor': 1.5.1(graphql@16.13.1) - '@graphql-tools/schema': 10.0.31(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/batch-execute': 10.0.8(graphql@16.13.2) + '@graphql-tools/executor': 1.5.3(graphql@16.13.2) + '@graphql-tools/schema': 10.0.33(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@repeaterjs/repeater': 3.0.6 '@whatwg-node/promise-helpers': 1.3.2 dataloader: 2.2.3 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/delegate@9.0.35(graphql@16.13.1)': + '@graphql-tools/delegate@9.0.35(graphql@16.13.2)': dependencies: - '@graphql-tools/batch-execute': 8.5.22(graphql@16.13.1) - '@graphql-tools/executor': 0.0.20(graphql@16.13.1) - '@graphql-tools/schema': 9.0.19(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/batch-execute': 8.5.22(graphql@16.13.2) + '@graphql-tools/executor': 0.0.20(graphql@16.13.2) + '@graphql-tools/schema': 9.0.19(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) dataloader: 2.2.3 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 value-or-promise: 1.0.12 - '@graphql-tools/documents@1.0.1(graphql@16.13.1)': + '@graphql-tools/documents@1.0.1(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 lodash.sortby: 4.7.0 tslib: 2.8.1 - '@graphql-tools/executor-common@1.0.6(graphql@16.13.1)': + '@graphql-tools/executor-common@1.0.6(graphql@16.13.2)': dependencies: '@envelop/core': 5.5.1 - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 - '@graphql-tools/executor-graphql-ws@0.0.14(graphql@16.13.1)': + '@graphql-tools/executor-graphql-ws@0.0.14(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) '@repeaterjs/repeater': 3.0.4 '@types/ws': 8.18.1 - graphql: 16.13.1 - graphql-ws: 5.12.1(graphql@16.13.1) + graphql: 16.13.2 + graphql-ws: 5.12.1(graphql@16.13.2) isomorphic-ws: 5.0.0(ws@8.17.1) tslib: 2.8.1 ws: 8.17.1 @@ -14899,13 +15281,13 @@ snapshots: - bufferutil - utf-8-validate - '@graphql-tools/executor-graphql-ws@3.1.5(graphql@16.13.1)': + '@graphql-tools/executor-graphql-ws@3.1.5(graphql@16.13.2)': dependencies: - '@graphql-tools/executor-common': 1.0.6(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/executor-common': 1.0.6(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@whatwg-node/disposablestack': 0.0.6 - graphql: 16.13.1 - graphql-ws: 6.0.7(graphql@16.13.1)(ws@8.17.1) + graphql: 16.13.2 + graphql-ws: 6.0.8(graphql@16.13.2)(ws@8.17.1) isows: 1.0.7(ws@8.17.1) tslib: 2.8.1 ws: 8.17.1 @@ -14915,55 +15297,55 @@ snapshots: - crossws - utf-8-validate - '@graphql-tools/executor-http@0.1.10(@types/node@24.10.1)(graphql@16.13.1)': + '@graphql-tools/executor-http@0.1.10(@types/node@24.10.1)(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) '@repeaterjs/repeater': 3.0.6 '@whatwg-node/fetch': 0.8.8 dset: 3.1.4 extract-files: 11.0.0 - graphql: 16.13.1 + graphql: 16.13.2 meros: 1.3.2(@types/node@24.10.1) tslib: 2.8.1 value-or-promise: 1.0.12 transitivePeerDependencies: - '@types/node' - '@graphql-tools/executor-http@3.1.1(@types/node@24.10.1)(graphql@16.13.1)': + '@graphql-tools/executor-http@3.2.1(@types/node@24.10.1)(graphql@16.13.2)': dependencies: '@graphql-hive/signal': 2.0.0 - '@graphql-tools/executor-common': 1.0.6(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/executor-common': 1.0.6(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@repeaterjs/repeater': 3.0.6 '@whatwg-node/disposablestack': 0.0.6 '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + graphql: 16.13.2 meros: 1.3.2(@types/node@24.10.1) tslib: 2.8.1 transitivePeerDependencies: - '@types/node' - '@graphql-tools/executor-http@3.1.1(@types/node@25.5.0)(graphql@16.13.1)': + '@graphql-tools/executor-http@3.2.1(@types/node@25.6.0)(graphql@16.13.2)': dependencies: '@graphql-hive/signal': 2.0.0 - '@graphql-tools/executor-common': 1.0.6(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/executor-common': 1.0.6(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@repeaterjs/repeater': 3.0.6 '@whatwg-node/disposablestack': 0.0.6 '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 - meros: 1.3.2(@types/node@25.5.0) + graphql: 16.13.2 + meros: 1.3.2(@types/node@25.6.0) tslib: 2.8.1 transitivePeerDependencies: - '@types/node' - '@graphql-tools/executor-legacy-ws@0.0.11(graphql@16.13.1)': + '@graphql-tools/executor-legacy-ws@0.0.11(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) '@types/ws': 8.18.1 - graphql: 16.13.1 + graphql: 16.13.2 isomorphic-ws: 5.0.0(ws@8.17.1) tslib: 2.8.1 ws: 8.17.1 @@ -14971,11 +15353,11 @@ snapshots: - bufferutil - utf-8-validate - '@graphql-tools/executor-legacy-ws@1.1.25(graphql@16.13.1)': + '@graphql-tools/executor-legacy-ws@1.1.28(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@types/ws': 8.18.1 - graphql: 16.13.1 + graphql: 16.13.2 isomorphic-ws: 5.0.0(ws@8.17.1) tslib: 2.8.1 ws: 8.17.1 @@ -14983,30 +15365,30 @@ snapshots: - bufferutil - utf-8-validate - '@graphql-tools/executor@0.0.20(graphql@16.13.1)': + '@graphql-tools/executor@0.0.20(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) '@repeaterjs/repeater': 3.0.6 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 value-or-promise: 1.0.12 - '@graphql-tools/executor@1.5.1(graphql@16.13.1)': + '@graphql-tools/executor@1.5.3(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.1) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) '@repeaterjs/repeater': 3.0.6 '@whatwg-node/disposablestack': 0.0.6 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/git-loader@8.0.32(graphql@16.13.1)': + '@graphql-tools/git-loader@8.0.36(graphql@16.13.2)': dependencies: - '@graphql-tools/graphql-tag-pluck': 8.3.27(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/graphql-tag-pluck': 8.3.31(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 is-glob: 4.0.3 micromatch: 4.0.8 tslib: 2.8.1 @@ -15014,177 +15396,203 @@ snapshots: transitivePeerDependencies: - supports-color - '@graphql-tools/github-loader@9.0.6(@types/node@24.10.1)(graphql@16.13.1)': + '@graphql-tools/github-loader@9.1.2(@types/node@24.10.1)(graphql@16.13.2)': dependencies: - '@graphql-tools/executor-http': 3.1.1(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/graphql-tag-pluck': 8.3.27(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/executor-http': 3.2.1(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/graphql-tag-pluck': 8.3.31(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + graphql: 16.13.2 sync-fetch: 0.6.0 tslib: 2.8.1 transitivePeerDependencies: - '@types/node' - supports-color - '@graphql-tools/github-loader@9.0.6(@types/node@25.5.0)(graphql@16.13.1)': + '@graphql-tools/github-loader@9.1.2(@types/node@25.6.0)(graphql@16.13.2)': dependencies: - '@graphql-tools/executor-http': 3.1.1(@types/node@25.5.0)(graphql@16.13.1) - '@graphql-tools/graphql-tag-pluck': 8.3.27(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/executor-http': 3.2.1(@types/node@25.6.0)(graphql@16.13.2) + '@graphql-tools/graphql-tag-pluck': 8.3.31(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + graphql: 16.13.2 sync-fetch: 0.6.0 tslib: 2.8.1 transitivePeerDependencies: - '@types/node' - supports-color - '@graphql-tools/graphql-file-loader@7.5.17(graphql@16.13.1)': + '@graphql-tools/graphql-file-loader@7.5.17(graphql@16.13.2)': dependencies: - '@graphql-tools/import': 6.7.18(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/import': 6.7.18(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) globby: 11.1.0 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 unixify: 1.0.0 - '@graphql-tools/graphql-file-loader@8.1.12(graphql@16.13.1)': + '@graphql-tools/graphql-file-loader@8.1.14(graphql@16.13.2)': dependencies: - '@graphql-tools/import': 7.1.12(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/import': 7.1.14(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) globby: 11.1.0 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 unixify: 1.0.0 - '@graphql-tools/graphql-tag-pluck@8.3.27(graphql@16.13.1)': + '@graphql-tools/graphql-tag-pluck@8.3.31(graphql@16.13.2)': dependencies: '@babel/core': 7.29.0 '@babel/parser': 7.29.2 '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@graphql-tools/import@6.7.18(graphql@16.13.1)': + '@graphql-tools/import@6.7.18(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + graphql: 16.13.2 resolve-from: 5.0.0 tslib: 2.8.1 - '@graphql-tools/import@7.1.12(graphql@16.13.1)': + '@graphql-tools/import@7.1.14(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 resolve-from: 5.0.0 tslib: 2.8.1 - '@graphql-tools/json-file-loader@7.4.18(graphql@16.13.1)': + '@graphql-tools/json-file-loader@7.4.18(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) globby: 11.1.0 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 unixify: 1.0.0 - '@graphql-tools/json-file-loader@8.0.26(graphql@16.13.1)': + '@graphql-tools/json-file-loader@8.0.28(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) globby: 11.1.0 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 unixify: 1.0.0 - '@graphql-tools/load@7.8.14(graphql@16.13.1)': + '@graphql-tools/load@7.8.14(graphql@16.13.2)': dependencies: - '@graphql-tools/schema': 9.0.19(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/schema': 9.0.19(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + graphql: 16.13.2 p-limit: 3.1.0 tslib: 2.8.1 - '@graphql-tools/load@8.1.8(graphql@16.13.1)': + '@graphql-tools/load@8.1.10(graphql@16.13.2)': dependencies: - '@graphql-tools/schema': 10.0.31(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/schema': 10.0.33(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 p-limit: 3.1.0 tslib: 2.8.1 - '@graphql-tools/merge@8.4.2(graphql@16.13.1)': + '@graphql-tools/merge@8.4.2(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/merge@9.1.7(graphql@16.13.1)': + '@graphql-tools/merge@9.1.7(graphql@16.13.2)': dependencies: - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/utils': 11.0.0(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/optimize@1.4.0(graphql@16.13.1)': + '@graphql-tools/merge@9.1.8(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + '@graphql-tools/utils': 11.0.1(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/optimize@2.0.0(graphql@16.13.1)': + '@graphql-tools/merge@9.1.9(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/relay-operation-optimizer@6.5.18(graphql@16.13.1)': + '@graphql-tools/optimize@1.4.0(graphql@16.13.2)': dependencies: - '@ardatan/relay-compiler': 12.0.0(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - graphql: 16.13.1 + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-tools/optimize@2.0.0(graphql@16.13.2)': + dependencies: + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-tools/relay-operation-optimizer@6.5.18(graphql@16.13.2)': + dependencies: + '@ardatan/relay-compiler': 12.0.0(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 transitivePeerDependencies: - encoding - supports-color - '@graphql-tools/relay-operation-optimizer@7.1.1(graphql@16.13.1)': + '@graphql-tools/relay-operation-optimizer@7.1.4(graphql@16.13.2)': + dependencies: + '@ardatan/relay-compiler': 13.0.1(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-tools/schema@10.0.31(graphql@16.13.2)': + dependencies: + '@graphql-tools/merge': 9.1.7(graphql@16.13.2) + '@graphql-tools/utils': 11.0.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-tools/schema@10.0.32(graphql@16.13.2)': dependencies: - '@ardatan/relay-compiler': 13.0.0(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/merge': 9.1.8(graphql@16.13.2) + '@graphql-tools/utils': 11.0.1(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/schema@10.0.31(graphql@16.13.1)': + '@graphql-tools/schema@10.0.33(graphql@16.13.2)': dependencies: - '@graphql-tools/merge': 9.1.7(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/merge': 9.1.9(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/schema@9.0.19(graphql@16.13.1)': + '@graphql-tools/schema@9.0.19(graphql@16.13.2)': dependencies: - '@graphql-tools/merge': 8.4.2(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-tools/merge': 8.4.2(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 value-or-promise: 1.0.12 - '@graphql-tools/url-loader@7.17.18(@types/node@24.10.1)(graphql@16.13.1)': + '@graphql-tools/url-loader@7.17.18(@types/node@24.10.1)(graphql@16.13.2)': dependencies: '@ardatan/sync-fetch': 0.0.1 - '@graphql-tools/delegate': 9.0.35(graphql@16.13.1) - '@graphql-tools/executor-graphql-ws': 0.0.14(graphql@16.13.1) - '@graphql-tools/executor-http': 0.1.10(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/executor-legacy-ws': 0.0.11(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - '@graphql-tools/wrap': 9.4.2(graphql@16.13.1) + '@graphql-tools/delegate': 9.0.35(graphql@16.13.2) + '@graphql-tools/executor-graphql-ws': 0.0.14(graphql@16.13.2) + '@graphql-tools/executor-http': 0.1.10(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/executor-legacy-ws': 0.0.11(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + '@graphql-tools/wrap': 9.4.2(graphql@16.13.2) '@types/ws': 8.18.1 '@whatwg-node/fetch': 0.8.8 - graphql: 16.13.1 + graphql: 16.13.2 isomorphic-ws: 5.0.0(ws@8.17.1) tslib: 2.8.1 value-or-promise: 1.0.12 @@ -15195,17 +15603,17 @@ snapshots: - encoding - utf-8-validate - '@graphql-tools/url-loader@9.0.6(@types/node@24.10.1)(graphql@16.13.1)': + '@graphql-tools/url-loader@9.1.2(@types/node@24.10.1)(graphql@16.13.2)': dependencies: - '@graphql-tools/executor-graphql-ws': 3.1.5(graphql@16.13.1) - '@graphql-tools/executor-http': 3.1.1(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/executor-legacy-ws': 1.1.25(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - '@graphql-tools/wrap': 11.1.12(graphql@16.13.1) + '@graphql-tools/executor-graphql-ws': 3.1.5(graphql@16.13.2) + '@graphql-tools/executor-http': 3.2.1(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/executor-legacy-ws': 1.1.28(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + '@graphql-tools/wrap': 11.1.14(graphql@16.13.2) '@types/ws': 8.18.1 '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + graphql: 16.13.2 isomorphic-ws: 5.0.0(ws@8.17.1) sync-fetch: 0.6.0 tslib: 2.8.1 @@ -15217,17 +15625,17 @@ snapshots: - crossws - utf-8-validate - '@graphql-tools/url-loader@9.0.6(@types/node@25.5.0)(graphql@16.13.1)': + '@graphql-tools/url-loader@9.1.2(@types/node@25.6.0)(graphql@16.13.2)': dependencies: - '@graphql-tools/executor-graphql-ws': 3.1.5(graphql@16.13.1) - '@graphql-tools/executor-http': 3.1.1(@types/node@25.5.0)(graphql@16.13.1) - '@graphql-tools/executor-legacy-ws': 1.1.25(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - '@graphql-tools/wrap': 11.1.12(graphql@16.13.1) + '@graphql-tools/executor-graphql-ws': 3.1.5(graphql@16.13.2) + '@graphql-tools/executor-http': 3.2.1(@types/node@25.6.0)(graphql@16.13.2) + '@graphql-tools/executor-legacy-ws': 1.1.28(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + '@graphql-tools/wrap': 11.1.14(graphql@16.13.2) '@types/ws': 8.18.1 '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + graphql: 16.13.2 isomorphic-ws: 5.0.0(ws@8.17.1) sync-fetch: 0.6.0 tslib: 2.8.1 @@ -15239,48 +15647,64 @@ snapshots: - crossws - utf-8-validate - '@graphql-tools/utils@11.0.0(graphql@16.13.1)': + '@graphql-tools/utils@11.0.0(graphql@16.13.2)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.1) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) '@whatwg-node/promise-helpers': 1.3.2 cross-inspect: 1.0.1 - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/utils@9.2.1(graphql@16.13.1)': + '@graphql-tools/utils@11.0.1(graphql@16.13.2)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) + '@whatwg-node/promise-helpers': 1.3.2 + cross-inspect: 1.0.1 + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/wrap@11.1.12(graphql@16.13.1)': + '@graphql-tools/utils@11.1.0(graphql@16.13.2)': dependencies: - '@graphql-tools/delegate': 12.0.12(graphql@16.13.1) - '@graphql-tools/schema': 10.0.31(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) '@whatwg-node/promise-helpers': 1.3.2 - graphql: 16.13.1 + cross-inspect: 1.0.1 + graphql: 16.13.2 tslib: 2.8.1 - '@graphql-tools/wrap@9.4.2(graphql@16.13.1)': + '@graphql-tools/utils@9.2.1(graphql@16.13.2)': dependencies: - '@graphql-tools/delegate': 9.0.35(graphql@16.13.1) - '@graphql-tools/schema': 9.0.19(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) - graphql: 16.13.1 + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-tools/wrap@11.1.14(graphql@16.13.2)': + dependencies: + '@graphql-tools/delegate': 12.0.14(graphql@16.13.2) + '@graphql-tools/schema': 10.0.33(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) + '@whatwg-node/promise-helpers': 1.3.2 + graphql: 16.13.2 + tslib: 2.8.1 + + '@graphql-tools/wrap@9.4.2(graphql@16.13.2)': + dependencies: + '@graphql-tools/delegate': 9.0.35(graphql@16.13.2) + '@graphql-tools/schema': 9.0.19(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) + graphql: 16.13.2 tslib: 2.8.1 value-or-promise: 1.0.12 - '@graphql-typed-document-node/core@3.2.0(graphql@16.13.1)': + '@graphql-typed-document-node/core@3.2.0(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - '@guolao/vue-monaco-editor@1.6.0(monaco-editor@0.55.1)(vue@3.5.31(typescript@5.9.3))': + '@guolao/vue-monaco-editor@1.6.0(monaco-editor@0.55.1)(vue@3.5.33(typescript@5.9.3))': dependencies: '@monaco-editor/loader': 1.7.0 monaco-editor: 0.55.1 - vue: 3.5.31(typescript@5.9.3) - vue-demi: 0.14.10(vue@3.5.31(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) '@hapi/b64@5.0.0': dependencies: @@ -15296,9 +15720,9 @@ snapshots: '@hapi/hoek@9.3.0': {} - '@hono/node-server@1.19.10(hono@4.12.7)': + '@hono/node-server@1.19.11(hono@4.12.15)': dependencies: - hono: 4.12.7 + hono: 4.12.15 '@hoppscotch/httpsnippet@3.0.9': dependencies: @@ -15309,23 +15733,23 @@ snapshots: stringify-object: 3.3.0 yargs: 17.7.2 - '@hoppscotch/ui@0.2.5(eslint@10.0.3(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3))': + '@hoppscotch/ui@0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@boringer-avatars/vue3': 0.2.1(vue@3.5.31(typescript@5.9.3)) + '@boringer-avatars/vue3': 0.2.1(vue@3.5.33(typescript@5.9.3)) '@fontsource-variable/inter': 5.2.8 '@fontsource-variable/material-symbols-rounded': 5.2.38 '@fontsource-variable/roboto-mono': 5.2.8 '@hoppscotch/vue-sonner': 1.2.3 - '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.31(typescript@5.9.3)) - '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - '@vueuse/core': 8.9.4(vue@3.5.31(typescript@5.9.3)) + '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.33(typescript@5.9.3)) + '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + '@vueuse/core': 8.9.4(vue@3.5.33(typescript@5.9.3)) fp-ts: 2.16.11 - lodash-es: 4.17.23 + lodash-es: 4.18.1 path: 0.12.7 - vite-plugin-eslint: 1.8.1(eslint@10.0.3(jiti@2.6.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - vue: 3.5.31(typescript@5.9.3) + vite-plugin-eslint: 1.8.1(eslint@10.2.1(jiti@2.6.1))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + vue: 3.5.33(typescript@5.9.3) vue-promise-modals: 0.1.0(typescript@5.9.3) - vuedraggable-es: 4.1.1(vue@3.5.31(typescript@5.9.3)) + vuedraggable-es: 4.1.1(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/composition-api' - eslint @@ -15333,23 +15757,23 @@ snapshots: - typescript - vite - '@hoppscotch/ui@0.2.5(eslint@10.0.3(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3))': + '@hoppscotch/ui@0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@boringer-avatars/vue3': 0.2.1(vue@3.5.31(typescript@5.9.3)) + '@boringer-avatars/vue3': 0.2.1(vue@3.5.33(typescript@5.9.3)) '@fontsource-variable/inter': 5.2.8 '@fontsource-variable/material-symbols-rounded': 5.2.38 '@fontsource-variable/roboto-mono': 5.2.8 '@hoppscotch/vue-sonner': 1.2.3 - '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.31(typescript@5.9.3)) - '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - '@vueuse/core': 8.9.4(vue@3.5.31(typescript@5.9.3)) + '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.33(typescript@5.9.3)) + '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + '@vueuse/core': 8.9.4(vue@3.5.33(typescript@5.9.3)) fp-ts: 2.16.11 - lodash-es: 4.17.23 + lodash-es: 4.18.1 path: 0.12.7 - vite-plugin-eslint: 1.8.1(eslint@10.0.3(jiti@2.6.1))(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - vue: 3.5.31(typescript@5.9.3) + vite-plugin-eslint: 1.8.1(eslint@10.2.1(jiti@2.6.1))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + vue: 3.5.33(typescript@5.9.3) vue-promise-modals: 0.1.0(typescript@5.9.3) - vuedraggable-es: 4.1.1(vue@3.5.31(typescript@5.9.3)) + vuedraggable-es: 4.1.1(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/composition-api' - eslint @@ -15357,23 +15781,23 @@ snapshots: - typescript - vite - '@hoppscotch/ui@0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3))': + '@hoppscotch/ui@0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@boringer-avatars/vue3': 0.2.1(vue@3.5.31(typescript@5.9.3)) + '@boringer-avatars/vue3': 0.2.1(vue@3.5.33(typescript@5.9.3)) '@fontsource-variable/inter': 5.2.8 '@fontsource-variable/material-symbols-rounded': 5.2.38 '@fontsource-variable/roboto-mono': 5.2.8 '@hoppscotch/vue-sonner': 1.2.3 - '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.31(typescript@5.9.3)) - '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - '@vueuse/core': 8.9.4(vue@3.5.31(typescript@5.9.3)) + '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.33(typescript@5.9.3)) + '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + '@vueuse/core': 8.9.4(vue@3.5.33(typescript@5.9.3)) fp-ts: 2.16.11 - lodash-es: 4.17.23 + lodash-es: 4.18.1 path: 0.12.7 - vite-plugin-eslint: 1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - vue: 3.5.31(typescript@5.9.3) + vite-plugin-eslint: 1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + vue: 3.5.33(typescript@5.9.3) vue-promise-modals: 0.1.0(typescript@5.9.3) - vuedraggable-es: 4.1.1(vue@3.5.31(typescript@5.9.3)) + vuedraggable-es: 4.1.1(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/composition-api' - eslint @@ -15381,23 +15805,23 @@ snapshots: - typescript - vite - '@hoppscotch/ui@0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3))': + '@hoppscotch/ui@0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@boringer-avatars/vue3': 0.2.1(vue@3.5.31(typescript@5.9.3)) + '@boringer-avatars/vue3': 0.2.1(vue@3.5.33(typescript@5.9.3)) '@fontsource-variable/inter': 5.2.8 '@fontsource-variable/material-symbols-rounded': 5.2.38 '@fontsource-variable/roboto-mono': 5.2.8 '@hoppscotch/vue-sonner': 1.2.3 - '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.31(typescript@5.9.3)) - '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - '@vueuse/core': 8.9.4(vue@3.5.31(typescript@5.9.3)) + '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.33(typescript@5.9.3)) + '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + '@vueuse/core': 8.9.4(vue@3.5.33(typescript@5.9.3)) fp-ts: 2.16.11 - lodash-es: 4.17.23 + lodash-es: 4.18.1 path: 0.12.7 - vite-plugin-eslint: 1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - vue: 3.5.31(typescript@5.9.3) + vite-plugin-eslint: 1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + vue: 3.5.33(typescript@5.9.3) vue-promise-modals: 0.1.0(typescript@5.9.3) - vuedraggable-es: 4.1.1(vue@3.5.31(typescript@5.9.3)) + vuedraggable-es: 4.1.1(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/composition-api' - eslint @@ -15407,9 +15831,9 @@ snapshots: '@hoppscotch/vue-sonner@1.2.3': {} - '@hoppscotch/vue-toasted@0.1.0(vue@3.5.31(typescript@5.9.3))': + '@hoppscotch/vue-toasted@0.1.0(vue@3.5.33(typescript@5.9.3))': dependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) '@humanfs/core@0.19.1': {} @@ -15422,7 +15846,7 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@iconify-json/lucide@1.2.99': + '@iconify-json/lucide@1.2.104': dependencies: '@iconify/types': 2.0.0 @@ -15440,7 +15864,7 @@ snapshots: dotenv: 16.5.0 glob: 11.1.0 picocolors: 1.1.1 - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.3 optionalDependencies: '@import-meta-env/unplugin': 0.6.3 @@ -15464,15 +15888,15 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/checkbox@4.3.2(@types/node@25.5.0)': + '@inquirer/checkbox@4.3.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/confirm@5.1.21(@types/node@24.10.1)': dependencies: @@ -15481,12 +15905,12 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/confirm@5.1.21(@types/node@25.5.0)': + '@inquirer/confirm@5.1.21(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/core@10.3.2(@types/node@24.10.1)': dependencies: @@ -15501,18 +15925,18 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/core@10.3.2(@types/node@25.5.0)': + '@inquirer/core@10.3.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/editor@4.2.23(@types/node@24.10.1)': dependencies: @@ -15522,13 +15946,13 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/editor@4.2.23(@types/node@25.5.0)': + '@inquirer/editor@4.2.23(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/external-editor': 1.0.3(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/external-editor': 1.0.3(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/expand@4.0.23(@types/node@24.10.1)': dependencies: @@ -15538,13 +15962,13 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/expand@4.0.23(@types/node@25.5.0)': + '@inquirer/expand@4.0.23(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/external-editor@1.0.3(@types/node@24.10.1)': dependencies: @@ -15553,12 +15977,12 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/external-editor@1.0.3(@types/node@25.5.0)': + '@inquirer/external-editor@1.0.3(@types/node@25.6.0)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/figures@1.0.15': {} @@ -15569,12 +15993,12 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/input@4.3.1(@types/node@25.5.0)': + '@inquirer/input@4.3.1(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/number@3.0.23(@types/node@24.10.1)': dependencies: @@ -15583,12 +16007,12 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/number@3.0.23(@types/node@25.5.0)': + '@inquirer/number@3.0.23(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/password@4.0.23(@types/node@24.10.1)': dependencies: @@ -15598,13 +16022,13 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/password@4.0.23(@types/node@25.5.0)': + '@inquirer/password@4.0.23(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/prompts@7.10.1(@types/node@24.10.1)': dependencies: @@ -15621,35 +16045,35 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/prompts@7.10.1(@types/node@25.5.0)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@25.5.0) - '@inquirer/confirm': 5.1.21(@types/node@25.5.0) - '@inquirer/editor': 4.2.23(@types/node@25.5.0) - '@inquirer/expand': 4.0.23(@types/node@25.5.0) - '@inquirer/input': 4.3.1(@types/node@25.5.0) - '@inquirer/number': 3.0.23(@types/node@25.5.0) - '@inquirer/password': 4.0.23(@types/node@25.5.0) - '@inquirer/rawlist': 4.1.11(@types/node@25.5.0) - '@inquirer/search': 3.2.2(@types/node@25.5.0) - '@inquirer/select': 4.4.2(@types/node@25.5.0) + '@inquirer/prompts@7.10.1(@types/node@25.6.0)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@25.6.0) + '@inquirer/confirm': 5.1.21(@types/node@25.6.0) + '@inquirer/editor': 4.2.23(@types/node@25.6.0) + '@inquirer/expand': 4.0.23(@types/node@25.6.0) + '@inquirer/input': 4.3.1(@types/node@25.6.0) + '@inquirer/number': 3.0.23(@types/node@25.6.0) + '@inquirer/password': 4.0.23(@types/node@25.6.0) + '@inquirer/rawlist': 4.1.11(@types/node@25.6.0) + '@inquirer/search': 3.2.2(@types/node@25.6.0) + '@inquirer/select': 4.4.2(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 - - '@inquirer/prompts@7.3.2(@types/node@25.5.0)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@25.5.0) - '@inquirer/confirm': 5.1.21(@types/node@25.5.0) - '@inquirer/editor': 4.2.23(@types/node@25.5.0) - '@inquirer/expand': 4.0.23(@types/node@25.5.0) - '@inquirer/input': 4.3.1(@types/node@25.5.0) - '@inquirer/number': 3.0.23(@types/node@25.5.0) - '@inquirer/password': 4.0.23(@types/node@25.5.0) - '@inquirer/rawlist': 4.1.11(@types/node@25.5.0) - '@inquirer/search': 3.2.2(@types/node@25.5.0) - '@inquirer/select': 4.4.2(@types/node@25.5.0) + '@types/node': 25.6.0 + + '@inquirer/prompts@7.3.2(@types/node@25.6.0)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@25.6.0) + '@inquirer/confirm': 5.1.21(@types/node@25.6.0) + '@inquirer/editor': 4.2.23(@types/node@25.6.0) + '@inquirer/expand': 4.0.23(@types/node@25.6.0) + '@inquirer/input': 4.3.1(@types/node@25.6.0) + '@inquirer/number': 3.0.23(@types/node@25.6.0) + '@inquirer/password': 4.0.23(@types/node@25.6.0) + '@inquirer/rawlist': 4.1.11(@types/node@25.6.0) + '@inquirer/search': 3.2.2(@types/node@25.6.0) + '@inquirer/select': 4.4.2(@types/node@25.6.0) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/rawlist@4.1.11(@types/node@24.10.1)': dependencies: @@ -15659,13 +16083,13 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/rawlist@4.1.11(@types/node@25.5.0)': + '@inquirer/rawlist@4.1.11(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/search@3.2.2(@types/node@24.10.1)': dependencies: @@ -15676,14 +16100,14 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/search@3.2.2(@types/node@25.5.0)': + '@inquirer/search@3.2.2(@types/node@25.6.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/select@4.4.2(@types/node@24.10.1)': dependencies: @@ -15695,28 +16119,28 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - '@inquirer/select@4.4.2(@types/node@25.5.0)': + '@inquirer/select@4.4.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.5.0) + '@inquirer/core': 10.3.2(@types/node@25.6.0) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@inquirer/type@3.0.10(@types/node@24.10.1)': optionalDependencies: '@types/node': 24.10.1 - '@inquirer/type@3.0.10(@types/node@25.5.0)': + '@inquirer/type@3.0.10(@types/node@25.6.0)': optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 - '@intlify/bundle-utils@11.0.7(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))': + '@intlify/bundle-utils@11.1.2(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))': dependencies: - '@intlify/message-compiler': 11.3.0 - '@intlify/shared': 11.3.0 + '@intlify/message-compiler': 11.4.0 + '@intlify/shared': 11.4.0 acorn: 8.16.0 esbuild: 0.25.12 escodegen: 2.1.0 @@ -15725,43 +16149,44 @@ snapshots: source-map-js: 1.2.1 yaml-eslint-parser: 1.3.2 optionalDependencies: - vue-i18n: 11.3.0(vue@3.5.31(typescript@5.9.3)) + vue-i18n: 11.4.0(vue@3.5.33(typescript@5.9.3)) - '@intlify/core-base@11.3.0': + '@intlify/core-base@11.4.0': dependencies: - '@intlify/devtools-types': 11.3.0 - '@intlify/message-compiler': 11.3.0 - '@intlify/shared': 11.3.0 + '@intlify/devtools-types': 11.4.0 + '@intlify/message-compiler': 11.4.0 + '@intlify/shared': 11.4.0 - '@intlify/devtools-types@11.3.0': + '@intlify/devtools-types@11.4.0': dependencies: - '@intlify/core-base': 11.3.0 - '@intlify/shared': 11.3.0 + '@intlify/core-base': 11.4.0 + '@intlify/shared': 11.4.0 - '@intlify/message-compiler@11.3.0': + '@intlify/message-compiler@11.4.0': dependencies: - '@intlify/shared': 11.3.0 + '@intlify/shared': 11.4.0 source-map-js: 1.2.1 - '@intlify/shared@11.3.0': {} + '@intlify/shared@11.4.0': {} - '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.31)(eslint@10.0.3(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3))': + '@intlify/unplugin-vue-i18n@11.1.2(@vue/compiler-dom@3.5.33)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3(jiti@2.6.1)) - '@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3))) - '@intlify/shared': 11.3.0 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.3.0)(@vue/compiler-dom@3.5.31)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@intlify/bundle-utils': 11.1.2(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3))) + '@intlify/shared': 11.4.0 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.4.0)(@vue/compiler-dom@3.5.33)(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.60.2) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 pathe: 2.0.3 picocolors: 1.1.1 unplugin: 2.3.11 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) optionalDependencies: - vue-i18n: 11.3.0(vue@3.5.31(typescript@5.9.3)) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue-i18n: 11.4.0(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/compiler-dom' - eslint @@ -15769,23 +16194,49 @@ snapshots: - supports-color - typescript - '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.31)(eslint@9.39.2(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3))': + '@intlify/unplugin-vue-i18n@11.1.2(@vue/compiler-dom@3.5.33)(eslint@9.39.2(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3))) - '@intlify/shared': 11.3.0 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.3.0)(@vue/compiler-dom@3.5.31)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@intlify/bundle-utils': 11.1.2(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3))) + '@intlify/shared': 11.4.0 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.4.0)(@vue/compiler-dom@3.5.33)(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.60.2) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + debug: 4.4.3(supports-color@8.1.1) + fast-glob: 3.3.3 + pathe: 2.0.3 + picocolors: 1.1.1 + unplugin: 2.3.11 + vue: 3.5.33(typescript@5.9.3) + optionalDependencies: + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue-i18n: 11.4.0(vue@3.5.33(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/compiler-dom' + - eslint + - rollup + - supports-color + - typescript + + '@intlify/unplugin-vue-i18n@11.1.2(@vue/compiler-dom@3.5.33)(eslint@9.39.2(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@intlify/bundle-utils': 11.1.2(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3))) + '@intlify/shared': 11.4.0 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.4.0)(@vue/compiler-dom@3.5.33)(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.60.2) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 pathe: 2.0.3 picocolors: 1.1.1 unplugin: 2.3.11 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) optionalDependencies: - vue-i18n: 11.3.0(vue@3.5.31(typescript@5.9.3)) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue-i18n: 11.4.0(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/compiler-dom' - eslint @@ -15793,14 +16244,14 @@ snapshots: - supports-color - typescript - '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.3.0)(@vue/compiler-dom@3.5.31)(vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3))': + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.4.0)(@vue/compiler-dom@3.5.33)(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3))': dependencies: '@babel/parser': 7.29.2 optionalDependencies: - '@intlify/shared': 11.3.0 - '@vue/compiler-dom': 3.5.31 - vue: 3.5.31(typescript@5.9.3) - vue-i18n: 11.3.0(vue@3.5.31(typescript@5.9.3)) + '@intlify/shared': 11.4.0 + '@vue/compiler-dom': 3.5.33 + vue: 3.5.33(typescript@5.9.3) + vue-i18n: 11.4.0(vue@3.5.33(typescript@5.9.3)) '@ioredis/commands@1.5.1': optional: true @@ -15829,13 +16280,13 @@ snapshots: '@jest/console@30.3.0': dependencies: '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 jest-message-util: 30.3.0 jest-util: 30.3.0 slash: 3.0.0 - '@jest/core@30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))': + '@jest/core@30.3.0(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3))': dependencies: '@jest/console': 30.3.0 '@jest/pattern': 30.0.1 @@ -15843,14 +16294,14 @@ snapshots: '@jest/test-result': 30.3.0 '@jest/transform': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 4.4.0 exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.3.0 - jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + jest-config: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) jest-haste-map: 30.3.0 jest-message-util: 30.3.0 jest-regex-util: 30.0.1 @@ -15876,7 +16327,7 @@ snapshots: dependencies: '@jest/fake-timers': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 jest-mock: 30.3.0 '@jest/expect-utils@29.7.0': @@ -15898,7 +16349,7 @@ snapshots: dependencies: '@jest/types': 30.3.0 '@sinonjs/fake-timers': 15.1.1 - '@types/node': 25.5.0 + '@types/node': 25.6.0 jest-message-util: 30.3.0 jest-mock: 30.3.0 jest-util: 30.3.0 @@ -15916,7 +16367,7 @@ snapshots: '@jest/pattern@30.0.1': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 jest-regex-util: 30.0.1 '@jest/reporters@30.3.0': @@ -15927,7 +16378,7 @@ snapshots: '@jest/transform': 30.3.0 '@jest/types': 30.3.0 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit-x: 0.2.2 @@ -16006,7 +16457,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -16016,7 +16467,7 @@ snapshots: '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -16073,6 +16524,8 @@ snapshots: '@jsdevtools/ono@7.1.3': {} + '@kurkle/color@0.3.4': {} + '@lezer/common@1.5.1': {} '@lezer/generator@1.8.0': @@ -16116,11 +16569,6 @@ snapshots: dependencies: state-local: 1.0.7 - '@mrleebo/prisma-ast@0.13.1': - dependencies: - chevrotain: 10.5.0 - lilconfig: 2.1.0 - '@napi-rs/canvas-android-arm64@0.1.97': optional: true @@ -16176,24 +16624,28 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@nestjs-modules/mailer@2.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(nodemailer@8.0.4)(terser@5.46.1)(typescript@5.9.3)': + '@nestjs-modules/mailer@2.3.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/terminus@11.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2))(chokidar@4.0.3)(nodemailer@8.0.7)(terser@5.46.1)(typescript@5.9.3)': dependencies: - '@css-inline/css-inline': 0.14.1 - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - glob: 10.5.0 - nodemailer: 8.0.4 + '@css-inline/css-inline': 0.20.0 + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + glob: 13.0.6 + nodemailer: 8.0.7 + tslib: 2.8.1 optionalDependencies: + '@nestjs/terminus': 11.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/ejs': 3.1.5 '@types/mjml': 4.7.4 '@types/pug': 2.0.10 - ejs: 3.1.10 + ejs: 5.0.2 handlebars: 4.7.9 - liquidjs: 10.25.0 + liquidjs: 10.25.7 mjml: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) + nunjucks: 3.2.4(chokidar@4.0.3) preview-email: 3.1.1 pug: 3.0.4 transitivePeerDependencies: + - chokidar - encoding - purgecss - relateurl @@ -16203,49 +16655,50 @@ snapshots: - typescript - uncss - '@nestjs/apollo@13.2.4(@apollo/server@5.5.0(graphql@16.13.1))(@as-integrations/express5@1.1.2(@apollo/server@5.5.0(graphql@16.13.1))(express@5.2.1))(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/graphql@13.2.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.1)(reflect-metadata@0.2.2))(graphql@16.13.1)': + '@nestjs/apollo@13.3.0(@apollo/server@5.5.0(graphql@16.13.2))(@as-integrations/express5@1.1.2(@apollo/server@5.5.0(graphql@16.13.2))(express@5.2.1))(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/graphql@13.3.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.2)(reflect-metadata@0.2.2))(graphql@16.13.2)': dependencies: - '@apollo/server': 5.5.0(graphql@16.13.1) - '@apollo/server-plugin-landing-page-graphql-playground': 4.0.1(@apollo/server@5.5.0(graphql@16.13.1)) - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/graphql': 13.2.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.1)(reflect-metadata@0.2.2) - graphql: 16.13.1 + '@apollo/server': 5.5.0(graphql@16.13.2) + '@apollo/server-plugin-landing-page-graphql-playground': 4.0.1(@apollo/server@5.5.0(graphql@16.13.2)) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/graphql': 13.3.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.2)(reflect-metadata@0.2.2) + graphql: 16.13.2 iterall: 1.3.0 - lodash.omit: 4.5.0 + lodash.omit: 4.18.0 tslib: 2.8.1 optionalDependencies: - '@as-integrations/express5': 1.1.2(@apollo/server@5.5.0(graphql@16.13.1))(express@5.2.1) + '@as-integrations/express5': 1.1.2(@apollo/server@5.5.0(graphql@16.13.2))(express@5.2.1) - '@nestjs/cli@11.0.16(@types/node@25.5.0)': + '@nestjs/cli@11.0.21(@types/node@25.6.0)(prettier@3.8.3)': dependencies: - '@angular-devkit/core': 19.2.19(chokidar@4.0.3) - '@angular-devkit/schematics': 19.2.19(chokidar@4.0.3) - '@angular-devkit/schematics-cli': 19.2.19(@types/node@25.5.0)(chokidar@4.0.3) - '@inquirer/prompts': 7.10.1(@types/node@25.5.0) - '@nestjs/schematics': 11.0.9(chokidar@4.0.3)(typescript@5.9.3) + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics-cli': 19.2.24(@types/node@25.6.0)(chokidar@4.0.3) + '@inquirer/prompts': 7.10.1(@types/node@25.6.0) + '@nestjs/schematics': 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) ansis: 4.2.0 chokidar: 4.0.3 cli-table3: 0.6.5 commander: 4.1.1 - fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.104.1) - glob: 13.0.0 + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.106.0) + glob: 13.0.6 node-emoji: 1.11.0 ora: 5.4.1 tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 typescript: 5.9.3 - webpack: 5.104.1 + webpack: 5.106.0 webpack-node-externals: 3.0.0 transitivePeerDependencies: - '@types/node' - esbuild + - prettier - uglify-js - webpack-cli - '@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.3.2 + file-type: 21.3.4 iterare: 1.2.1 load-esm: 1.0.3 reflect-metadata: 0.2.2 @@ -16258,45 +16711,45 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/config@4.0.3(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@nestjs/config@4.0.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - dotenv: 17.2.3 + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + dotenv: 17.4.1 dotenv-expand: 12.0.3 - lodash: 4.17.23 + lodash: 4.18.1 rxjs: 7.8.2 - '@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 - path-to-regexp: 8.4.0 + path-to-regexp: 8.4.2 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/platform-express': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) - '@nestjs/graphql@13.2.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.1)(reflect-metadata@0.2.2)': + '@nestjs/graphql@13.3.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(graphql@16.13.2)(reflect-metadata@0.2.2)': dependencies: - '@graphql-tools/merge': 9.1.7(graphql@16.13.1) - '@graphql-tools/schema': 10.0.31(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) + '@graphql-tools/merge': 9.1.8(graphql@16.13.2) + '@graphql-tools/schema': 10.0.32(graphql@16.13.2) + '@graphql-tools/utils': 11.0.1(graphql@16.13.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) chokidar: 4.0.3 fast-glob: 3.3.3 - graphql: 16.13.1 - graphql-tag: 2.12.6(graphql@16.13.1) - graphql-ws: 6.0.7(graphql@16.13.1)(ws@8.17.1) - lodash: 4.17.23 + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) + graphql-ws: 6.0.8(graphql@16.13.2)(ws@8.17.1) + lodash: 4.18.1 normalize-path: 3.0.0 reflect-metadata: 0.2.2 - subscriptions-transport-ws: 0.11.0(graphql@16.13.1) + subscriptions-transport-ws: 0.11.0(graphql@16.13.2) tslib: 2.8.1 ws: 8.17.1 optionalDependencies: @@ -16308,101 +16761,103 @@ snapshots: - crossws - utf-8-validate - '@nestjs/jwt@11.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))': + '@nestjs/jwt@11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/jsonwebtoken': 9.0.10 jsonwebtoken: 9.0.3 - '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': + '@nestjs/mapped-types@2.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 optionalDependencies: class-transformer: 0.5.1 class-validator: 0.15.1 - '@nestjs/passport@11.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': + '@nestjs/passport@11.0.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) passport: 0.7.0 - '@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': + '@nestjs/platform-express@11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.6 express: 5.2.1 multer: 2.1.1 - path-to-regexp: 8.4.0 + path-to-regexp: 8.4.2 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@nestjs/schedule@6.1.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': + '@nestjs/schedule@6.1.3(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) cron: 4.4.0 - '@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.9.3)': + '@nestjs/schematics@11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3)': dependencies: - '@angular-devkit/core': 19.2.17(chokidar@4.0.3) - '@angular-devkit/schematics': 19.2.17(chokidar@4.0.3) - comment-json: 4.4.1 + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + comment-json: 5.0.0 jsonc-parser: 3.3.1 pluralize: 8.0.0 typescript: 5.9.3 + optionalDependencies: + prettier: 3.8.3 transitivePeerDependencies: - chokidar - '@nestjs/swagger@11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': + '@nestjs/swagger@11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.16.0 - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) js-yaml: 4.1.1 - lodash: 4.17.23 - path-to-regexp: 8.4.0 + lodash: 4.18.1 + path-to-regexp: 8.4.2 reflect-metadata: 0.2.2 - swagger-ui-dist: 5.31.0 + swagger-ui-dist: 5.32.4 optionalDependencies: class-transformer: 0.5.1 class-validator: 0.15.1 - '@nestjs/terminus@11.1.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@prisma/client@7.5.0(prisma@7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/terminus@11.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) boxen: 5.1.2 check-disk-space: 3.4.0 reflect-metadata: 0.2.2 rxjs: 7.8.2 optionalDependencies: - '@prisma/client': 7.5.0(prisma@7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) + '@prisma/client': 7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) - '@nestjs/testing@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17)': + '@nestjs/testing@11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/platform-express@11.1.19)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/platform-express': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) - '@nestjs/throttler@6.5.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(reflect-metadata@0.2.2)': + '@nestjs/throttler@6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 - '@noble/curves@2.0.1': + '@noble/curves@2.2.0': dependencies: - '@noble/hashes': 2.0.1 + '@noble/hashes': 2.2.0 '@noble/hashes@1.8.0': {} - '@noble/hashes@2.0.1': {} + '@noble/hashes@2.2.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -16531,31 +16986,33 @@ snapshots: '@popperjs/core@2.11.8': {} - '@posthog/core@1.24.0': + '@posthog/core@1.27.7': dependencies: - cross-spawn: 7.0.6 + '@posthog/types': 1.372.3 - '@prisma/adapter-pg@7.5.0': + '@posthog/types@1.372.3': {} + + '@prisma/adapter-pg@7.8.0': dependencies: - '@prisma/driver-adapter-utils': 7.5.0 - '@types/pg': 8.11.11 + '@prisma/driver-adapter-utils': 7.8.0 + '@types/pg': 8.20.0 pg: 8.20.0 postgres-array: 3.0.4 transitivePeerDependencies: - pg-native - '@prisma/client-runtime-utils@7.5.0': {} + '@prisma/client-runtime-utils@7.8.0': {} - '@prisma/client@7.5.0(prisma@7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@prisma/client-runtime-utils': 7.5.0 + '@prisma/client-runtime-utils': 7.8.0 optionalDependencies: - prisma: 7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + prisma: 7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) typescript: 5.9.3 - '@prisma/config@7.5.0': + '@prisma/config@7.8.0': dependencies: - c12: 3.1.0 + c12: 3.3.4 deepmerge-ts: 7.1.5 effect: 3.20.0 empathic: 2.0.0 @@ -16564,20 +17021,20 @@ snapshots: '@prisma/debug@7.2.0': {} - '@prisma/debug@7.5.0': {} + '@prisma/debug@7.8.0': {} - '@prisma/dev@0.20.0(typescript@5.9.3)': + '@prisma/dev@0.24.3(typescript@5.9.3)': dependencies: - '@electric-sql/pglite': 0.3.15 - '@electric-sql/pglite-socket': 0.0.20(@electric-sql/pglite@0.3.15) - '@electric-sql/pglite-tools': 0.2.20(@electric-sql/pglite@0.3.15) - '@hono/node-server': 1.19.10(hono@4.12.7) - '@mrleebo/prisma-ast': 0.13.1 + '@electric-sql/pglite': 0.4.1 + '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) + '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) + '@hono/node-server': 1.19.11(hono@4.12.15) '@prisma/get-platform': 7.2.0 '@prisma/query-plan-executor': 7.2.0 + '@prisma/streams-local': 0.1.2 foreground-child: 3.3.1 get-port-please: 3.2.0 - hono: 4.12.7 + hono: 4.12.15 http-status-codes: 2.3.0 pathe: 2.0.3 proper-lockfile: 4.1.2 @@ -16588,40 +17045,51 @@ snapshots: transitivePeerDependencies: - typescript - '@prisma/driver-adapter-utils@7.5.0': + '@prisma/driver-adapter-utils@7.8.0': dependencies: - '@prisma/debug': 7.5.0 + '@prisma/debug': 7.8.0 - '@prisma/engines-version@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': {} + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} - '@prisma/engines@7.5.0': + '@prisma/engines@7.8.0': dependencies: - '@prisma/debug': 7.5.0 - '@prisma/engines-version': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e - '@prisma/fetch-engine': 7.5.0 - '@prisma/get-platform': 7.5.0 + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/fetch-engine': 7.8.0 + '@prisma/get-platform': 7.8.0 - '@prisma/fetch-engine@7.5.0': + '@prisma/fetch-engine@7.8.0': dependencies: - '@prisma/debug': 7.5.0 - '@prisma/engines-version': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e - '@prisma/get-platform': 7.5.0 + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/get-platform': 7.8.0 '@prisma/get-platform@7.2.0': dependencies: '@prisma/debug': 7.2.0 - '@prisma/get-platform@7.5.0': + '@prisma/get-platform@7.8.0': dependencies: - '@prisma/debug': 7.5.0 + '@prisma/debug': 7.8.0 '@prisma/query-plan-executor@7.2.0': {} - '@prisma/studio-core@0.21.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@prisma/streams-local@0.1.2': dependencies: + ajv: 8.18.0 + better-result: 2.8.2 + env-paths: 3.0.0 + proper-lockfile: 4.1.2 + + '@prisma/studio-core@0.27.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-toggle': 1.1.10(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/react': 19.2.14 + chart.js: 4.5.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@types/react-dom' '@protobufjs/aspromise@1.1.2': {} @@ -16646,6 +17114,60 @@ snapshots: '@protobufjs/utf8@1.1.0': {} + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-primitive@2.1.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-toggle@1.1.10(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@relmify/jest-fp-ts@2.1.1(fp-ts@2.16.11)(io-ts@2.2.22(fp-ts@2.16.11))': dependencies: '@jest/expect-utils': 29.7.0 @@ -16659,7 +17181,7 @@ snapshots: '@repeaterjs/repeater@3.0.6': {} - '@rolldown/pluginutils@1.0.0-rc.2': {} + '@rolldown/pluginutils@1.0.0-rc.13': {} '@rollup/plugin-babel@5.3.1(@babel/core@7.29.0)(@types/babel__core@7.20.5)(rollup@2.80.0)': dependencies: @@ -16672,13 +17194,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-inject@5.0.5(rollup@4.59.0)': + '@rollup/plugin-inject@5.0.5(rollup@4.60.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.2) estree-walker: 2.0.2 magic-string: 0.30.21 optionalDependencies: - rollup: 4.59.0 + rollup: 4.60.2 '@rollup/plugin-node-resolve@15.3.1(rollup@2.80.0)': dependencies: @@ -16686,7 +17208,7 @@ snapshots: '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.11 + resolve: 1.22.12 optionalDependencies: rollup: 2.80.0 @@ -16698,7 +17220,7 @@ snapshots: '@rollup/plugin-terser@0.4.4(rollup@2.80.0)': dependencies: - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.3 smob: 1.6.1 terser: 5.46.1 optionalDependencies: @@ -16759,86 +17281,169 @@ snapshots: optionalDependencies: rollup: 4.59.0 + '@rollup/pluginutils@5.3.0(rollup@4.60.2)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.4 + optionalDependencies: + rollup: 4.60.2 + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true + '@rollup/rollup-android-arm-eabi@4.60.2': + optional: true + '@rollup/rollup-android-arm64@4.59.0': optional: true + '@rollup/rollup-android-arm64@4.60.2': + optional: true + '@rollup/rollup-darwin-arm64@4.59.0': optional: true + '@rollup/rollup-darwin-arm64@4.60.2': + optional: true + '@rollup/rollup-darwin-x64@4.59.0': optional: true + '@rollup/rollup-darwin-x64@4.60.2': + optional: true + '@rollup/rollup-freebsd-arm64@4.59.0': optional: true + '@rollup/rollup-freebsd-arm64@4.60.2': + optional: true + '@rollup/rollup-freebsd-x64@4.59.0': optional: true + '@rollup/rollup-freebsd-x64@4.60.2': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true + '@rollup/rollup-linux-arm64-gnu@4.60.2': + optional: true + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true + '@rollup/rollup-linux-arm64-musl@4.60.2': + optional: true + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true + '@rollup/rollup-linux-loong64-gnu@4.60.2': + optional: true + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true + '@rollup/rollup-linux-loong64-musl@4.60.2': + optional: true + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + optional: true + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true + '@rollup/rollup-linux-ppc64-musl@4.60.2': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + optional: true + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true + '@rollup/rollup-linux-riscv64-musl@4.60.2': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true + '@rollup/rollup-linux-s390x-gnu@4.60.2': + optional: true + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true + '@rollup/rollup-linux-x64-gnu@4.60.2': + optional: true + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true + '@rollup/rollup-linux-x64-musl@4.60.2': + optional: true + '@rollup/rollup-openbsd-x64@4.59.0': optional: true + '@rollup/rollup-openbsd-x64@4.60.2': + optional: true + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true + '@rollup/rollup-openharmony-arm64@4.60.2': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true + '@rollup/rollup-win32-arm64-msvc@4.60.2': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true + '@rollup/rollup-win32-ia32-msvc@4.60.2': + optional: true + '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true + '@rollup/rollup-win32-x64-gnu@4.60.2': + optional: true + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true + '@rollup/rollup-win32-x64-msvc@4.60.2': + optional: true + '@rushstack/eslint-patch@1.16.1': {} '@scarf/scarf@1.4.0': {} - '@scure/base@2.0.0': {} + '@scure/base@2.2.0': {} '@selderee/plugin-htmlparser2@0.11.0': dependencies: @@ -16880,7 +17485,7 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.12 - '@sveltejs/vite-plugin-svelte@1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1))': + '@sveltejs/vite-plugin-svelte@1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1))': dependencies: debug: 4.4.3(supports-color@8.1.1) deepmerge: 4.3.1 @@ -16888,8 +17493,8 @@ snapshots: magic-string: 0.26.7 svelte: 3.59.2 svelte-hmr: 0.15.3(svelte@3.59.2) - vite: 3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1) - vitefu: 0.2.5(vite@3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1)) + vite: 3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1) + vitefu: 0.2.5(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1)) transitivePeerDependencies: - supports-color @@ -17013,12 +17618,12 @@ snapshots: '@types/bcrypt@6.0.0': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/caseless@0.12.5': {} @@ -17031,7 +17636,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/cookie-parser@1.4.10(@types/express@5.0.6)': dependencies: @@ -17041,7 +17646,7 @@ snapshots: '@types/cors@2.8.19': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/crypto-js@4.2.2': {} @@ -17077,7 +17682,7 @@ snapshots: '@types/express-serve-static-core@5.1.1': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/qs': 6.15.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -17094,7 +17699,7 @@ snapshots: dependencies: '@hapi/boom': 9.1.4 '@types/crypto-js': 4.2.2 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/request': 2.48.13 '@types/http-errors@2.0.5': {} @@ -17123,7 +17728,7 @@ snapshots: '@types/jsonwebtoken@9.0.10': dependencies: '@types/ms': 2.1.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/linkify-it@5.0.0': {} @@ -17166,25 +17771,25 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/node@25.5.0': + '@types/node@25.6.0': dependencies: - undici-types: 7.18.2 + undici-types: 7.19.2 - '@types/nodemailer@7.0.11': + '@types/nodemailer@8.0.0': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/nprogress@0.2.3': {} '@types/oauth@0.9.6': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/paho-mqtt@1.0.10': {} '@types/papaparse@5.5.2': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/passport-github2@1.2.9': dependencies: @@ -17222,15 +17827,15 @@ snapshots: dependencies: '@types/express': 5.0.6 - '@types/pg@8.11.11': + '@types/pg@8.20.0': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 pg-protocol: 1.13.0 - pg-types: 4.1.0 + pg-types: 2.2.0 '@types/postman-collection@3.5.11': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/pug@2.0.10': optional: true @@ -17249,7 +17854,7 @@ snapshots: '@types/request@2.48.13': dependencies: '@types/caseless': 0.12.5 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/tough-cookie': 4.0.5 form-data: 4.0.4 @@ -17257,20 +17862,20 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/send@1.2.1': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/splitpanes@2.2.6(typescript@5.9.3)': dependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) transitivePeerDependencies: - typescript @@ -17284,7 +17889,7 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 25.5.0 + '@types/node': 25.6.0 form-data: 4.0.4 '@types/supertest@7.2.0': @@ -17304,7 +17909,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/yargs-parser@21.0.3': {} @@ -17312,15 +17917,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/type-utils': 8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.57.2 - eslint: 10.0.3(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -17328,14 +17933,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/type-utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.2 + '@typescript-eslint/parser': 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/type-utils': 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.0 eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 @@ -17344,14 +17949,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.2 - debug: 4.4.3(supports-color@8.1.1) - eslint: 10.0.3(jiti@2.6.1) + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/type-utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.1 + eslint: 10.2.1(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -17368,6 +17977,30 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.0 + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.1 + debug: 4.4.3(supports-color@8.1.1) + eslint: 10.2.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.57.2(typescript@5.9.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) @@ -17377,32 +18010,68 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.59.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) + '@typescript-eslint/types': 8.59.0 + debug: 4.4.3(supports-color@8.1.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.59.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@5.9.3) + '@typescript-eslint/types': 8.59.1 + debug: 4.4.3(supports-color@8.1.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.57.2': dependencies: '@typescript-eslint/types': 8.57.2 '@typescript-eslint/visitor-keys': 8.57.2 + '@typescript-eslint/scope-manager@8.59.0': + dependencies: + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/visitor-keys': 8.59.0 + + '@typescript-eslint/scope-manager@8.59.1': + dependencies: + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/visitor-keys': 8.59.1 + '@typescript-eslint/tsconfig-utils@8.57.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/tsconfig-utils@8.59.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.57.2 '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3(supports-color@8.1.1) - eslint: 10.0.3(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3(supports-color@8.1.1) eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.3) @@ -17410,8 +18079,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3(supports-color@8.1.1) + eslint: 10.2.1(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.57.2': {} + '@typescript-eslint/types@8.59.0': {} + + '@typescript-eslint/types@8.59.1': {} + '@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.57.2(typescript@5.9.3) @@ -17419,7 +18104,7 @@ snapshots: '@typescript-eslint/types': 8.57.2 '@typescript-eslint/visitor-keys': 8.57.2 debug: 4.4.3(supports-color@8.1.1) - minimatch: 10.2.3 + minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -17427,13 +18112,32 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.2(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.0(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - eslint: 10.0.3(jiti@2.6.1) + '@typescript-eslint/project-service': 8.59.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/visitor-keys': 8.59.0 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 10.2.3 + semver: 7.7.4 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.59.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.59.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@5.9.3) + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/visitor-keys': 8.59.1 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 10.2.3 + semver: 7.7.4 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -17449,18 +18153,50 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.57.2': + '@typescript-eslint/utils@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + eslint: 10.2.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.57.2': + dependencies: + '@typescript-eslint/types': 8.57.2 + eslint-visitor-keys: 5.0.1 + + '@typescript-eslint/visitor-keys@8.59.0': + dependencies: + '@typescript-eslint/types': 8.59.0 + eslint-visitor-keys: 5.0.1 + + '@typescript-eslint/visitor-keys@8.59.1': dependencies: - '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/types': 8.59.1 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.0': {} - '@unhead/vue@2.1.12(vue@3.5.31(typescript@5.9.3))': + '@unhead/vue@2.1.12(vue@3.5.33(typescript@5.9.3))': dependencies: hookable: 6.1.0 unhead: 2.1.12 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -17521,43 +18257,43 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@urql/core@6.0.1(graphql@16.13.1)': + '@urql/core@6.0.1(graphql@16.13.2)': dependencies: - '@0no-co/graphql.web': 1.2.0(graphql@16.13.1) + '@0no-co/graphql.web': 1.2.0(graphql@16.13.2) wonka: 6.3.6 transitivePeerDependencies: - graphql - '@urql/devtools@2.0.3(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1)': + '@urql/devtools@2.0.3(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2)': dependencies: - '@urql/core': 6.0.1(graphql@16.13.1) - graphql: 16.13.1 + '@urql/core': 6.0.1(graphql@16.13.2) + graphql: 16.13.2 wonka: 6.3.6 - '@urql/exchange-auth@3.0.0(@urql/core@6.0.1(graphql@16.13.1))': + '@urql/exchange-auth@3.0.0(@urql/core@6.0.1(graphql@16.13.2))': dependencies: - '@urql/core': 6.0.1(graphql@16.13.1) + '@urql/core': 6.0.1(graphql@16.13.2) wonka: 6.3.6 - '@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.1))(graphql@16.13.1)': + '@urql/exchange-graphcache@7.2.4(@urql/core@6.0.1(graphql@16.13.2))(graphql@16.13.2)': dependencies: - '@0no-co/graphql.web': 1.2.0(graphql@16.13.1) - '@urql/core': 6.0.1(graphql@16.13.1) + '@0no-co/graphql.web': 1.2.0(graphql@16.13.2) + '@urql/core': 6.0.1(graphql@16.13.2) wonka: 6.3.6 transitivePeerDependencies: - graphql - '@urql/introspection@0.3.3(graphql@16.13.1)': + '@urql/introspection@0.3.3(graphql@16.13.2)': dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - '@urql/vue@2.0.0(@urql/core@6.0.1(graphql@16.13.1))(vue@3.5.31(typescript@5.9.3))': + '@urql/vue@2.1.0(@urql/core@6.0.1(graphql@16.13.2))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@urql/core': 6.0.1(graphql@16.13.1) - vue: 3.5.31(typescript@5.9.3) + '@urql/core': 6.0.1(graphql@16.13.2) + vue: 3.5.33(typescript@5.9.3) wonka: 6.3.6 - '@vitejs/plugin-legacy@2.3.1(terser@5.46.1)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))': + '@vitejs/plugin-legacy@2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))': dependencies: '@babel/standalone': 7.29.2 core-js: 3.49.0 @@ -17565,9 +18301,9 @@ snapshots: regenerator-runtime: 0.13.11 systemjs: 6.15.1 terser: 5.46.1 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - '@vitejs/plugin-legacy@2.3.1(terser@5.46.1)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))': + '@vitejs/plugin-legacy@2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))': dependencies: '@babel/standalone': 7.29.2 core-js: 3.49.0 @@ -17575,9 +18311,9 @@ snapshots: regenerator-runtime: 0.13.11 systemjs: 6.15.1 terser: 5.46.1 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - '@vitejs/plugin-legacy@7.2.1(terser@5.46.1)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))': + '@vitejs/plugin-legacy@7.2.1(terser@5.46.1)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) @@ -17592,68 +18328,68 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.46.1 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.6(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) - vue: 3.5.31(typescript@5.9.3) + '@rolldown/pluginutils': 1.0.0-rc.13 + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue: 3.5.33(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.31(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.6(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: - '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) - vue: 3.5.31(typescript@5.9.3) + '@rolldown/pluginutils': 1.0.0-rc.13 + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue: 3.5.33(typescript@5.9.3) - '@vitest/expect@4.1.2': + '@vitest/expect@4.1.5': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.2(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))': + '@vitest/mocker@4.1.5(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.2 + '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - '@vitest/mocker@4.1.2(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))': + '@vitest/mocker@4.1.5(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.2 + '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - '@vitest/pretty-format@4.1.2': + '@vitest/pretty-format@4.1.5': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.2': + '@vitest/runner@4.1.5': dependencies: - '@vitest/utils': 4.1.2 + '@vitest/utils': 4.1.5 pathe: 2.0.3 - '@vitest/snapshot@4.1.2': + '@vitest/snapshot@4.1.5': dependencies: - '@vitest/pretty-format': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/pretty-format': 4.1.5 + '@vitest/utils': 4.1.5 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.2': {} + '@vitest/spy@4.1.5': {} - '@vitest/utils@4.1.2': + '@vitest/utils@4.1.5': dependencies: - '@vitest/pretty-format': 4.1.2 + '@vitest/pretty-format': 4.1.5 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -17690,27 +18426,40 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@3.5.33': + dependencies: + '@babel/parser': 7.29.2 + '@vue/shared': 3.5.33 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + '@vue/compiler-dom@3.5.31': dependencies: '@vue/compiler-core': 3.5.31 '@vue/shared': 3.5.31 - '@vue/compiler-sfc@3.5.31': + '@vue/compiler-dom@3.5.33': + dependencies: + '@vue/compiler-core': 3.5.33 + '@vue/shared': 3.5.33 + + '@vue/compiler-sfc@3.5.33': dependencies: '@babel/parser': 7.29.2 - '@vue/compiler-core': 3.5.31 - '@vue/compiler-dom': 3.5.31 - '@vue/compiler-ssr': 3.5.31 - '@vue/shared': 3.5.31 + '@vue/compiler-core': 3.5.33 + '@vue/compiler-dom': 3.5.33 + '@vue/compiler-ssr': 3.5.33 + '@vue/shared': 3.5.33 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.8 + postcss: 8.5.10 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.31': + '@vue/compiler-ssr@3.5.33': dependencies: - '@vue/compiler-dom': 3.5.31 - '@vue/shared': 3.5.31 + '@vue/compiler-dom': 3.5.33 + '@vue/shared': 3.5.33 '@vue/compiler-vue2@2.7.16': dependencies: @@ -17719,11 +18468,11 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/utils': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) + eslint-plugin-vue: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) fast-glob: 3.3.3 typescript-eslint: 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) vue-eslint-parser: 10.4.0(eslint@9.39.2(jiti@2.6.1)) @@ -17739,7 +18488,7 @@ snapshots: '@vue/compiler-dom': 3.5.31 '@vue/reactivity': 3.5.31 '@vue/shared': 3.5.31 - minimatch: 10.2.3 + minimatch: 9.0.9 muggle-string: 0.3.1 vue-template-compiler: 2.7.16 optionalDependencies: @@ -17752,7 +18501,7 @@ snapshots: '@vue/compiler-vue2': 2.7.16 '@vue/shared': 3.5.31 computeds: 0.0.1 - minimatch: 10.2.3 + minimatch: 9.0.9 muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: @@ -17765,7 +18514,7 @@ snapshots: '@vue/compiler-vue2': 2.7.16 '@vue/shared': 3.5.31 alien-signals: 0.4.14 - minimatch: 10.2.3 + minimatch: 9.0.9 muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: @@ -17775,26 +18524,32 @@ snapshots: dependencies: '@vue/shared': 3.5.31 - '@vue/runtime-core@3.5.31': + '@vue/reactivity@3.5.33': dependencies: - '@vue/reactivity': 3.5.31 - '@vue/shared': 3.5.31 + '@vue/shared': 3.5.33 - '@vue/runtime-dom@3.5.31': + '@vue/runtime-core@3.5.33': dependencies: - '@vue/reactivity': 3.5.31 - '@vue/runtime-core': 3.5.31 - '@vue/shared': 3.5.31 + '@vue/reactivity': 3.5.33 + '@vue/shared': 3.5.33 + + '@vue/runtime-dom@3.5.33': + dependencies: + '@vue/reactivity': 3.5.33 + '@vue/runtime-core': 3.5.33 + '@vue/shared': 3.5.33 csstype: 3.2.3 - '@vue/server-renderer@3.5.31(vue@3.5.31(typescript@5.9.3))': + '@vue/server-renderer@3.5.33(vue@3.5.33(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.31 - '@vue/shared': 3.5.31 - vue: 3.5.31(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.33 + '@vue/shared': 3.5.33 + vue: 3.5.33(typescript@5.9.3) '@vue/shared@3.5.31': {} + '@vue/shared@3.5.33': {} + '@vue/typescript@1.8.8(typescript@5.9.3)': dependencies: '@volar/typescript': 1.10.10 @@ -17802,35 +18557,35 @@ snapshots: transitivePeerDependencies: - typescript - '@vueuse/core@14.2.1(vue@3.5.31(typescript@5.9.3))': + '@vueuse/core@14.2.1(vue@3.5.33(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.2.1 - '@vueuse/shared': 14.2.1(vue@3.5.31(typescript@5.9.3)) - vue: 3.5.31(typescript@5.9.3) + '@vueuse/shared': 14.2.1(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) - '@vueuse/core@8.9.4(vue@3.5.31(typescript@5.9.3))': + '@vueuse/core@8.9.4(vue@3.5.33(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.14 '@vueuse/metadata': 8.9.4 - '@vueuse/shared': 8.9.4(vue@3.5.31(typescript@5.9.3)) - vue-demi: 0.14.10(vue@3.5.31(typescript@5.9.3)) + '@vueuse/shared': 8.9.4(vue@3.5.33(typescript@5.9.3)) + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) optionalDependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) '@vueuse/metadata@14.2.1': {} '@vueuse/metadata@8.9.4': {} - '@vueuse/shared@14.2.1(vue@3.5.31(typescript@5.9.3))': + '@vueuse/shared@14.2.1(vue@3.5.33(typescript@5.9.3))': dependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) - '@vueuse/shared@8.9.4(vue@3.5.31(typescript@5.9.3))': + '@vueuse/shared@8.9.4(vue@3.5.33(typescript@5.9.3))': dependencies: - vue-demi: 0.14.10(vue@3.5.31(typescript@5.9.3)) + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) optionalDependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) '@webassemblyjs/ast@1.14.1': dependencies: @@ -17947,7 +18702,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@xmldom/xmldom@0.8.11': {} + '@xmldom/xmldom@0.8.13': {} '@xtuc/ieee754@1.2.0': {} @@ -17960,6 +18715,9 @@ snapshots: libqp: 2.1.1 optional: true + a-sync-waterfall@1.0.1: + optional: true + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -18006,9 +18764,9 @@ snapshots: optionalDependencies: ajv: 8.18.0 - ajv-formats@3.0.1(ajv@8.17.1): + ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 ajv-keywords@3.5.2(ajv@6.14.0): dependencies: @@ -18026,14 +18784,14 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.17.1: + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ajv@8.18.0: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 fast-uri: 3.1.0 @@ -18089,11 +18847,11 @@ snapshots: apiconnect-wsdl@2.0.36(openapi-types@12.1.3): dependencies: - '@xmldom/xmldom': 0.8.11 + '@xmldom/xmldom': 0.8.13 iconv-lite: 0.6.3 js-yaml: 4.1.1 jszip: 3.10.1 - lodash: 4.17.23 + lodash: 4.18.1 oas-validator: 5.0.8 swagger-parser: 10.0.3(openapi-types@12.1.3) swagger2openapi: 7.0.8 @@ -18172,13 +18930,13 @@ snapshots: auto-bind@4.0.0: {} - autoprefixer@10.4.27(postcss@8.5.8): + autoprefixer@10.5.0(postcss@8.5.10): dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001781 + browserslist: 4.28.2 + caniuse-lite: 1.0.30001791 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -18189,19 +18947,19 @@ snapshots: aws4fetch@1.0.20: {} - axios-cookiejar-support@6.0.5(axios@1.13.6)(tough-cookie@6.0.1): + axios-cookiejar-support@6.0.5(axios@1.15.2)(tough-cookie@6.0.1): dependencies: - axios: 1.13.6 + axios: 1.15.2 http-cookie-agent: 7.0.3(tough-cookie@6.0.1) tough-cookie: 6.0.1 transitivePeerDependencies: - undici - axios@1.13.6: + axios@1.15.2: dependencies: - follow-redirects: 1.15.11 + follow-redirects: 1.16.0 form-data: 4.0.4 - proxy-from-env: 1.1.0 + proxy-from-env: 2.1.0 transitivePeerDependencies: - debug @@ -18343,6 +19101,8 @@ snapshots: baseline-browser-mapping@2.10.11: {} + baseline-browser-mapping@2.10.23: {} + basic-auth@2.0.1: dependencies: safe-buffer: 5.1.2 @@ -18352,6 +19112,8 @@ snapshots: node-addon-api: 8.7.0 node-gyp-build: 4.8.4 + better-result@2.8.2: {} + bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 @@ -18376,7 +19138,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.15.1 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -18400,6 +19162,10 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -18425,6 +19191,14 @@ snapshots: node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.23 + caniuse-lite: 1.0.30001791 + electron-to-chromium: 1.5.344 + node-releases: 2.0.38 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + bs-logger@0.2.6: dependencies: fast-json-stable-stringify: 2.1.0 @@ -18464,20 +19238,20 @@ snapshots: bytes@3.1.2: {} - c12@3.1.0: + c12@3.3.4: dependencies: - chokidar: 4.0.3 + chokidar: 5.0.0 confbox: 0.2.4 - defu: 6.1.4 - dotenv: 16.6.1 + defu: 6.1.7 + dotenv: 17.4.2 exsolve: 1.0.8 - giget: 2.0.0 + giget: 3.2.0 jiti: 2.6.1 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 1.0.0 + perfect-debounce: 2.1.0 pkg-types: 2.3.0 - rc9: 2.1.2 + rc9: 3.0.1 cac@6.7.14: {} @@ -18493,6 +19267,13 @@ snapshots: get-intrinsic: 1.3.0 set-function-length: 1.2.2 + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 @@ -18515,14 +19296,16 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001781 + browserslist: 4.28.2 + caniuse-lite: 1.0.30001791 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 optional: true caniuse-lite@1.0.30001781: {} + caniuse-lite@1.0.30001791: {} + capital-case@1.0.4: dependencies: no-case: 3.0.4 @@ -18589,6 +19372,10 @@ snapshots: charset@1.0.1: {} + chart.js@4.5.1: + dependencies: + '@kurkle/color': 0.3.4 + check-disk-space@3.4.0: {} cheerio-select@2.1.0: @@ -18612,15 +19399,6 @@ snapshots: parse5-htmlparser2-tree-adapter: 7.1.0 optional: true - chevrotain@10.5.0: - dependencies: - '@chevrotain/cst-dts-gen': 10.5.0 - '@chevrotain/gast': 10.5.0 - '@chevrotain/types': 10.5.0 - '@chevrotain/utils': 10.5.0 - lodash: 4.17.23 - regexp-to-ast: 0.5.0 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -18637,18 +19415,16 @@ snapshots: dependencies: readdirp: 4.1.2 + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + chrome-trace-event@1.0.4: {} ci-info@3.9.0: {} ci-info@4.4.0: {} - citty@0.1.6: - dependencies: - consola: 3.4.2 - - citty@0.2.1: {} - cjs-module-lexer@2.2.0: {} class-transformer@0.5.1: {} @@ -18742,6 +19518,9 @@ snapshots: commander@4.1.1: {} + commander@5.1.0: + optional: true + commander@6.2.1: optional: true @@ -18750,10 +19529,9 @@ snapshots: commander@9.5.0: optional: true - comment-json@4.4.1: + comment-json@5.0.0: dependencies: array-timsort: 1.0.3 - core-util-is: 1.0.3 esprima: 4.0.1 common-tags@1.8.2: {} @@ -18802,7 +19580,7 @@ snapshots: content-type@1.0.5: {} - conventional-changelog-angular@8.3.0: + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -18815,6 +19593,11 @@ snapshots: '@simple-libs/stream-utils': 1.2.0 meow: 13.2.0 + conventional-commits-parser@6.4.0: + dependencies: + '@simple-libs/stream-utils': 1.2.0 + meow: 13.2.0 + convert-source-map@2.0.0: {} cookie-es@2.0.0: {} @@ -18826,8 +19609,6 @@ snapshots: cookie-signature@1.0.6: {} - cookie-signature@1.0.7: {} - cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -18855,7 +19636,7 @@ snapshots: corser@2.0.1: {} - cosmiconfig-typescript-loader@6.2.0(@types/node@24.10.1)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3): + cosmiconfig-typescript-loader@6.3.0(@types/node@24.10.1)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3): dependencies: '@types/node': 24.10.1 cosmiconfig: 9.0.1(typescript@5.9.3) @@ -18925,9 +19706,9 @@ snapshots: crypto-random-string@2.0.0: {} - css-declaration-sorter@7.3.1(postcss@8.5.8): + css-declaration-sorter@7.3.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 optional: true css-select@5.2.2: @@ -18957,51 +19738,51 @@ snapshots: cssfilter@0.0.10: {} - cssnano-preset-default@7.0.11(postcss@8.5.8): - dependencies: - browserslist: 4.28.1 - css-declaration-sorter: 7.3.1(postcss@8.5.8) - cssnano-utils: 5.0.1(postcss@8.5.8) - postcss: 8.5.8 - postcss-calc: 10.1.1(postcss@8.5.8) - postcss-colormin: 7.0.6(postcss@8.5.8) - postcss-convert-values: 7.0.9(postcss@8.5.8) - postcss-discard-comments: 7.0.6(postcss@8.5.8) - postcss-discard-duplicates: 7.0.2(postcss@8.5.8) - postcss-discard-empty: 7.0.1(postcss@8.5.8) - postcss-discard-overridden: 7.0.1(postcss@8.5.8) - postcss-merge-longhand: 7.0.5(postcss@8.5.8) - postcss-merge-rules: 7.0.8(postcss@8.5.8) - postcss-minify-font-values: 7.0.1(postcss@8.5.8) - postcss-minify-gradients: 7.0.1(postcss@8.5.8) - postcss-minify-params: 7.0.6(postcss@8.5.8) - postcss-minify-selectors: 7.0.6(postcss@8.5.8) - postcss-normalize-charset: 7.0.1(postcss@8.5.8) - postcss-normalize-display-values: 7.0.1(postcss@8.5.8) - postcss-normalize-positions: 7.0.1(postcss@8.5.8) - postcss-normalize-repeat-style: 7.0.1(postcss@8.5.8) - postcss-normalize-string: 7.0.1(postcss@8.5.8) - postcss-normalize-timing-functions: 7.0.1(postcss@8.5.8) - postcss-normalize-unicode: 7.0.6(postcss@8.5.8) - postcss-normalize-url: 7.0.1(postcss@8.5.8) - postcss-normalize-whitespace: 7.0.1(postcss@8.5.8) - postcss-ordered-values: 7.0.2(postcss@8.5.8) - postcss-reduce-initial: 7.0.6(postcss@8.5.8) - postcss-reduce-transforms: 7.0.1(postcss@8.5.8) - postcss-svgo: 7.1.1(postcss@8.5.8) - postcss-unique-selectors: 7.0.5(postcss@8.5.8) - optional: true - - cssnano-utils@5.0.1(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - optional: true - - cssnano@7.1.3(postcss@8.5.8): - dependencies: - cssnano-preset-default: 7.0.11(postcss@8.5.8) + cssnano-preset-default@7.0.11(postcss@8.5.10): + dependencies: + browserslist: 4.28.2 + css-declaration-sorter: 7.3.1(postcss@8.5.10) + cssnano-utils: 5.0.1(postcss@8.5.10) + postcss: 8.5.10 + postcss-calc: 10.1.1(postcss@8.5.10) + postcss-colormin: 7.0.6(postcss@8.5.10) + postcss-convert-values: 7.0.9(postcss@8.5.10) + postcss-discard-comments: 7.0.6(postcss@8.5.10) + postcss-discard-duplicates: 7.0.2(postcss@8.5.10) + postcss-discard-empty: 7.0.1(postcss@8.5.10) + postcss-discard-overridden: 7.0.1(postcss@8.5.10) + postcss-merge-longhand: 7.0.5(postcss@8.5.10) + postcss-merge-rules: 7.0.8(postcss@8.5.10) + postcss-minify-font-values: 7.0.1(postcss@8.5.10) + postcss-minify-gradients: 7.0.1(postcss@8.5.10) + postcss-minify-params: 7.0.6(postcss@8.5.10) + postcss-minify-selectors: 7.0.6(postcss@8.5.10) + postcss-normalize-charset: 7.0.1(postcss@8.5.10) + postcss-normalize-display-values: 7.0.1(postcss@8.5.10) + postcss-normalize-positions: 7.0.1(postcss@8.5.10) + postcss-normalize-repeat-style: 7.0.1(postcss@8.5.10) + postcss-normalize-string: 7.0.1(postcss@8.5.10) + postcss-normalize-timing-functions: 7.0.1(postcss@8.5.10) + postcss-normalize-unicode: 7.0.6(postcss@8.5.10) + postcss-normalize-url: 7.0.1(postcss@8.5.10) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.10) + postcss-ordered-values: 7.0.2(postcss@8.5.10) + postcss-reduce-initial: 7.0.6(postcss@8.5.10) + postcss-reduce-transforms: 7.0.1(postcss@8.5.10) + postcss-svgo: 7.1.1(postcss@8.5.10) + postcss-unique-selectors: 7.0.5(postcss@8.5.10) + optional: true + + cssnano-utils@5.0.1(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + optional: true + + cssnano@7.1.3(postcss@8.5.10): + dependencies: + cssnano-preset-default: 7.0.11(postcss@8.5.10) lilconfig: 3.1.3 - postcss: 8.5.8 + postcss: 8.5.10 optional: true csso@5.0.5: @@ -19111,7 +19892,7 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.4: {} + defu@6.1.7: {} delayed-stream@1.0.0: {} @@ -19150,11 +19931,11 @@ snapshots: diff@7.0.0: {} - dioc@3.0.2(vue@3.5.31(typescript@5.9.3)): + dioc@3.0.2(vue@3.5.33(typescript@5.9.3)): dependencies: rxjs: 7.8.2 optionalDependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) dir-glob@3.0.1: dependencies: @@ -19203,7 +19984,11 @@ snapshots: domelementtype: 2.3.0 optional: true - dompurify@3.3.3: + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dompurify@3.4.1: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -19238,9 +20023,9 @@ snapshots: dotenv@16.6.1: {} - dotenv@17.2.3: {} + dotenv@17.4.1: {} - dotenv@17.3.1: {} + dotenv@17.4.2: {} dset@3.1.4: {} @@ -19273,8 +20058,13 @@ snapshots: dependencies: jake: 10.9.4 + ejs@5.0.2: + optional: true + electron-to-chromium@1.5.325: {} + electron-to-chromium@1.5.344: {} + emittery@0.13.1: {} emoji-regex@10.6.0: {} @@ -19382,6 +20172,8 @@ snapshots: env-paths@2.2.1: {} + env-paths@3.0.0: {} + environment@1.1.0: {} errno@0.1.8: @@ -19451,6 +20243,63 @@ snapshots: unbox-primitive: 1.1.0 which-typed-array: 1.1.20 + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.3 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.20 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -19668,35 +20517,35 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.1.8(eslint@10.0.3(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.0.3(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)): dependencies: eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.3(jiti@2.6.1)))(eslint@10.0.3(jiti@2.6.1))(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)))(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3): dependencies: - eslint: 10.0.3(jiti@2.6.1) - prettier: 3.8.1 + eslint: 10.2.1(jiti@2.6.1) + prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@10.0.3(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@10.2.1(jiti@2.6.1)) - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3): dependencies: eslint: 9.39.2(jiti@2.6.1) - prettier: 3.8.1 + prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))): + eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) eslint: 9.39.2(jiti@2.6.1) @@ -19707,7 +20556,7 @@ snapshots: vue-eslint-parser: 10.4.0(eslint@9.39.2(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.57.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-scope@5.1.1: dependencies: @@ -19732,14 +20581,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.0.3(jiti@2.6.1): + eslint@10.2.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.3 - '@eslint/config-helpers': 0.5.3 - '@eslint/core': 1.1.1 - '@eslint/plugin-kit': 0.6.1 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.5.5 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -19931,19 +20780,6 @@ snapshots: jest-mock: 30.3.0 jest-util: 30.3.0 - express-session@1.19.0: - dependencies: - cookie: 0.7.2 - cookie-signature: 1.0.7 - debug: 2.6.9 - depd: 2.0.0 - on-headers: 1.1.0 - parseurl: 1.3.3 - safe-buffer: 5.2.1 - uid-safe: 2.1.5 - transitivePeerDependencies: - - supports-color - express@5.2.1: dependencies: accepts: 2.0.0 @@ -20068,7 +20904,7 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-type@21.3.2: + file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.5 @@ -20081,7 +20917,7 @@ snapshots: filelist@1.0.6: dependencies: - minimatch: 10.2.3 + minimatch: 5.1.9 fill-range@7.1.1: dependencies: @@ -20133,7 +20969,7 @@ snapshots: flatted@3.4.2: {} - follow-redirects@1.15.11: {} + follow-redirects@1.16.0: {} for-each@0.3.5: dependencies: @@ -20144,7 +20980,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.104.1): + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.106.0): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -20159,14 +20995,14 @@ snapshots: semver: 7.7.4 tapable: 2.3.2 typescript: 5.9.3 - webpack: 5.104.1 + webpack: 5.106.0 form-data@4.0.4: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.3 mime-types: 2.1.35 formdata-polyfill@4.0.10: @@ -20199,7 +21035,7 @@ snapshots: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-monkey@1.1.0: {} @@ -20274,18 +21110,11 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - giget@2.0.0: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - defu: 6.1.4 - node-fetch-native: 1.6.7 - nypm: 0.6.5 - pathe: 2.0.3 + giget@3.2.0: {} - git-raw-commits@5.0.1(conventional-commits-parser@6.3.0): + git-raw-commits@5.0.1(conventional-commits-parser@6.4.0): dependencies: - '@conventional-changelog/git-client': 2.6.0(conventional-commits-parser@6.3.0) + '@conventional-changelog/git-client': 2.7.0(conventional-commits-parser@6.4.0) meow: 13.2.0 transitivePeerDependencies: - conventional-commits-filter @@ -20305,7 +21134,7 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 10.2.3 + minimatch: 9.0.9 minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 @@ -20314,17 +21143,11 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 4.2.3 - minimatch: 10.2.3 + minimatch: 10.2.4 minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 2.0.2 - glob@13.0.0: - dependencies: - minimatch: 10.2.3 - minipass: 7.1.3 - path-scurry: 2.0.2 - glob@13.0.6: dependencies: minimatch: 10.2.3 @@ -20340,15 +21163,15 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - global-directory@4.0.1: + global-directory@5.0.0: dependencies: - ini: 4.1.1 + ini: 6.0.0 globals@14.0.0: {} globals@16.5.0: {} - globals@17.4.0: {} + globals@17.5.0: {} globalthis@1.0.4: dependencies: @@ -20372,16 +21195,16 @@ snapshots: graphmatch@1.1.1: {} - graphql-config@4.5.0(@types/node@24.10.1)(graphql@16.13.1): + graphql-config@4.5.0(@types/node@24.10.1)(graphql@16.13.2): dependencies: - '@graphql-tools/graphql-file-loader': 7.5.17(graphql@16.13.1) - '@graphql-tools/json-file-loader': 7.4.18(graphql@16.13.1) - '@graphql-tools/load': 7.8.14(graphql@16.13.1) - '@graphql-tools/merge': 8.4.2(graphql@16.13.1) - '@graphql-tools/url-loader': 7.17.18(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/utils': 9.2.1(graphql@16.13.1) + '@graphql-tools/graphql-file-loader': 7.5.17(graphql@16.13.2) + '@graphql-tools/json-file-loader': 7.4.18(graphql@16.13.2) + '@graphql-tools/load': 7.8.14(graphql@16.13.2) + '@graphql-tools/merge': 8.4.2(graphql@16.13.2) + '@graphql-tools/url-loader': 7.17.18(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/utils': 9.2.1(graphql@16.13.2) cosmiconfig: 8.0.0 - graphql: 16.13.1 + graphql: 16.13.2 jiti: 1.17.1 minimatch: 4.2.5 string-env-interpolation: 1.0.1 @@ -20392,18 +21215,18 @@ snapshots: - encoding - utf-8-validate - graphql-config@5.1.6(@types/node@24.10.1)(graphql@16.13.1)(typescript@5.9.3): + graphql-config@5.1.6(@types/node@24.10.1)(graphql@16.13.2)(typescript@5.9.3): dependencies: - '@graphql-tools/graphql-file-loader': 8.1.12(graphql@16.13.1) - '@graphql-tools/json-file-loader': 8.0.26(graphql@16.13.1) - '@graphql-tools/load': 8.1.8(graphql@16.13.1) - '@graphql-tools/merge': 9.1.7(graphql@16.13.1) - '@graphql-tools/url-loader': 9.0.6(@types/node@24.10.1)(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/graphql-file-loader': 8.1.14(graphql@16.13.2) + '@graphql-tools/json-file-loader': 8.0.28(graphql@16.13.2) + '@graphql-tools/load': 8.1.10(graphql@16.13.2) + '@graphql-tools/merge': 9.1.9(graphql@16.13.2) + '@graphql-tools/url-loader': 9.1.2(@types/node@24.10.1)(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) cosmiconfig: 8.3.6(typescript@5.9.3) - graphql: 16.13.1 + graphql: 16.13.2 jiti: 2.6.1 - minimatch: 10.2.3 + minimatch: 10.2.4 string-env-interpolation: 1.0.1 tslib: 2.8.1 transitivePeerDependencies: @@ -20414,18 +21237,18 @@ snapshots: - typescript - utf-8-validate - graphql-config@5.1.6(@types/node@25.5.0)(graphql@16.13.1)(typescript@5.9.3): + graphql-config@5.1.6(@types/node@25.6.0)(graphql@16.13.2)(typescript@5.9.3): dependencies: - '@graphql-tools/graphql-file-loader': 8.1.12(graphql@16.13.1) - '@graphql-tools/json-file-loader': 8.0.26(graphql@16.13.1) - '@graphql-tools/load': 8.1.8(graphql@16.13.1) - '@graphql-tools/merge': 9.1.7(graphql@16.13.1) - '@graphql-tools/url-loader': 9.0.6(@types/node@25.5.0)(graphql@16.13.1) - '@graphql-tools/utils': 11.0.0(graphql@16.13.1) + '@graphql-tools/graphql-file-loader': 8.1.14(graphql@16.13.2) + '@graphql-tools/json-file-loader': 8.0.28(graphql@16.13.2) + '@graphql-tools/load': 8.1.10(graphql@16.13.2) + '@graphql-tools/merge': 9.1.9(graphql@16.13.2) + '@graphql-tools/url-loader': 9.1.2(@types/node@25.6.0)(graphql@16.13.2) + '@graphql-tools/utils': 11.1.0(graphql@16.13.2) cosmiconfig: 8.3.6(typescript@5.9.3) - graphql: 16.13.1 + graphql: 16.13.2 jiti: 2.6.1 - minimatch: 10.2.3 + minimatch: 10.2.4 string-env-interpolation: 1.0.1 tslib: 2.8.1 transitivePeerDependencies: @@ -20436,13 +21259,13 @@ snapshots: - typescript - utf-8-validate - graphql-language-service-interface@2.10.2(@types/node@24.10.1)(graphql@16.13.1): + graphql-language-service-interface@2.10.2(@types/node@24.10.1)(graphql@16.13.2): dependencies: - graphql: 16.13.1 - graphql-config: 4.5.0(@types/node@24.10.1)(graphql@16.13.1) - graphql-language-service-parser: 1.10.4(@types/node@24.10.1)(graphql@16.13.1) - graphql-language-service-types: 1.8.7(@types/node@24.10.1)(graphql@16.13.1) - graphql-language-service-utils: 2.7.1(@types/node@24.10.1)(graphql@16.13.1) + graphql: 16.13.2 + graphql-config: 4.5.0(@types/node@24.10.1)(graphql@16.13.2) + graphql-language-service-parser: 1.10.4(@types/node@24.10.1)(graphql@16.13.2) + graphql-language-service-types: 1.8.7(@types/node@24.10.1)(graphql@16.13.2) + graphql-language-service-utils: 2.7.1(@types/node@24.10.1)(graphql@16.13.2) vscode-languageserver-types: 3.17.5 transitivePeerDependencies: - '@types/node' @@ -20451,10 +21274,10 @@ snapshots: - encoding - utf-8-validate - graphql-language-service-parser@1.10.4(@types/node@24.10.1)(graphql@16.13.1): + graphql-language-service-parser@1.10.4(@types/node@24.10.1)(graphql@16.13.2): dependencies: - graphql: 16.13.1 - graphql-language-service-types: 1.8.7(@types/node@24.10.1)(graphql@16.13.1) + graphql: 16.13.2 + graphql-language-service-types: 1.8.7(@types/node@24.10.1)(graphql@16.13.2) transitivePeerDependencies: - '@types/node' - bufferutil @@ -20462,10 +21285,10 @@ snapshots: - encoding - utf-8-validate - graphql-language-service-types@1.8.7(@types/node@24.10.1)(graphql@16.13.1): + graphql-language-service-types@1.8.7(@types/node@24.10.1)(graphql@16.13.2): dependencies: - graphql: 16.13.1 - graphql-config: 4.5.0(@types/node@24.10.1)(graphql@16.13.1) + graphql: 16.13.2 + graphql-config: 4.5.0(@types/node@24.10.1)(graphql@16.13.2) vscode-languageserver-types: 3.17.5 transitivePeerDependencies: - '@types/node' @@ -20474,11 +21297,11 @@ snapshots: - encoding - utf-8-validate - graphql-language-service-utils@2.7.1(@types/node@24.10.1)(graphql@16.13.1): + graphql-language-service-utils@2.7.1(@types/node@24.10.1)(graphql@16.13.2): dependencies: '@types/json-schema': 7.0.9 - graphql: 16.13.1 - graphql-language-service-types: 1.8.7(@types/node@24.10.1)(graphql@16.13.1) + graphql: 16.13.2 + graphql-language-service-types: 1.8.7(@types/node@24.10.1)(graphql@16.13.2) nullthrows: 1.1.1 transitivePeerDependencies: - '@types/node' @@ -20487,39 +21310,39 @@ snapshots: - encoding - utf-8-validate - graphql-query-complexity@1.1.0(graphql@16.13.1): + graphql-query-complexity@1.1.0(graphql@16.13.2): dependencies: - graphql: 16.13.1 + graphql: 16.13.2 lodash.get: 4.4.2 - graphql-redis-subscriptions@2.7.0(graphql-subscriptions@3.0.0(graphql@16.13.1)): + graphql-redis-subscriptions@2.7.0(graphql-subscriptions@3.0.0(graphql@16.13.2)): dependencies: - graphql-subscriptions: 3.0.0(graphql@16.13.1) + graphql-subscriptions: 3.0.0(graphql@16.13.2) optionalDependencies: ioredis: 5.10.1 transitivePeerDependencies: - supports-color - graphql-subscriptions@3.0.0(graphql@16.13.1): + graphql-subscriptions@3.0.0(graphql@16.13.2): dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - graphql-tag@2.12.6(graphql@16.13.1): + graphql-tag@2.12.6(graphql@16.13.2): dependencies: - graphql: 16.13.1 + graphql: 16.13.2 tslib: 2.8.1 - graphql-ws@5.12.1(graphql@16.13.1): + graphql-ws@5.12.1(graphql@16.13.2): dependencies: - graphql: 16.13.1 + graphql: 16.13.2 - graphql-ws@6.0.7(graphql@16.13.1)(ws@8.17.1): + graphql-ws@6.0.8(graphql@16.13.2)(ws@8.17.1): dependencies: - graphql: 16.13.1 + graphql: 16.13.2 optionalDependencies: ws: 8.17.1 - graphql@16.13.1: {} + graphql@16.13.2: {} handlebars@4.7.9: dependencies: @@ -20562,6 +21385,10 @@ snapshots: dependencies: function-bind: 1.1.2 + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + hawk@9.0.2: dependencies: '@hapi/b64': 5.0.0 @@ -20580,7 +21407,7 @@ snapshots: highlightjs-curl@1.3.0: {} - hono@4.12.7: {} + hono@4.12.15: {} hookable@6.1.0: {} @@ -20590,9 +21417,9 @@ snapshots: dependencies: whatwg-encoding: 2.0.0 - html-encoding-sniffer@6.0.0(@noble/hashes@2.0.1): + html-encoding-sniffer@6.0.0(@noble/hashes@2.2.0): dependencies: - '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) + '@exodus/bytes': 1.15.0(@noble/hashes@2.2.0) transitivePeerDependencies: - '@noble/hashes' @@ -20607,14 +21434,14 @@ snapshots: selderee: 0.11.0 optional: true - htmlnano@2.1.5(cssnano@7.1.3(postcss@8.5.8))(postcss@8.5.8)(terser@5.46.1)(typescript@5.9.3): + htmlnano@2.1.5(cssnano@7.1.3(postcss@8.5.10))(postcss@8.5.10)(terser@5.46.1)(typescript@5.9.3): dependencies: '@types/relateurl': 0.2.33 cosmiconfig: 9.0.1(typescript@5.9.3) posthtml: 0.16.7 optionalDependencies: - cssnano: 7.1.3(postcss@8.5.8) - postcss: 8.5.8 + cssnano: 7.1.3(postcss@8.5.10) + postcss: 8.5.10 terser: 5.46.1 transitivePeerDependencies: - typescript @@ -20675,7 +21502,7 @@ snapshots: http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.11 + follow-redirects: 1.16.0 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -20768,7 +21595,7 @@ snapshots: ini@1.3.8: optional: true - ini@4.1.1: {} + ini@6.0.0: {} insomnia-importers@3.6.0(openapi-types@12.1.3): dependencies: @@ -21108,7 +21935,7 @@ snapshots: '@jest/expect': 30.3.0 '@jest/test-result': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.2 @@ -21128,15 +21955,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)): + jest-cli@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)): dependencies: - '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) '@jest/test-result': 30.3.0 '@jest/types': 30.3.0 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + jest-config: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) jest-util: 30.3.0 jest-validate: 30.3.0 yargs: 17.7.2 @@ -21147,7 +21974,7 @@ snapshots: - supports-color - ts-node - jest-config@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)): + jest-config@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)): dependencies: '@babel/core': 7.29.0 '@jest/get-type': 30.1.0 @@ -21173,8 +22000,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 25.5.0 - ts-node: 10.9.2(@types/node@25.5.0)(typescript@5.9.3) + '@types/node': 25.6.0 + ts-node: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -21210,7 +22037,7 @@ snapshots: '@jest/environment': 30.3.0 '@jest/fake-timers': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 jest-mock: 30.3.0 jest-util: 30.3.0 jest-validate: 30.3.0 @@ -21220,7 +22047,7 @@ snapshots: jest-haste-map@30.3.0: dependencies: '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -21275,17 +22102,18 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.6 - jest-mock-extended@4.0.0(@jest/globals@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3): + jest-mock-extended@4.0.1(@jest/globals@30.3.0)(jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)))(typescript@5.9.3): dependencies: '@jest/globals': 30.3.0 - jest: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + jest: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) + lodash.isequal: 4.5.0 ts-essentials: 10.1.1(typescript@5.9.3) typescript: 5.9.3 jest-mock@30.3.0: dependencies: '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 jest-util: 30.3.0 jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): @@ -21319,7 +22147,7 @@ snapshots: '@jest/test-result': 30.3.0 '@jest/transform': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 emittery: 0.13.1 exit-x: 0.2.2 @@ -21348,7 +22176,7 @@ snapshots: '@jest/test-result': 30.3.0 '@jest/transform': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 cjs-module-lexer: 2.2.0 collect-v8-coverage: 1.0.3 @@ -21395,7 +22223,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -21404,7 +22232,7 @@ snapshots: jest-util@30.3.0: dependencies: '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 chalk: 4.1.2 ci-info: 4.4.0 graceful-fs: 4.2.11 @@ -21423,7 +22251,7 @@ snapshots: dependencies: '@jest/test-result': 30.3.0 '@jest/types': 30.3.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -21432,24 +22260,24 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@30.3.0: dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@ungap/structured-clone': 1.3.0 jest-util: 30.3.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)): + jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)): dependencies: - '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) '@jest/types': 30.3.0 import-local: 3.2.0 - jest-cli: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + jest-cli: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -21487,15 +22315,15 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@27.4.0(@noble/hashes@2.0.1): + jsdom@27.4.0(@noble/hashes@2.2.0): dependencies: '@acemir/cssom': 0.9.31 '@asamuzakjp/dom-selector': 6.8.1 - '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) + '@exodus/bytes': 1.15.0(@noble/hashes@2.2.0) cssstyle: 5.3.7 data-urls: 6.0.1 decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0(@noble/hashes@2.0.1) + html-encoding-sniffer: 6.0.0(@noble/hashes@2.2.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 @@ -21527,8 +22355,6 @@ snapshots: json-schema-traverse@1.0.0: {} - json-schema@0.4.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} json-to-pretty-yaml@1.2.2: @@ -21553,6 +22379,12 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsonpointer@5.0.1: {} jsonwebtoken@9.0.3: @@ -21639,8 +22471,6 @@ snapshots: dependencies: immediate: 3.0.6 - lilconfig@2.1.0: {} - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -21660,7 +22490,7 @@ snapshots: liquid-json@0.3.1: {} - liquidjs@10.25.0: + liquidjs@10.25.7: dependencies: commander: 10.0.1 optional: true @@ -21701,7 +22531,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.23: {} + lodash-es@4.18.1: {} lodash.camelcase@4.3.0: {} @@ -21737,7 +22567,7 @@ snapshots: lodash.mergewith@4.6.2: {} - lodash.omit@4.5.0: {} + lodash.omit@4.18.0: {} lodash.once@4.1.1: {} @@ -21752,7 +22582,7 @@ snapshots: lodash.upperfirst@4.3.1: {} - lodash@4.17.23: {} + lodash@4.18.1: {} log-symbols@4.1.0: dependencies: @@ -21893,9 +22723,9 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 - meros@1.3.2(@types/node@25.5.0): + meros@1.3.2(@types/node@25.6.0): optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 methods@1.1.2: {} @@ -21946,6 +22776,14 @@ snapshots: dependencies: brace-expansion: 1.1.12 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.0 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + minimist@1.2.8: {} minipass@7.1.3: {} @@ -21955,7 +22793,7 @@ snapshots: mjml-accordion@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -21971,7 +22809,7 @@ snapshots: mjml-body@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -21987,7 +22825,7 @@ snapshots: mjml-button@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22003,7 +22841,7 @@ snapshots: mjml-carousel@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22021,8 +22859,8 @@ snapshots: '@babel/runtime': 7.29.2 chokidar: 3.6.0 glob: 10.5.0 - lodash: 4.17.23 - minimatch: 10.2.3 + lodash: 4.18.1 + minimatch: 9.0.9 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) mjml-parser-xml: 5.0.0-alpha.4 mjml-validator: 5.0.0-alpha.4 @@ -22041,7 +22879,7 @@ snapshots: mjml-column@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22058,15 +22896,15 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 cheerio: 1.0.0-rc.12 - cssnano: 7.1.3(postcss@8.5.8) + cssnano: 7.1.3(postcss@8.5.10) detect-node: 2.1.0 - htmlnano: 2.1.5(cssnano@7.1.3(postcss@8.5.8))(postcss@8.5.8)(terser@5.46.1)(typescript@5.9.3) + htmlnano: 2.1.5(cssnano@7.1.3(postcss@8.5.10))(postcss@8.5.10)(terser@5.46.1)(typescript@5.9.3) juice: 10.0.1 - lodash: 4.17.23 + lodash: 4.18.1 mjml-parser-xml: 5.0.0-alpha.4 mjml-validator: 5.0.0-alpha.4 - postcss: 8.5.8 - prettier: 3.8.1 + postcss: 8.5.10 + prettier: 3.8.3 transitivePeerDependencies: - encoding - purgecss @@ -22081,7 +22919,7 @@ snapshots: mjml-divider@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22097,7 +22935,7 @@ snapshots: mjml-group@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22113,7 +22951,7 @@ snapshots: mjml-head-attributes@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22129,7 +22967,7 @@ snapshots: mjml-head-breakpoint@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22145,7 +22983,7 @@ snapshots: mjml-head-font@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22161,7 +22999,7 @@ snapshots: mjml-head-html-attributes@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22177,7 +23015,7 @@ snapshots: mjml-head-preview@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22193,7 +23031,7 @@ snapshots: mjml-head-style@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22209,7 +23047,7 @@ snapshots: mjml-head-title@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22225,7 +23063,7 @@ snapshots: mjml-head@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22241,7 +23079,7 @@ snapshots: mjml-hero@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22257,7 +23095,7 @@ snapshots: mjml-image@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22273,7 +23111,7 @@ snapshots: mjml-navbar@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22291,7 +23129,7 @@ snapshots: '@babel/runtime': 7.29.2 detect-node: 2.1.0 htmlparser2: 9.1.0 - lodash: 4.17.23 + lodash: 4.18.1 optional: true mjml-preset-core@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): @@ -22336,7 +23174,7 @@ snapshots: mjml-raw@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22352,7 +23190,7 @@ snapshots: mjml-section@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22368,7 +23206,7 @@ snapshots: mjml-social@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22384,7 +23222,7 @@ snapshots: mjml-spacer@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22400,7 +23238,7 @@ snapshots: mjml-table@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22416,7 +23254,7 @@ snapshots: mjml-text@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: - encoding @@ -22437,7 +23275,7 @@ snapshots: mjml-wrapper@5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - lodash: 4.17.23 + lodash: 4.18.1 mjml-core: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) mjml-section: 5.0.0-alpha.4(terser@5.46.1)(typescript@5.9.3) transitivePeerDependencies: @@ -22491,10 +23329,10 @@ snapshots: is-path-inside: 3.0.3 js-yaml: 4.1.1 log-symbols: 4.1.0 - minimatch: 10.2.3 + minimatch: 9.0.9 ms: 2.1.3 picocolors: 1.1.1 - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.3 strip-json-comments: 3.1.1 supports-color: 8.1.1 workerpool: 9.3.4 @@ -22504,7 +23342,7 @@ snapshots: monaco-editor@0.55.1: dependencies: - dompurify: 3.3.3 + dompurify: 3.2.7 marked: 14.0.0 morgan@1.10.1: @@ -22584,14 +23422,12 @@ snapshots: node-emoji@1.11.0: dependencies: - lodash: 4.17.23 + lodash: 4.18.1 node-fetch-h2@2.3.0: dependencies: http2-client: 1.3.5 - node-fetch-native@1.6.7: {} - node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -22612,10 +23448,12 @@ snapshots: node-releases@2.0.36: {} + node-releases@2.0.38: {} + nodemailer@7.0.13: optional: true - nodemailer@8.0.4: {} + nodemailer@8.0.7: {} normalize-package-data@2.5.0: dependencies: @@ -22664,11 +23502,14 @@ snapshots: nullthrows@1.1.1: {} - nypm@0.6.5: + nunjucks@3.2.4(chokidar@4.0.3): dependencies: - citty: 0.2.1 - pathe: 2.0.3 - tinyexec: 1.0.4 + a-sync-waterfall: 1.0.1 + asap: 2.0.6 + commander: 5.1.0 + optionalDependencies: + chokidar: 4.0.3 + optional: true oas-kit-common@1.0.8: dependencies: @@ -22720,8 +23561,6 @@ snapshots: has-symbols: 1.1.0 object-keys: 1.1.1 - obuf@1.1.2: {} - obug@2.1.1: {} ohash@2.0.11: {} @@ -22983,6 +23822,8 @@ snapshots: path-to-regexp@8.4.0: {} + path-to-regexp@8.4.2: {} + path-type@3.0.0: dependencies: pify: 3.0.0 @@ -23011,8 +23852,6 @@ snapshots: pend@1.2.0: {} - perfect-debounce@1.0.0: {} - perfect-debounce@2.1.0: {} pg-cloudflare@1.3.0: @@ -23022,8 +23861,6 @@ snapshots: pg-int8@1.0.1: {} - pg-numeric@1.0.2: {} - pg-pool@3.13.0(pg@8.20.0): dependencies: pg: 8.20.0 @@ -23038,16 +23875,6 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg-types@4.1.0: - dependencies: - pg-int8: 1.0.1 - pg-numeric: 1.0.2 - postgres-array: 3.0.4 - postgres-bytea: 3.0.0 - postgres-date: 2.1.0 - postgres-interval: 3.0.0 - postgres-range: 1.1.4 - pg@8.20.0: dependencies: pg-connection-string: 2.12.0 @@ -23066,8 +23893,6 @@ snapshots: picomatch@2.3.2: {} - picomatch@4.0.2: {} - picomatch@4.0.4: {} pidtree@0.3.1: {} @@ -23105,207 +23930,207 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-calc@10.1.1(postcss@8.5.8): + postcss-calc@10.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 optional: true - postcss-colormin@7.0.6(postcss@8.5.8): + postcss-colormin@7.0.6(postcss@8.5.10): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-convert-values@7.0.9(postcss@8.5.8): + postcss-convert-values@7.0.9(postcss@8.5.10): dependencies: - browserslist: 4.28.1 - postcss: 8.5.8 + browserslist: 4.28.2 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-discard-comments@7.0.6(postcss@8.5.8): + postcss-discard-comments@7.0.6(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 optional: true - postcss-discard-duplicates@7.0.2(postcss@8.5.8): + postcss-discard-duplicates@7.0.2(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 optional: true - postcss-discard-empty@7.0.1(postcss@8.5.8): + postcss-discard-empty@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 optional: true - postcss-discard-overridden@7.0.1(postcss@8.5.8): + postcss-discard-overridden@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 optional: true - postcss-import@15.1.0(postcss@8.5.8): + postcss-import@15.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.11 - postcss-js@4.1.0(postcss@8.5.8): + postcss-js@4.1.0(postcss@8.5.10): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.8 + postcss: 8.5.10 - postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.5.10)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.3 optionalDependencies: - postcss: 8.5.8 + postcss: 8.5.10 ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) - postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.5.10)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.3 optionalDependencies: - postcss: 8.5.8 - ts-node: 10.9.2(@types/node@25.5.0)(typescript@5.9.3) + postcss: 8.5.10 + ts-node: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.3): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.10)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 - postcss: 8.5.8 + postcss: 8.5.10 yaml: 2.8.3 - postcss-merge-longhand@7.0.5(postcss@8.5.8): + postcss-merge-longhand@7.0.5(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - stylehacks: 7.0.8(postcss@8.5.8) + stylehacks: 7.0.8(postcss@8.5.10) optional: true - postcss-merge-rules@7.0.8(postcss@8.5.8): + postcss-merge-rules@7.0.8(postcss@8.5.10): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-api: 3.0.0 - cssnano-utils: 5.0.1(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 5.0.1(postcss@8.5.10) + postcss: 8.5.10 postcss-selector-parser: 7.1.1 optional: true - postcss-minify-font-values@7.0.1(postcss@8.5.8): + postcss-minify-font-values@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-minify-gradients@7.0.1(postcss@8.5.8): + postcss-minify-gradients@7.0.1(postcss@8.5.10): dependencies: colord: 2.9.3 - cssnano-utils: 5.0.1(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 5.0.1(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-minify-params@7.0.6(postcss@8.5.8): + postcss-minify-params@7.0.6(postcss@8.5.10): dependencies: - browserslist: 4.28.1 - cssnano-utils: 5.0.1(postcss@8.5.8) - postcss: 8.5.8 + browserslist: 4.28.2 + cssnano-utils: 5.0.1(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-minify-selectors@7.0.6(postcss@8.5.8): + postcss-minify-selectors@7.0.6(postcss@8.5.10): dependencies: cssesc: 3.0.0 - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 optional: true - postcss-nested@6.2.0(postcss@8.5.8): + postcss-nested@6.2.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 6.1.2 - postcss-normalize-charset@7.0.1(postcss@8.5.8): + postcss-normalize-charset@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 optional: true - postcss-normalize-display-values@7.0.1(postcss@8.5.8): + postcss-normalize-display-values@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-positions@7.0.1(postcss@8.5.8): + postcss-normalize-positions@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-repeat-style@7.0.1(postcss@8.5.8): + postcss-normalize-repeat-style@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-string@7.0.1(postcss@8.5.8): + postcss-normalize-string@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-timing-functions@7.0.1(postcss@8.5.8): + postcss-normalize-timing-functions@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-unicode@7.0.6(postcss@8.5.8): + postcss-normalize-unicode@7.0.6(postcss@8.5.10): dependencies: - browserslist: 4.28.1 - postcss: 8.5.8 + browserslist: 4.28.2 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-url@7.0.1(postcss@8.5.8): + postcss-normalize-url@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-normalize-whitespace@7.0.1(postcss@8.5.8): + postcss-normalize-whitespace@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-ordered-values@7.0.2(postcss@8.5.8): + postcss-ordered-values@7.0.2(postcss@8.5.10): dependencies: - cssnano-utils: 5.0.1(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 5.0.1(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true - postcss-reduce-initial@7.0.6(postcss@8.5.8): + postcss-reduce-initial@7.0.6(postcss@8.5.10): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-api: 3.0.0 - postcss: 8.5.8 + postcss: 8.5.10 optional: true - postcss-reduce-transforms@7.0.1(postcss@8.5.8): + postcss-reduce-transforms@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 optional: true @@ -23319,22 +24144,22 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@7.1.1(postcss@8.5.8): + postcss-svgo@7.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 svgo: 4.0.1 optional: true - postcss-unique-selectors@7.0.5(postcss@8.5.8): + postcss-unique-selectors@7.0.5(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 optional: true postcss-value-parser@4.2.0: {} - postcss@8.5.8: + postcss@8.5.10: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -23346,27 +24171,17 @@ snapshots: postgres-bytea@1.0.1: {} - postgres-bytea@3.0.0: - dependencies: - obuf: 1.1.2 - postgres-date@1.0.7: {} - postgres-date@2.1.0: {} - postgres-interval@1.2.0: dependencies: xtend: 4.0.2 - postgres-interval@3.0.0: {} - - postgres-range@1.1.4: {} - postgres@3.4.7: {} - posthog-node@5.28.4(rxjs@7.8.2): + posthog-node@5.30.6(rxjs@7.8.2): dependencies: - '@posthog/core': 1.24.0 + '@posthog/core': 1.27.7 optionalDependencies: rxjs: 7.8.2 @@ -23393,7 +24208,7 @@ snapshots: http-reasons: 0.1.0 iconv-lite: 0.6.3 liquid-json: 0.3.1 - lodash: 4.17.23 + lodash: 4.18.1 mime: 3.0.0 mime-format: 2.0.2 postman-url-encoder: 3.0.8 @@ -23410,15 +24225,15 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier-plugin-tailwindcss@0.7.1(prettier@3.8.1): + prettier-plugin-tailwindcss@0.7.1(prettier@3.8.3): dependencies: - prettier: 3.8.1 + prettier: 3.8.3 - prettier-plugin-tailwindcss@0.7.2(prettier@3.8.1): + prettier-plugin-tailwindcss@0.7.2(prettier@3.8.3): dependencies: - prettier: 3.8.1 + prettier: 3.8.3 - prettier@3.8.1: {} + prettier@3.8.3: {} pretty-bytes@5.6.0: {} @@ -23451,18 +24266,19 @@ snapshots: uuid: 9.0.1 optional: true - prisma@7.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): dependencies: - '@prisma/config': 7.5.0 - '@prisma/dev': 0.20.0(typescript@5.9.3) - '@prisma/engines': 7.5.0 - '@prisma/studio-core': 0.21.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@prisma/config': 7.8.0 + '@prisma/dev': 0.24.3(typescript@5.9.3) + '@prisma/engines': 7.8.0 + '@prisma/studio-core': 0.27.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) mysql2: 3.15.3 postgres: 3.4.7 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - '@types/react' + - '@types/react-dom' - magicast - react - react-dom @@ -23486,7 +24302,7 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} prr@1.0.1: {} @@ -23595,6 +24411,10 @@ snapshots: dependencies: side-channel: 1.1.0 + qs@6.15.1: + dependencies: + side-channel: 1.1.0 + quansync@0.2.11: {} queue-microtask@1.2.3: {} @@ -23619,7 +24439,7 @@ snapshots: cross-fetch: 4.1.0 is-url: 1.2.4 js-base64: 3.7.8 - lodash: 4.17.23 + lodash: 4.18.1 pako: 1.0.11 pluralize: 8.0.0 readable-stream: 4.5.2 @@ -23636,12 +24456,6 @@ snapshots: ramda@0.27.2: {} - random-bytes@1.0.0: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - range-parser@1.2.1: {} raw-body@3.0.2: @@ -23651,9 +24465,9 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - rc9@2.1.2: + rc9@3.0.1: dependencies: - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 rc@1.2.8: @@ -23713,6 +24527,8 @@ snapshots: readdirp@4.1.2: {} + readdirp@5.0.0: {} + redis-errors@1.2.0: optional: true @@ -23746,8 +24562,6 @@ snapshots: regenerator-runtime@0.14.1: {} - regexp-to-ast@0.5.0: {} - regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -23812,6 +24626,13 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -23849,10 +24670,10 @@ snapshots: dependencies: rollup-plugin-inject: 3.0.2 - rollup-plugin-polyfill-node@0.13.0(rollup@4.59.0): + rollup-plugin-polyfill-node@0.13.0(rollup@4.60.2): dependencies: - '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) - rollup: 4.59.0 + '@rollup/plugin-inject': 5.0.5(rollup@4.60.2) + rollup: 4.60.2 rollup-pluginutils@2.8.2: dependencies: @@ -23893,6 +24714,37 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + rollup@4.60.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.2 + '@rollup/rollup-android-arm64': 4.60.2 + '@rollup/rollup-darwin-arm64': 4.60.2 + '@rollup/rollup-darwin-x64': 4.60.2 + '@rollup/rollup-freebsd-arm64': 4.60.2 + '@rollup/rollup-freebsd-x64': 4.60.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 + '@rollup/rollup-linux-arm-musleabihf': 4.60.2 + '@rollup/rollup-linux-arm64-gnu': 4.60.2 + '@rollup/rollup-linux-arm64-musl': 4.60.2 + '@rollup/rollup-linux-loong64-gnu': 4.60.2 + '@rollup/rollup-linux-loong64-musl': 4.60.2 + '@rollup/rollup-linux-ppc64-gnu': 4.60.2 + '@rollup/rollup-linux-ppc64-musl': 4.60.2 + '@rollup/rollup-linux-riscv64-gnu': 4.60.2 + '@rollup/rollup-linux-riscv64-musl': 4.60.2 + '@rollup/rollup-linux-s390x-gnu': 4.60.2 + '@rollup/rollup-linux-x64-gnu': 4.60.2 + '@rollup/rollup-linux-x64-musl': 4.60.2 + '@rollup/rollup-openbsd-x64': 4.60.2 + '@rollup/rollup-openharmony-arm64': 4.60.2 + '@rollup/rollup-win32-arm64-msvc': 4.60.2 + '@rollup/rollup-win32-ia32-msvc': 4.60.2 + '@rollup/rollup-win32-x64-gnu': 4.60.2 + '@rollup/rollup-win32-x64-msvc': 4.60.2 + fsevents: 2.3.3 + router@2.2.0: dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -23930,6 +24782,14 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -23947,7 +24807,7 @@ snapshots: safer-buffer@2.1.2: {} - sass@1.98.0: + sass@1.99.0: dependencies: chokidar: 4.0.3 immutable: 5.1.5 @@ -24015,9 +24875,7 @@ snapshots: seq-queue@0.0.5: {} - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + serialize-javascript@7.0.3: {} serve-static@2.2.1: dependencies: @@ -24363,10 +25221,10 @@ snapshots: string.prototype.matchall@4.0.12: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.1 + es-abstract: 1.24.2 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -24447,18 +25305,18 @@ snapshots: style-mod@4.1.3: {} - stylehacks@7.0.8(postcss@8.5.8): + stylehacks@7.0.8(postcss@8.5.10): dependencies: - browserslist: 4.28.1 - postcss: 8.5.8 + browserslist: 4.28.2 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 optional: true - subscriptions-transport-ws@0.11.0(graphql@16.13.1): + subscriptions-transport-ws@0.11.0(graphql@16.13.2): dependencies: backo2: 1.0.2 eventemitter3: 3.1.2 - graphql: 16.13.1 + graphql: 16.13.2 iterall: 1.3.0 symbol-observable: 1.2.0 ws: 7.5.10 @@ -24486,7 +25344,7 @@ snapshots: formidable: 3.5.4 methods: 1.1.2 mime: 2.6.0 - qs: 6.15.0 + qs: 6.15.1 transitivePeerDependencies: - supports-color @@ -24539,7 +25397,7 @@ snapshots: transitivePeerDependencies: - openapi-types - swagger-ui-dist@5.31.0: + swagger-ui-dist@5.32.4: dependencies: '@scarf/scarf': 1.4.0 @@ -24597,18 +25455,18 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.8 - postcss-import: 15.1.0(postcss@8.5.8) - postcss-js: 4.1.0(postcss@8.5.8) - postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) - postcss-nested: 6.2.0(postcss@8.5.8) + postcss: 8.5.10 + postcss-import: 15.1.0(postcss@8.5.10) + postcss-js: 4.1.0(postcss@8.5.10) + postcss-load-config: 4.0.2(postcss@8.5.10)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + postcss-nested: 6.2.0(postcss@8.5.10) postcss-selector-parser: 6.1.2 resolve: 1.22.11 sucrase: 3.35.1 transitivePeerDependencies: - ts-node - tailwindcss@3.4.16(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)): + tailwindcss@3.4.16(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -24624,11 +25482,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.8 - postcss-import: 15.1.0(postcss@8.5.8) - postcss-js: 4.1.0(postcss@8.5.8) - postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) - postcss-nested: 6.2.0(postcss@8.5.8) + postcss: 8.5.10 + postcss-import: 15.1.0(postcss@8.5.10) + postcss-js: 4.1.0(postcss@8.5.10) + postcss-load-config: 4.0.2(postcss@8.5.10)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) + postcss-nested: 6.2.0(postcss@8.5.10) postcss-selector-parser: 6.1.2 resolve: 1.22.11 sucrase: 3.35.1 @@ -24658,13 +25516,13 @@ snapshots: minimatch: 3.1.5 resolve-from: 2.0.0 - terser-webpack-plugin@5.4.0(webpack@5.104.1): + terser-webpack-plugin@5.4.0(webpack@5.106.0): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.46.1 - webpack: 5.104.1 + webpack: 5.106.0 terser@5.46.1: dependencies: @@ -24703,11 +25561,18 @@ snapshots: tinyexec@1.0.4: {} + tinyexec@1.1.1: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinyrainbow@3.1.0: {} tippy.js@6.3.7: @@ -24780,12 +25645,12 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)) + jest: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -24800,7 +25665,7 @@ snapshots: babel-jest: 30.3.0(@babel/core@7.29.0) jest-util: 30.3.0 - ts-loader@9.5.4(typescript@5.9.3)(webpack@5.104.1): + ts-loader@9.5.7(typescript@5.9.3)(webpack@5.106.0): dependencies: chalk: 4.1.2 enhanced-resolve: 5.20.1 @@ -24808,11 +25673,11 @@ snapshots: semver: 7.7.4 source-map: 0.7.6 typescript: 5.9.3 - webpack: 5.104.1 + webpack: 5.106.0 ts-log@2.2.7: {} - ts-node-dev@2.0.0(@types/node@25.5.0)(typescript@5.9.3): + ts-node-dev@2.0.0(@types/node@25.6.0)(typescript@5.9.3): dependencies: chokidar: 3.6.0 dynamic-dedupe: 0.3.0 @@ -24822,7 +25687,7 @@ snapshots: rimraf: 2.7.1 source-map-support: 0.5.21 tree-kill: 1.2.2 - ts-node: 10.9.2(@types/node@25.5.0)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) tsconfig: 7.0.0 typescript: 5.9.3 transitivePeerDependencies: @@ -24849,14 +25714,14 @@ snapshots: yn: 3.1.1 optional: true - ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3): + ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 25.5.0 + '@types/node': 25.6.0 acorn: 8.16.0 acorn-walk: 8.3.5 arg: 4.1.3 @@ -24889,11 +25754,9 @@ snapshots: tslib@2.4.1: {} - tslib@2.6.3: {} - tslib@2.8.1: {} - tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3): + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.10)(typescript@5.9.3)(yaml@2.8.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.4) cac: 6.7.14 @@ -24904,7 +25767,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.3) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.10)(yaml@2.8.3) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 @@ -24913,7 +25776,7 @@ snapshots: tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.5.8 + postcss: 8.5.10 typescript: 5.9.3 transitivePeerDependencies: - jiti @@ -25005,10 +25868,6 @@ snapshots: uglify-js@3.19.3: optional: true - uid-safe@2.1.5: - dependencies: - random-bytes: 1.0.0 - uid2@0.0.4: {} uid@2.0.2: @@ -25028,7 +25887,7 @@ snapshots: undici-types@7.16.0: {} - undici-types@7.18.2: {} + undici-types@7.19.2: {} unhead@2.1.12: dependencies: @@ -25059,7 +25918,7 @@ snapshots: union@0.5.0: dependencies: - qs: 6.15.0 + qs: 6.15.1 unique-string@2.0.0: dependencies: @@ -25073,19 +25932,19 @@ snapshots: unpipe@1.0.0: {} - unplugin-fonts@1.4.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + unplugin-fonts@1.4.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: fast-glob: 3.3.3 unplugin: 2.3.5 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - unplugin-fonts@1.4.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + unplugin-fonts@1.4.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: fast-glob: 3.3.3 unplugin: 2.3.5 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - unplugin-icons@22.5.0(@vue/compiler-sfc@3.5.31)(svelte@3.59.2)(vue-template-compiler@2.7.16): + unplugin-icons@22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16): dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/utils': 3.1.0 @@ -25093,7 +25952,7 @@ snapshots: local-pkg: 1.1.2 unplugin: 2.3.11 optionalDependencies: - '@vue/compiler-sfc': 3.5.31 + '@vue/compiler-sfc': 3.5.33 svelte: 3.59.2 vue-template-compiler: 2.7.16 transitivePeerDependencies: @@ -25104,7 +25963,7 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.4 - unplugin-vue-components@30.0.0(@babel/parser@7.29.2)(vue@3.5.31(typescript@5.9.3)): + unplugin-vue-components@30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)): dependencies: chokidar: 4.0.3 debug: 4.4.3(supports-color@8.1.1) @@ -25114,7 +25973,7 @@ snapshots: tinyglobby: 0.2.15 unplugin: 2.3.11 unplugin-utils: 0.3.1 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) optionalDependencies: '@babel/parser': 7.29.2 transitivePeerDependencies: @@ -25170,6 +26029,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + upper-case-first@2.0.2: dependencies: tslib: 2.8.1 @@ -25189,7 +26054,7 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.15.0 + qs: 6.15.1 urlpattern-polyfill@10.1.0: {} @@ -25250,17 +26115,17 @@ snapshots: dependencies: zod: 3.25.32 - vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-dev-rpc@1.1.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: birpc: 2.9.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vite-hot-client: 2.1.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) - vite-hot-client@2.1.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-hot-client@2.1.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-checker@0.12.0(eslint@9.39.2(jiti@2.6.1))(meow@13.2.0)(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-tsc@1.8.8(typescript@5.9.3)): + vite-plugin-checker@0.12.0(eslint@9.39.2(jiti@2.6.1))(meow@13.2.0)(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-tsc@1.8.8(typescript@5.9.3)): dependencies: '@babel/code-frame': 7.29.0 chokidar: 4.0.3 @@ -25269,7 +26134,7 @@ snapshots: picomatch: 4.0.4 tiny-invariant: 1.3.3 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vscode-uri: 3.1.0 optionalDependencies: eslint: 9.39.2(jiti@2.6.1) @@ -25278,57 +26143,57 @@ snapshots: typescript: 5.9.3 vue-tsc: 1.8.8(typescript@5.9.3) - vite-plugin-eslint@1.8.1(eslint@10.0.3(jiti@2.6.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-eslint@1.8.1(eslint@10.2.1(jiti@2.6.1))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.12 - eslint: 10.0.3(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) rollup: 2.80.0 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-eslint@1.8.1(eslint@10.0.3(jiti@2.6.1))(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-eslint@1.8.1(eslint@10.2.1(jiti@2.6.1))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.12 - eslint: 10.0.3(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) rollup: 2.80.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-eslint@1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-eslint@1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.12 eslint: 9.39.2(jiti@2.6.1) rollup: 2.80.0 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-eslint@1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-eslint@1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.12 eslint: 9.39.2(jiti@2.6.1) rollup: 2.80.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-fonts@0.7.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-fonts@0.7.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: fast-glob: 3.3.3 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-fonts@0.7.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-fonts@0.7.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: fast-glob: 3.3.3 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-html-config@2.0.2(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-html-config@2.0.2(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-html-config@2.0.2(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-html-config@2.0.2(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-inspect@11.3.3(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: ansis: 4.2.0 debug: 4.4.3(supports-color@8.1.1) @@ -25338,8 +26203,8 @@ snapshots: perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.1 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) - vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vite-dev-rpc: 1.1.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) transitivePeerDependencies: - supports-color @@ -25348,7 +26213,7 @@ snapshots: sitemap: 8.0.3 xml-formatter: 3.7.0 - vite-plugin-pages@0.33.2(@vue/compiler-sfc@3.5.31)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3))): + vite-plugin-pages@0.33.2(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))): dependencies: '@types/debug': 4.1.13 debug: 4.4.3(supports-color@8.1.1) @@ -25359,15 +26224,15 @@ snapshots: micromatch: 4.0.8 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) yaml: 2.8.3 optionalDependencies: - '@vue/compiler-sfc': 3.5.31 - vue-router: 4.6.4(vue@3.5.31(typescript@5.9.3)) + '@vue/compiler-sfc': 3.5.33 + vue-router: 4.6.4(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - supports-color - vite-plugin-pages@0.33.3(@vue/compiler-sfc@3.5.31)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3))): + vite-plugin-pages@0.33.3(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))): dependencies: '@types/debug': 4.1.13 debug: 4.4.3(supports-color@8.1.1) @@ -25378,15 +26243,15 @@ snapshots: micromatch: 4.0.8 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) yaml: 2.8.3 optionalDependencies: - '@vue/compiler-sfc': 3.5.31 - vue-router: 4.6.4(vue@3.5.31(typescript@5.9.3)) + '@vue/compiler-sfc': 3.5.33 + vue-router: 4.6.4(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - supports-color - vite-plugin-pages@0.33.3(@vue/compiler-sfc@3.5.31)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3))): + vite-plugin-pages@0.33.3(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))): dependencies: '@types/debug': 4.1.13 debug: 4.4.3(supports-color@8.1.1) @@ -25397,137 +26262,137 @@ snapshots: micromatch: 4.0.8 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) yaml: 2.8.3 optionalDependencies: - '@vue/compiler-sfc': 3.5.31 - vue-router: 4.6.4(vue@3.5.31(typescript@5.9.3)) + '@vue/compiler-sfc': 3.5.33 + vue-router: 4.6.4(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - supports-color - vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): + vite-plugin-pwa@1.2.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): dependencies: debug: 4.4.3(supports-color@8.1.1) pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) workbox-build: 7.4.0(@types/babel__core@7.20.5) workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): + vite-plugin-pwa@1.2.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): dependencies: debug: 4.4.3(supports-color@8.1.1) pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) workbox-build: 7.4.0(@types/babel__core@7.20.5) workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vite-plugin-static-copy@3.3.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vite-plugin-static-copy@3.3.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: chokidar: 3.6.0 p-map: 7.0.4 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-vue-layouts@0.11.0(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)): + vite-plugin-vue-layouts@0.11.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)): dependencies: debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) - vue: 3.5.31(typescript@5.9.3) - vue-router: 4.6.4(vue@3.5.31(typescript@5.9.3)) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue: 3.5.33(typescript@5.9.3) + vue-router: 4.6.4(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - supports-color - vite-plugin-vue-layouts@0.11.0(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.31(typescript@5.9.3)))(vue@3.5.31(typescript@5.9.3)): + vite-plugin-vue-layouts@0.11.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)): dependencies: debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) - vue: 3.5.31(typescript@5.9.3) - vue-router: 4.6.4(vue@3.5.31(typescript@5.9.3)) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vue: 3.5.33(typescript@5.9.3) + vue-router: 4.6.4(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - supports-color - vite@3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1): + vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1): dependencies: esbuild: 0.15.18 - postcss: 8.5.8 + postcss: 8.5.10 resolve: 1.22.11 rollup: 2.80.0 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 fsevents: 2.3.3 - sass: 1.98.0 + sass: 1.99.0 terser: 5.46.1 - vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3): + vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3): dependencies: esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.8 + postcss: 8.5.10 rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.10.1 fsevents: 2.3.3 jiti: 2.6.1 - sass: 1.98.0 + sass: 1.99.0 terser: 5.46.1 yaml: 2.8.3 - vite@7.3.1(@types/node@24.9.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3): + vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3): dependencies: esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.8 + postcss: 8.5.10 rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.9.1 fsevents: 2.3.3 jiti: 2.6.1 - sass: 1.98.0 + sass: 1.99.0 terser: 5.46.1 yaml: 2.8.3 - vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3): + vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3): dependencies: esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.8 + postcss: 8.5.10 rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 fsevents: 2.3.3 jiti: 2.6.1 - sass: 1.98.0 + sass: 1.99.0 terser: 5.46.1 yaml: 2.8.3 - vitefu@0.2.5(vite@3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1)): + vitefu@0.2.5(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1)): optionalDependencies: - vite: 3.2.11(@types/node@25.5.0)(sass@1.98.0)(terser@5.46.1) + vite: 3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1) - vitest@4.1.2(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.0.1))(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vitest@4.1.5(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.2 - '@vitest/mocker': 4.1.2(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.2 - '@vitest/runner': 4.1.2 - '@vitest/snapshot': 4.1.2 - '@vitest/spy': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/expect': 4.1.5 + '@vitest/mocker': 4.1.5(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.5 + '@vitest/runner': 4.1.5 + '@vitest/snapshot': 4.1.5 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -25539,23 +26404,23 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.1 - jsdom: 27.4.0(@noble/hashes@2.0.1) + jsdom: 27.4.0(@noble/hashes@2.2.0) transitivePeerDependencies: - msw - vitest@4.1.2(@types/node@25.5.0)(jsdom@27.4.0(@noble/hashes@2.0.1))(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)): + vitest@4.1.5(@types/node@25.6.0)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.2 - '@vitest/mocker': 4.1.2(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.2 - '@vitest/runner': 4.1.2 - '@vitest/snapshot': 4.1.2 - '@vitest/spy': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/expect': 4.1.5 + '@vitest/mocker': 4.1.5(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.5 + '@vitest/runner': 4.1.5 + '@vitest/snapshot': 4.1.5 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -25567,11 +26432,11 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.5.0 - jsdom: 27.4.0(@noble/hashes@2.0.1) + '@types/node': 25.6.0 + jsdom: 27.4.0(@noble/hashes@2.2.0) transitivePeerDependencies: - msw @@ -25582,9 +26447,9 @@ snapshots: vscode-uri@3.1.0: {} - vue-demi@0.14.10(vue@3.5.31(typescript@5.9.3)): + vue-demi@0.14.10(vue@3.5.33(typescript@5.9.3)): dependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1)): dependencies: @@ -25598,43 +26463,43 @@ snapshots: transitivePeerDependencies: - supports-color - vue-i18n@11.3.0(vue@3.5.31(typescript@5.9.3)): + vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)): dependencies: - '@intlify/core-base': 11.3.0 - '@intlify/devtools-types': 11.3.0 - '@intlify/shared': 11.3.0 + '@intlify/core-base': 11.4.0 + '@intlify/devtools-types': 11.4.0 + '@intlify/shared': 11.4.0 '@vue/devtools-api': 6.6.4 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) - vue-json-pretty@2.6.0(vue@3.5.31(typescript@5.9.3)): + vue-json-pretty@2.6.0(vue@3.5.33(typescript@5.9.3)): dependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) - vue-pdf-embed@2.1.4(vue@3.5.31(typescript@5.9.3)): + vue-pdf-embed@2.1.4(vue@3.5.33(typescript@5.9.3)): dependencies: pdfjs-dist: 4.10.38 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) vue-promise-modals@0.1.0(typescript@5.9.3): dependencies: - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) transitivePeerDependencies: - typescript - vue-router@4.6.4(vue@3.5.31(typescript@5.9.3)): + vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)): dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) vue-template-compiler@2.7.16: dependencies: de-indent: 1.0.2 he: 1.2.0 - vue-tippy@6.7.1(vue@3.5.31(typescript@5.9.3)): + vue-tippy@6.7.1(vue@3.5.33(typescript@5.9.3)): dependencies: tippy.js: 6.3.7 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) vue-tsc@1.8.8(typescript@5.9.3): dependencies: @@ -25656,20 +26521,20 @@ snapshots: '@vue/language-core': 2.2.0(typescript@5.9.3) typescript: 5.9.3 - vue@3.5.31(typescript@5.9.3): + vue@3.5.33(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.31 - '@vue/compiler-sfc': 3.5.31 - '@vue/runtime-dom': 3.5.31 - '@vue/server-renderer': 3.5.31(vue@3.5.31(typescript@5.9.3)) - '@vue/shared': 3.5.31 + '@vue/compiler-dom': 3.5.33 + '@vue/compiler-sfc': 3.5.33 + '@vue/runtime-dom': 3.5.33 + '@vue/server-renderer': 3.5.33(vue@3.5.33(typescript@5.9.3)) + '@vue/shared': 3.5.33 optionalDependencies: typescript: 5.9.3 - vuedraggable-es@4.1.1(vue@3.5.31(typescript@5.9.3)): + vuedraggable-es@4.1.1(vue@3.5.33(typescript@5.9.3)): dependencies: sortablejs: 1.14.0 - vue: 3.5.31(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) w3c-keyname@2.2.8: {} @@ -25724,7 +26589,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.104.1: + webpack@5.106.0: dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -25748,7 +26613,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.2 - terser-webpack-plugin: 5.4.0(webpack@5.104.1) + terser-webpack-plugin: 5.4.0(webpack@5.106.0) watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: @@ -25861,7 +26726,7 @@ snapshots: workbox-build@7.4.0(@types/babel__core@7.20.5): dependencies: - '@apideck/better-ajv-errors': 0.3.6(ajv@8.18.0) + '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) '@babel/core': 7.29.0 '@babel/preset-env': 7.29.2(@babel/core@7.29.0) '@babel/runtime': 7.29.2 @@ -25870,12 +26735,12 @@ snapshots: '@rollup/plugin-replace': 2.4.2(rollup@2.80.0) '@rollup/plugin-terser': 0.4.4(rollup@2.80.0) '@surma/rollup-plugin-off-main-thread': 2.2.3 - ajv: 8.18.0 + ajv: 8.20.0 common-tags: 1.8.2 fast-json-stable-stringify: 2.1.0 fs-extra: 9.1.0 glob: 11.1.0 - lodash: 4.17.23 + lodash: 4.18.1 pretty-bytes: 5.6.0 rollup: 2.80.0 source-map: 0.8.0-beta.0 diff --git a/prod.Dockerfile b/prod.Dockerfile index 29691df428d..66ec5bcb787 100644 --- a/prod.Dockerfile +++ b/prod.Dockerfile @@ -1,18 +1,18 @@ # Base Go builder with Go lang installation # This stage is used to build both Caddy and the webapp server, # preventing vulnerable packages on the dependency chain -FROM alpine:3.23.3 AS go_builder +FROM alpine:3.23.4 AS go_builder RUN apk add --no-cache curl git openssh-client ARG TARGETARCH -ENV GOLANG_VERSION=1.26.1 +ENV GOLANG_VERSION=1.26.2 # Download Go tarball RUN case "${TARGETARCH}" in amd64) GOARCH=amd64 ;; arm64) GOARCH=arm64 ;; *) echo "Unsupported arch: ${TARGETARCH}" && exit 1 ;; esac && \ curl -fsSL "https://go.dev/dl/go${GOLANG_VERSION}.linux-${GOARCH}.tar.gz" -o go.tar.gz # Checksum verification of Go tarball RUN case "${TARGETARCH}" in \ - amd64) expected="031f088e5d955bab8657ede27ad4e3bc5b7c1ba281f05f245bcc304f327c987a" ;; \ - arm64) expected="a290581cfe4fe28ddd737dde3095f3dbeb7f2e4065cab4eae44dfc53b760c2f7" ;; \ + amd64) expected="990e6b4bbba816dc3ee129eaeaf4b42f17c2800b88a2166c265ac1a200262282" ;; \ + arm64) expected="c958a1fe1b361391db163a485e21f5f228142d6f8b584f6bef89b26f66dc5b23" ;; \ esac && \ actual=$(sha256sum go.tar.gz | cut -d' ' -f1) && \ [ "$actual" = "$expected" ] && \ @@ -39,10 +39,21 @@ RUN expected="40cb9dc5e0b005bba635e830ba2354450248831fca3b58f5c49892a4747d0e76" (echo "❌ Caddy Source Checksum failed!" && exit 1) WORKDIR /tmp/caddy-build RUN tar -xzf /tmp/caddy-build/src.tar.gz && \ - # Fix CVE: upgrade google.golang.org/grpc to 1.79.3 (CVSS 9.1) + # Fix CVE-2026-33186: upgrade google.golang.org/grpc to 1.79.3 (CRITICAL - gRPC-Go authorization bypass) go get google.golang.org/grpc@v1.79.3 && \ - # Fix CVE: upgrade github.com/smallstep/certificates to 0.30.0 (CVSS 10) + # Fix CVE-2026-30836 + CVE-2026-40097: upgrade github.com/smallstep/certificates to 0.30.0 (CRITICAL - unauthenticated cert issuance via SCEP) go get github.com/smallstep/certificates@v0.30.0 && \ + # Fix CVE-2026-33816 + GHSA-j88v-2chj-qfwx: upgrade github.com/jackc/pgx/v5 to 5.9.2 (CRITICAL - memory-safety + SQL injection) + go get github.com/jackc/pgx/v5@v5.9.2 && \ + # Fix CVE-2026-34986: upgrade go-jose v3 and v4 (HIGH - DoS via crafted JWE) + go get github.com/go-jose/go-jose/v3@v3.0.5 && \ + go get github.com/go-jose/go-jose/v4@v4.1.4 && \ + # Fix CVE-2026-39883: upgrade go.opentelemetry.io/otel/sdk to 1.43.0 (HIGH - PATH hijacking) + go get go.opentelemetry.io/otel/sdk@v1.43.0 && \ + # Fix CVE-2026-39882: upgrade OpenTelemetry OTLP exporters (MEDIUM) + go get go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp@v0.19.0 && \ + go get go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp@v1.43.0 && \ + go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.43.0 && \ # Clean up any existing vendor directory and regenerate with updated deps rm -rf vendor && \ go mod tidy && \ @@ -65,7 +76,7 @@ RUN CGO_ENABLED=0 GOOS=linux go build -o webapp-server . # Shared Node.js base with optimized NPM installation -FROM alpine:3.23.3 AS node_base +FROM alpine:3.23.4 AS node_base # Install dependencies RUN apk upgrade --no-cache && \ apk add --no-cache nodejs curl bash tini ca-certificates @@ -73,9 +84,9 @@ RUN apk upgrade --no-cache && \ RUN mkdir -p /tmp/npm-install WORKDIR /tmp/npm-install # Download NPM tarball -RUN curl -fsSL https://registry.npmjs.org/npm/-/npm-11.11.1.tgz -o npm.tgz +RUN curl -fsSL https://registry.npmjs.org/npm/-/npm-11.13.0.tgz -o npm.tgz # Verify checksum -RUN expected="a3b2dbeb2544809a75f186cbae27adc5ceb5adc1ee696e17dfed689d7f46fcf2" \ +RUN expected="a4ffa1de3bf1c7f9d5e3dd24fe2921970bdb1589d647f4083eaaaab3be974b7e" \ && actual=$(sha256sum npm.tgz | cut -d' ' -f1) \ && [ "$actual" = "$expected" ] \ && echo "✅ NPM Tarball Checksum OK" \ @@ -83,10 +94,10 @@ RUN expected="a3b2dbeb2544809a75f186cbae27adc5ceb5adc1ee696e17dfed689d7f46fcf2" # Install NPM from verified tarball and global packages RUN tar -xzf npm.tgz && \ cd package && \ - node bin/npm-cli.js install -g npm@11.11.1 && \ + node bin/npm-cli.js install -g npm@11.13.0 && \ cd / && \ rm -rf /tmp/npm-install -RUN npm install -g pnpm@10.32.1 @import-meta-env/cli@0.7.4 +RUN npm install -g pnpm@10.33.2 @import-meta-env/cli@0.7.4 # Fix CVE-2025-64756 by replacing vulnerable glob in @import-meta-env/cli (ships glob@11.0.2, fix requires >=11.1.0) RUN mkdir -p /tmp/glob-fix && \ @@ -104,16 +115,6 @@ RUN mkdir -p /tmp/serialize-fix && \ cp -r node_modules/serialize-javascript /usr/lib/node_modules/@import-meta-env/cli/node_modules/ && \ rm -rf /tmp/serialize-fix -# Fix CVE: upgrade picomatch in npm and pnpm (ships 4.0.3, fix requires >=4.0.4) -RUN mkdir -p /tmp/picomatch-fix && \ - cd /tmp/picomatch-fix && \ - npm install picomatch@4.0.4 && \ - rm -rf /usr/lib/node_modules/npm/node_modules/tinyglobby/node_modules/picomatch && \ - cp -r node_modules/picomatch /usr/lib/node_modules/npm/node_modules/tinyglobby/node_modules/ && \ - rm -rf /usr/lib/node_modules/pnpm/dist/node_modules/picomatch && \ - cp -r node_modules/picomatch /usr/lib/node_modules/pnpm/dist/node_modules/ && \ - rm -rf /tmp/picomatch-fix - FROM node_base AS base_builder