chore: security patch for the dependency chain v2025.11.0 (#5590)

Bump dependencies and account for breaking changes.

---------

Co-authored-by: James George <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
Mir Arif Hasan 2025-11-24 14:51:29 +06:00 committed by GitHub
parent b438e1d813
commit 904a1b0405
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
69 changed files with 6494 additions and 10531 deletions

View file

@ -13,10 +13,9 @@ jobs:
strategy:
matrix:
# Pinned to Node.js 22 to maintain compatibility with isolated-vm v5.x
# Node.js 24 requires isolated-vm v6+ due to V8 API changes
# TODO: Upgrade to isolated-vm v6 and support Node.js 24 in future dependency update cycle
node-version: ["22"]
# Pinned to Node.js 22 due to known test failures on Node.js 24.
# Future TODO: Investigate test failures and move to Node.js 24 (Active LTS).
node-version: [22]
steps:
- name: Checkout
@ -33,8 +32,14 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
run_install: true
version: 10
run_install: false
- name: Install dependencies
run: pnpm install
env:
DATABASE_URL: postgresql://postgres:testpass@localhost:5432/hoppscotch
DATA_ENCRYPTION_KEY: "12345678901234567890123456789012"
- name: Run tests
run: pnpm test

View file

@ -52,7 +52,7 @@ fs.rmSync("build.env")
const caddyFileName = process.env.ENABLE_SUBPATH_BASED_ACCESS === 'true' ? 'aio-subpath-access.Caddyfile' : 'aio-multiport-setup.Caddyfile'
const caddyProcess = runChildProcessWithPrefix("caddy", ["run", "--config", `/etc/caddy/${caddyFileName}`, "--adapter", "caddyfile"], "App/Admin Dashboard Caddy")
const backendProcess = runChildProcessWithPrefix("node", ["/dist/backend/dist/main.js"], "Backend Server")
const backendProcess = runChildProcessWithPrefix("node", ["/dist/backend/dist/src/main.js"], "Backend Server")
const webappProcess = runChildProcessWithPrefix("webapp-server", [], "Webapp Server")
caddyProcess.on("exit", (code) => {

View file

@ -5,7 +5,7 @@
"author": "Hoppscotch (support@hoppscotch.io)",
"private": true,
"license": "MIT",
"packageManager": "pnpm@10.18.3",
"packageManager": "pnpm@10.23.0",
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepare": "husky",
@ -27,11 +27,11 @@
"@commitlint/cli": "20.1.0",
"@commitlint/config-conventional": "20.0.0",
"@hoppscotch/ui": "0.2.5",
"@types/node": "24.9.1",
"@types/node": "24.10.1",
"cross-env": "10.1.0",
"http-server": "14.1.1",
"husky": "9.1.7",
"lint-staged": "16.2.5"
"lint-staged": "16.2.7"
},
"pnpm": {
"overrides": {
@ -39,6 +39,8 @@
"apiconnect-wsdl": "2.0.36",
"cross-spawn": "7.0.6",
"execa@0.10.0": "2.0.0",
"glob@<11.1.0": "11.1.0",
"hono@<4.10.3": "4.10.3",
"nodemailer@<7.0.7": "7.0.7",
"sha.js@2.4.11": "2.4.12",
"subscriptions-transport-ws>ws": "7.5.10",

View file

@ -24,8 +24,8 @@
"devDependencies": {
"@lezer/generator": "1.8.0",
"@rollup/plugin-typescript": "12.1.4",
"mocha": "11.7.4",
"rollup": "4.52.5",
"mocha": "11.7.5",
"rollup": "4.53.3",
"typescript": "5.9.3"
}
}

View file

@ -6,6 +6,8 @@
.env
# Prisma
src/generated/
# Logs
logs

View file

@ -3,7 +3,7 @@
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [{ "include": "mailer/templates/**/*", "outDir": "dist" }],
"assets": [{ "include": "mailer/templates/**/*", "outDir": "dist/src" }],
"watchAssets": true
}
}

View file

@ -14,7 +14,7 @@
"prebuild": "rimraf dist",
"build": "nest build",
"postbuild": "mkdir -p dist/mailer && cp -r src/mailer/templates dist/mailer/templates",
"generate-gql-sdl": "cross-env GQL_SCHEMA_EMIT_LOCATION='../../../gql-gen/backend-schema.gql' GENERATE_GQL_SCHEMA=true WHITELISTED_ORIGINS='' nest start",
"generate-gql-sdl": "cross-env GQL_SCHEMA_EMIT_LOCATION='../../../../gql-gen/backend-schema.gql' GENERATE_GQL_SCHEMA=true WHITELISTED_ORIGINS='' nest start",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
@ -30,76 +30,80 @@
"do-test": "pnpm run test"
},
"dependencies": {
"@apollo/server": "4.12.1",
"@apollo/server": "5.2.0",
"@as-integrations/express5": "1.1.2",
"@nestjs-modules/mailer": "2.0.2",
"@nestjs/apollo": "13.2.1",
"@nestjs/common": "11.1.6",
"@nestjs/common": "11.1.9",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/core": "11.1.9",
"@nestjs/graphql": "13.2.0",
"@nestjs/jwt": "11.0.1",
"@nestjs/passport": "11.0.0",
"@nestjs/platform-express": "11.1.6",
"@nestjs/platform-express": "11.1.9",
"@nestjs/schedule": "6.0.1",
"@nestjs/swagger": "11.2.1",
"@nestjs/swagger": "11.2.3",
"@nestjs/terminus": "11.0.0",
"@nestjs/throttler": "6.4.0",
"@prisma/client": "6.17.1",
"@prisma/adapter-pg": "7.0.0",
"@prisma/client": "7.0.0",
"argon2": "0.44.0",
"bcrypt": "6.0.0",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"cookie": "1.0.2",
"cookie-parser": "1.4.7",
"dotenv": "17.2.3",
"express": "5.1.0",
"express-session": "1.18.2",
"fp-ts": "2.16.11",
"graphql": "16.11.0",
"graphql": "16.12.0",
"graphql-query-complexity": "1.1.0",
"graphql-redis-subscriptions": "2.7.0",
"graphql-subscriptions": "3.0.0",
"handlebars": "4.7.8",
"io-ts": "2.2.22",
"morgan": "1.10.1",
"nodemailer": "7.0.9",
"nodemailer": "7.0.10",
"passport": "0.7.0",
"passport-github2": "0.1.12",
"passport-google-oauth20": "2.0.0",
"passport-jwt": "4.0.1",
"passport-local": "1.0.0",
"passport-microsoft": "2.1.0",
"posthog-node": "5.10.0",
"prisma": "6.17.1",
"pg": "8.16.3",
"posthog-node": "5.13.2",
"prisma": "7.0.0",
"reflect-metadata": "0.2.2",
"rimraf": "6.0.1",
"rimraf": "6.1.2",
"rxjs": "7.8.2"
},
"devDependencies": {
"@eslint/eslintrc": "3.3.1",
"@eslint/js": "9.37.0",
"@nestjs/cli": "11.0.10",
"@eslint/js": "9.39.1",
"@nestjs/cli": "11.0.12",
"@nestjs/schematics": "11.0.9",
"@nestjs/testing": "11.1.6",
"@nestjs/testing": "11.1.9",
"@relmify/jest-fp-ts": "2.1.1",
"@types/bcrypt": "6.0.0",
"@types/cookie-parser": "1.4.9",
"@types/express": "5.0.3",
"@types/cookie-parser": "1.4.10",
"@types/express": "5.0.5",
"@types/jest": "30.0.0",
"@types/node": "24.9.1",
"@types/nodemailer": "7.0.2",
"@types/node": "24.10.1",
"@types/nodemailer": "7.0.4",
"@types/passport-github2": "1.2.9",
"@types/passport-google-oauth20": "2.0.16",
"@types/passport-google-oauth20": "2.0.17",
"@types/passport-jwt": "4.0.1",
"@types/passport-microsoft": "2.1.0",
"@types/passport-microsoft": "2.1.1",
"@types/pg": "8.15.6",
"@types/supertest": "6.0.3",
"@typescript-eslint/eslint-plugin": "8.46.1",
"@typescript-eslint/parser": "8.46.1",
"@typescript-eslint/eslint-plugin": "8.47.0",
"@typescript-eslint/parser": "8.47.0",
"cross-env": "10.1.0",
"eslint": "9.37.0",
"eslint": "9.39.1",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-prettier": "5.5.4",
"globals": "16.4.0",
"globals": "16.5.0",
"jest": "30.2.0",
"jest-mock-extended": "4.0.0",
"prettier": "3.6.2",

View file

@ -0,0 +1,12 @@
import 'dotenv/config';
import { defineConfig, env } from 'prisma/config';
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
});

View file

@ -1,11 +1,10 @@
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "debian-openssl-1.1.x", "debian-openssl-3.0.x"]
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Team {

View file

@ -40,7 +40,7 @@ const caddyProcess = runChildProcessWithPrefix(
);
const backendProcess = runChildProcessWithPrefix(
'node',
['/dist/backend/dist/main.js'],
['/dist/backend/dist/src/main.js'],
'Backend Server',
);

View file

@ -7,7 +7,7 @@ import {
ACCESS_TOKEN_NOT_FOUND,
} from 'src/errors';
import { AuthUser } from 'src/types/AuthUser';
import { PersonalAccessToken } from '@prisma/client';
import { PersonalAccessToken } from 'src/generated/prisma/client';
import { AccessToken } from 'src/types/AccessToken';
import { HttpStatus } from '@nestjs/common';

View file

@ -10,7 +10,7 @@ import {
ACCESS_TOKEN_NOT_FOUND,
} from 'src/errors';
import { CreateAccessTokenResponse } from './helper';
import { PersonalAccessToken } from '@prisma/client';
import { PersonalAccessToken } from 'src/generated/prisma/client';
import { AccessToken } from 'src/types/AccessToken';
@Injectable()

View file

@ -1,7 +1,7 @@
import { AdminService } from './admin.service';
import { PubSubService } from '../pubsub/pubsub.service';
import { mockDeep } from 'jest-mock-extended';
import { InvitedUsers, User as DbUser } from '@prisma/client';
import { InvitedUsers, User as DbUser } from 'src/generated/prisma/client';
import { UserService } from '../user/user.service';
import { TeamService } from '../team/team.service';
import { TeamEnvironmentsService } from '../team-environments/team-environments.service';

View file

@ -1,6 +1,6 @@
import { HttpStatus } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Account, VerificationToken } from '@prisma/client';
import { Account, VerificationToken } from 'src/generated/prisma/client';
import { mockDeep } from 'jest-mock-extended';
import {
INVALID_EMAIL,

View file

@ -25,7 +25,7 @@ import {
import { JwtService } from '@nestjs/jwt';
import { RESTError } from 'src/types/RESTError';
import { AuthUser, IsAdmin } from 'src/types/AuthUser';
import { VerificationToken } from '@prisma/client';
import { VerificationToken } from 'src/generated/prisma/client';
import { Origin } from './helper';
import { ConfigService } from '@nestjs/config';
import { InfraConfigService } from 'src/infra-config/infra-config.service';

View file

@ -34,7 +34,8 @@ export const JSON_INVALID = 'json_invalid' as const;
* Auth Provider not specified
* (Auth)
*/
export const AUTH_PROVIDER_NOT_SPECIFIED = 'auth/provider_not_specified' as const;
export const AUTH_PROVIDER_NOT_SPECIFIED =
'auth/provider_not_specified' as const;
/**
* Email not provided by OAuth provider

View file

@ -9,7 +9,7 @@ import {
} from 'src/errors';
import { ConfigService } from '@nestjs/config';
import * as helper from './helper';
import { InfraConfig as dbInfraConfig } from '@prisma/client';
import { InfraConfig as dbInfraConfig } from 'src/generated/prisma/client';
import { InfraConfig } from './infra-config.model';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { ServiceStatus } from './helper';

View file

@ -1,7 +1,7 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { InfraConfig } from './infra-config.model';
import { PrismaService } from 'src/prisma/prisma.service';
import { InfraConfig as DBInfraConfig } from '@prisma/client';
import { InfraConfig as DBInfraConfig } from 'src/generated/prisma/client';
import * as E from 'fp-ts/Either';
import { InfraConfigEnum } from 'src/types/InfraConfig';
import {

View file

@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import { InfraToken as dbInfraToken } from '@prisma/client';
import { InfraToken as dbInfraToken } from 'src/generated/prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateInfraTokenResponse, InfraToken } from './infra-token.model';
import { calculateExpirationDate, isValidLength } from 'src/utils';

View file

@ -1,18 +1,21 @@
import { NestFactory } from '@nestjs/core';
import { json } from 'express';
import { AppModule } from './app.module';
import * as cookieParser from 'cookie-parser';
import cookieParser from 'cookie-parser';
import { ValidationPipe, VersioningType } from '@nestjs/common';
import * as session from 'express-session';
import session from 'express-session';
import { emitGQLSchemaFile } from './gql-schema';
import * as crypto from 'crypto';
import * as morgan from 'morgan';
import morgan from 'morgan';
import { ConfigService } from '@nestjs/config';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { InfraTokenModule } from './infra-token/infra-token.module';
import { NestExpressApplication } from '@nestjs/platform-express';
function setupSwagger(app: NestExpressApplication, isProduction: boolean): void {
function setupSwagger(
app: NestExpressApplication,
isProduction: boolean,
): void {
const swaggerDocPath = '/api-docs';
const config = new DocumentBuilder()
@ -57,6 +60,8 @@ async function bootstrap() {
secret:
configService.get<string>('INFRA.SESSION_SECRET') ||
crypto.randomBytes(16).toString('hex'),
resave: false,
saveUninitialized: false,
}),
);

View file

@ -11,7 +11,7 @@ import { MockServerService } from './mock-server.service';
import * as E from 'fp-ts/Either';
import { AccessTokenService } from 'src/access-token/access-token.service';
import { TeamService } from 'src/team/team.service';
import { WorkspaceType } from '@prisma/client';
import { WorkspaceType } from 'src/generated/prisma/client';
/**
* Guard to extract and validate mock server ID from either:
@ -47,7 +47,7 @@ export class MockRequestGuard implements CanActivate {
if (E.isLeft(mockServerResult)) {
console.warn(
`Mock server lookup failed for subdomain: ${String(mockServerSubdomain).replace(/\r|\n/g, "")}, error: ${mockServerResult.left}`,
`Mock server lookup failed for subdomain: ${String(mockServerSubdomain).replace(/\r|\n/g, '')}, error: ${mockServerResult.left}`,
);
throw new NotFoundException(
`Mock server '${mockServerSubdomain}' not found`,

View file

@ -1,6 +1,9 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { MockServer as dbMockServer, MockServerAction } from '@prisma/client';
import {
MockServer as dbMockServer,
MockServerAction,
} from 'src/generated/prisma/client';
@Injectable()
export class MockServerAnalyticsService {

View file

@ -7,7 +7,7 @@ import {
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Request, Response } from 'express';
import { MockServer } from '@prisma/client';
import { MockServer } from 'src/generated/prisma/client';
import { MockServerService } from './mock-server.service';
@Injectable()

View file

@ -12,7 +12,7 @@ import { MockServerService } from './mock-server.service';
import { MockServerLoggingInterceptor } from './mock-server-logging.interceptor';
import * as E from 'fp-ts/Either';
import { MockRequestGuard } from './mock-request.guard';
import { MockServer } from '@prisma/client';
import { MockServer } from 'src/generated/prisma/client';
import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.guard';
/**

View file

@ -17,7 +17,7 @@ import {
UserCollection,
TeamCollection,
UserRequest,
} from '@prisma/client';
} from 'src/generated/prisma/client';
import { WorkspaceType } from '../types/WorkspaceTypes';
import { User } from '../user/user.model';
import {

View file

@ -26,7 +26,7 @@ import {
MockServerAction,
TeamAccessRole,
MockServer as dbMockServer,
} from '@prisma/client';
} from 'src/generated/prisma/client';
import { OffsetPaginationArgs } from 'src/types/input-types.args';
import { ConfigService } from '@nestjs/config';
import { MockServerAnalyticsService } from './mock-server-analytics.service';

View file

@ -1,18 +1,30 @@
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient, Prisma } from '@prisma/client';
import { PrismaClient, Prisma } from 'src/generated/prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import pg from 'pg';
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
private pool: pg.Pool;
constructor() {
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
});
const adapter = new PrismaPg(pool);
super({
adapter,
transactionOptions: {
maxWait: 5000, // 5 seconds
timeout: 10000, // 10 seconds
},
});
this.pool = pool;
}
async onModuleInit() {
await this.$connect();
@ -20,6 +32,7 @@ export class PrismaService
async onModuleDestroy() {
await this.$disconnect();
await this.pool.end();
}
/**

View file

@ -11,7 +11,7 @@ import {
} from 'src/errors';
import { UserDataHandler } from 'src/user/user.data.handler';
import { Shortcode, ShortcodeWithUserEmail } from './shortcode.model';
import { Shortcode as DBShortCode } from '@prisma/client';
import { Shortcode as DBShortCode } from 'src/generated/prisma/client';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { UserService } from 'src/user/user.service';
import { stringToJson } from 'src/utils';

View file

@ -1,4 +1,4 @@
import { TeamRequest } from '@prisma/client';
import { TeamRequest } from 'src/generated/prisma/client';
// Type of data returned from the query to obtain all search results
export type SearchQueryReturnType = {

View file

@ -11,7 +11,7 @@ import * as E from 'fp-ts/Either';
import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.guard';
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { RequiresTeamRole } from 'src/team/decorators/requires-team-role.decorator';
import { TeamAccessRole } from '@prisma/client';
import { TeamAccessRole } from 'src/generated/prisma/client';
import { RESTTeamMemberGuard } from 'src/team/guards/rest-team-member.guard';
import { throwHTTPErr } from 'src/utils';
import { RESTError } from 'src/types/RESTError';

View file

@ -1,4 +1,7 @@
import { Team, TeamCollection as DBTeamCollection } from '@prisma/client';
import {
Team,
TeamCollection as DBTeamCollection,
} from 'src/generated/prisma/client';
import { mockDeep, mockReset } from 'jest-mock-extended';
import {
TEAM_COLL_DATA_INVALID,

View file

@ -35,7 +35,7 @@ import {
Prisma,
TeamCollection as DBTeamCollection,
TeamRequest,
} from '@prisma/client';
} from 'src/generated/prisma/client';
import { CollectionFolder } from 'src/types/CollectionFolder';
import { CollectionSearchNode } from 'src/types/CollectionSearchNode';
import {

View file

@ -11,7 +11,7 @@ import {
import { TeamService } from 'src/team/team.service';
import { GqlExecutionContext } from '@nestjs/graphql';
import * as E from 'fp-ts/Either';
import { TeamAccessRole } from '@prisma/client';
import { TeamAccessRole } from 'src/generated/prisma/client';
import { throwErr } from 'src/utils';
/**

View file

@ -1,5 +1,8 @@
import { Injectable } from '@nestjs/common';
import { TeamEnvironment as DBTeamEnvironment, Prisma } from '@prisma/client';
import {
TeamEnvironment as DBTeamEnvironment,
Prisma,
} from 'src/generated/prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { TeamEnvironment } from './team-environments.model';

View file

@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
import * as O from 'fp-ts/Option';
import * as E from 'fp-ts/Either';
import { PrismaService } from 'src/prisma/prisma.service';
import { TeamInvitation as DBTeamInvitation } from '@prisma/client';
import { TeamInvitation as DBTeamInvitation } from 'src/generated/prisma/client';
import { TeamMember, TeamAccessRole } from 'src/team/team.model';
import { TeamService } from 'src/team/team.service';
import {

View file

@ -18,7 +18,7 @@ import {
TeamRequest as DbTeamRequest,
Team as DbTeam,
TeamCollection as DbTeamCollection,
} from '@prisma/client';
} from 'src/generated/prisma/client';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { SortOptions } from 'src/types/SortOptions';

View file

@ -15,7 +15,10 @@ import { PubSubService } from 'src/pubsub/pubsub.service';
import { stringToJson } from 'src/utils';
import * as E from 'fp-ts/Either';
import * as O from 'fp-ts/Option';
import { Prisma, TeamRequest as DbTeamRequest } from '@prisma/client';
import {
Prisma,
TeamRequest as DbTeamRequest,
} from 'src/generated/prisma/client';
import { SortOptions } from 'src/types/SortOptions';
@Injectable()

View file

@ -1,4 +1,4 @@
import { TeamAccessRole } from '@prisma/client';
import { TeamAccessRole } from 'src/generated/prisma/client';
import { SetMetadata } from '@nestjs/common';
export const RequiresTeamRole = (...roles: TeamAccessRole[]) =>

View file

@ -1,7 +1,7 @@
import { TeamService } from './team.service';
import { PrismaService } from '../prisma/prisma.service';
import { Team, TeamMember, TeamAccessRole } from './team.model';
import { TeamMember as DbTeamMember } from '@prisma/client';
import { TeamMember as DbTeamMember } from 'src/generated/prisma/client';
import {
USER_NOT_FOUND,
TEAM_INVALID_ID,

View file

@ -1,7 +1,7 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { TeamMember, TeamAccessRole, Team } from './team.model';
import { PrismaService } from '../prisma/prisma.service';
import { TeamMember as DbTeamMember } from '@prisma/client';
import { TeamMember as DbTeamMember } from 'src/generated/prisma/client';
import { UserService } from '../user/user.service';
import { UserDataHandler } from 'src/user/user.data.handler';
import {

View file

@ -1,4 +1,4 @@
import { User } from '@prisma/client';
import { User } from 'src/generated/prisma/client';
export type AuthUser = User;

View file

@ -1,4 +1,4 @@
import { UserCollection as DBUserCollection } from '@prisma/client';
import { UserCollection as DBUserCollection } from 'src/generated/prisma/client';
import { mockDeep, mockReset } from 'jest-mock-extended';
import {
USER_COLL_DEST_SAME,

View file

@ -20,7 +20,11 @@ import { AuthUser } from 'src/types/AuthUser';
import * as E from 'fp-ts/Either';
import * as O from 'fp-ts/Option';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { Prisma, UserCollection, ReqType as DBReqType } from '@prisma/client';
import {
Prisma,
UserCollection,
ReqType as DBReqType,
} from 'src/generated/prisma/client';
import {
UserCollection as UserCollectionModel,
UserCollectionExportJSONData,

View file

@ -1,7 +1,7 @@
import {
ReqType as DbRequestType,
UserRequest as DbUserRequest,
} from '@prisma/client';
} from 'src/generated/prisma/client';
import { mockDeep, mockReset } from 'jest-mock-extended';
import {
JSON_INVALID,

View file

@ -3,7 +3,10 @@ import { PrismaService } from '../prisma/prisma.service';
import { PubSubService } from '../pubsub/pubsub.service';
import * as E from 'fp-ts/Either';
import { UserRequest } from './user-request.model';
import { Prisma, UserRequest as DbUserRequest } from '@prisma/client';
import {
Prisma,
UserRequest as DbUserRequest,
} from 'src/generated/prisma/client';
import {
USER_COLLECTION_NOT_FOUND,
USER_REQUEST_CREATION_FAILED,

View file

@ -4,7 +4,7 @@ import { PubSubService } from 'src/pubsub/pubsub.service';
import { User } from 'src/user/user.model';
import * as E from 'fp-ts/Either';
import { stringToJson } from 'src/utils';
import { UserSettings as DbUserSettings } from '@prisma/client';
import { UserSettings as DbUserSettings } from 'src/generated/prisma/client';
import { UserSettings } from './user-settings.model';
import {
USER_SETTINGS_ALREADY_EXISTS,

View file

@ -18,7 +18,7 @@ import { SessionType, User } from './user.model';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { encrypt, stringToJson, taskEitherValidateArraySeq } from 'src/utils';
import { UserDataHandler } from './user.data.handler';
import { User as DbUser } from '@prisma/client';
import { User as DbUser } from 'src/generated/prisma/client';
import { OffsetPaginationArgs } from 'src/types/input-types.args';
import { GetUserWorkspacesResponse } from 'src/infra-token/request-response.dto';
import { TeamAccessRole } from 'src/team/team.model';

View file

@ -1,7 +1,7 @@
import { ExecutionContext, HttpException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { GqlExecutionContext } from '@nestjs/graphql';
import { Prisma } from '@prisma/client';
import { Prisma } from 'src/generated/prisma/client';
import * as A from 'fp-ts/Array';
import * as E from 'fp-ts/Either';
import { pipe } from 'fp-ts/lib/function';

View file

@ -6,7 +6,7 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"target": "ES2023",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
@ -18,5 +18,7 @@
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"moduleResolution": "node"
}
}

View file

@ -16,17 +16,17 @@ const packageJsonPath = fileURLToPath(
);
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
const requiredNodeVersionRange = packageJson.engines?.node || ">=20";
const requiredNodeVersionRange = packageJson.engines?.node || ">=22";
// Extract the major version from the start of the range
const requiredNodeVersion = semver.major(
semver.minVersion(requiredNodeVersionRange) ?? "20"
semver.minVersion(requiredNodeVersionRange) ?? "22"
);
const currentNodeVersion = process.versions.node;
// Last supported version of the CLI for Node.js v18
const lastSupportedVersion = "0.11.1";
// Last supported version of the CLI for Node.js v20
const lastSupportedVersion = "0.26.0";
if (!semver.satisfies(currentNodeVersion, requiredNodeVersionRange)) {
console.error(
@ -34,8 +34,8 @@ if (!semver.satisfies(currentNodeVersion, requiredNodeVersionRange)) {
);
console.error(
`\nIf you prefer staying on Node.js ${highlightVersion("18")}, you can install the last supported version of the CLI:\n` +
`${chalk.green(`npm install -g @hoppscotch/cli@${lastSupportedVersion}`)}`
`\nIf you prefer staying on Node.js ${highlightVersion("20")}, you can install the last supported version of the CLI:\n` +
`${chalk.green(`npm install -g @hoppscotch/cli@${lastSupportedVersion}`)} alongside ${highlightVersion("2025.10.1")} of the Hoppscotch app.\n`
);
process.exit(1);
}

View file

@ -12,7 +12,7 @@
"access": "public"
},
"engines": {
"node": ">=20"
"node": ">=22"
},
"scripts": {
"build": "pnpm exec tsup",
@ -42,16 +42,16 @@
"private": false,
"dependencies": {
"aws4fetch": "1.0.20",
"axios": "1.12.2",
"axios": "1.13.2",
"chalk": "5.6.2",
"commander": "14.0.1",
"isolated-vm": "5.0.4",
"commander": "14.0.2",
"isolated-vm": "6.0.2",
"js-md5": "0.8.3",
"lodash-es": "4.17.21",
"papaparse": "5.5.3",
"qs": "6.14.0",
"verzod": "0.4.0",
"xmlbuilder2": "3.1.1",
"xmlbuilder2": "4.0.0",
"zod": "3.25.32"
},
"devDependencies": {
@ -59,14 +59,14 @@
"@hoppscotch/js-sandbox": "workspace:^",
"@relmify/jest-fp-ts": "2.1.1",
"@types/lodash-es": "4.17.12",
"@types/papaparse": "5.3.16",
"@types/papaparse": "5.5.0",
"@types/qs": "6.14.0",
"fp-ts": "2.16.11",
"prettier": "3.6.2",
"qs": "6.11.2",
"semver": "7.7.3",
"tsup": "8.5.0",
"tsup": "8.5.1",
"typescript": "5.9.3",
"vitest": "3.2.4"
"vitest": "4.0.12"
}
}

View file

@ -356,9 +356,9 @@ describe("getters", () => {
})
);
vi.spyOn(mutators, "readJsonFile").mockImplementation(() =>
Promise.resolve(sampleCollectionContents)
);
const readJsonFileSpy = vi
.spyOn(mutators, "readJsonFile")
.mockImplementation(() => Promise.resolve(sampleCollectionContents));
vi.spyOn(
workspaceAccessHelpers,
@ -370,6 +370,9 @@ describe("getters", () => {
const accessToken = "valid-access-token";
const serverUrl = "valid-url";
// Clear spy calls from setup
readJsonFileSpy.mockClear();
await getResourceContents({
pathOrId,
accessToken,
@ -389,7 +392,7 @@ describe("getters", () => {
expect(
workspaceAccessHelpers.transformWorkspaceCollections
).toBeCalled();
expect(mutators.readJsonFile).not.toHaveBeenCalled();
expect(readJsonFileSpy).not.toHaveBeenCalled();
});
});
});

View file

@ -11,7 +11,7 @@
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"composite": true,
"lib": ["ESNext", "DOM"],
"lib": ["ESNext", "DOM"]
},
"files": ["package.json"]
}

View file

@ -22,18 +22,18 @@
},
"dependencies": {
"@apidevtools/swagger-parser": "12.1.0",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/commands": "6.8.1",
"@codemirror/autocomplete": "6.20.0",
"@codemirror/commands": "6.10.0",
"@codemirror/lang-javascript": "6.2.4",
"@codemirror/lang-json": "6.0.2",
"@codemirror/lang-xml": "6.1.0",
"@codemirror/language": "6.11.3",
"@codemirror/legacy-modes": "6.5.1",
"@codemirror/lint": "6.8.5",
"@codemirror/merge": "6.10.2",
"@codemirror/legacy-modes": "6.5.2",
"@codemirror/lint": "6.9.2",
"@codemirror/merge": "6.11.2",
"@codemirror/search": "6.5.11",
"@codemirror/state": "6.5.2",
"@codemirror/view": "6.38.1",
"@codemirror/view": "6.38.8",
"@guolao/vue-monaco-editor": "1.6.0",
"@hoppscotch/codemirror-lang-graphql": "workspace:^",
"@hoppscotch/data": "workspace:^",
@ -44,21 +44,22 @@
"@hoppscotch/ui": "0.2.5",
"@hoppscotch/vue-toasted": "0.1.0",
"@lezer/highlight": "1.2.1",
"@noble/curves": "1.9.7",
"@scure/base": "1.2.6",
"@noble/curves": "2.0.1",
"@scure/base": "2.0.0",
"@shopify/lang-jsonc": "1.0.1",
"@tauri-apps/api": "2.1.1",
"@tauri-apps/plugin-store": "2.2.0",
"@types/hawk": "9.0.6",
"@types/hawk": "9.0.7",
"@types/markdown-it": "14.1.2",
"@types/node": "24.10.1",
"@unhead/vue": "2.0.19",
"@urql/core": "6.0.1",
"@urql/devtools": "2.0.3",
"@urql/exchange-auth": "3.0.0",
"@vueuse/core": "13.7.0",
"@vueuse/core": "14.0.0",
"acorn-walk": "8.3.4",
"aws4fetch": "1.0.20",
"axios": "1.12.2",
"axios": "1.13.2",
"buffer": "6.0.3",
"cookie-es": "2.0.0",
"dioc": "3.0.2",
@ -66,21 +67,21 @@
"events": "3.3.0",
"fp-ts": "2.16.11",
"globalthis": "1.0.4",
"graphql": "16.11.0",
"graphql": "16.12.0",
"graphql-language-service-interface": "2.10.2",
"graphql-tag": "2.12.6",
"hawk": "9.0.2",
"insomnia-importers": "3.6.0",
"io-ts": "2.2.22",
"js-md5": "0.8.3",
"js-yaml": "4.1.0",
"js-yaml": "4.1.1",
"jsonc-parser": "3.3.1",
"jsonpath-plus": "10.3.0",
"lodash-es": "4.17.21",
"lossless-json": "4.3.0",
"markdown-it": "14.1.0",
"minisearch": "7.2.0",
"monaco-editor": "0.52.2",
"monaco-editor": "0.55.1",
"nprogress": "0.2.0",
"paho-mqtt": "1.1.0",
"path": "0.12.7",
@ -88,8 +89,9 @@
"process": "0.11.10",
"qs": "6.14.0",
"quicktype-core": "23.2.6",
"rollup": "4.53.3",
"rxjs": "7.8.2",
"set-cookie-parser": "2.7.1",
"set-cookie-parser": "2.7.2",
"set-cookie-parser-es": "1.0.5",
"socket.io-client-v2": "npm:socket.io-client@2.5.0",
"socket.io-client-v3": "npm:socket.io-client@3.1.3",
@ -98,23 +100,23 @@
"splitpanes": "3.1.5",
"stream-browserify": "3.0.0",
"subscriptions-transport-ws": "0.11.0",
"superjson": "2.2.3",
"superjson": "2.2.5",
"tern": "0.24.3",
"timers": "0.1.1",
"tippy.js": "6.3.7",
"url": "0.11.4",
"util": "0.12.5",
"uuid": "11.1.0",
"uuid": "13.0.0",
"verzod": "0.4.0",
"vue": "3.5.22",
"vue-i18n": "11.1.12",
"vue-json-pretty": "2.5.0",
"vue-json-pretty": "2.6.0",
"vue-pdf-embed": "2.1.3",
"vue-router": "4.6.3",
"vue-tippy": "6.7.1",
"vuedraggable-es": "4.1.1",
"wonka": "6.3.5",
"workbox-window": "7.3.0",
"workbox-window": "7.4.0",
"xml-formatter": "3.6.7",
"yargs-parser": "22.0.0",
"zod": "3.25.32"
@ -122,18 +124,19 @@
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@esbuild-plugins/node-modules-polyfill": "0.2.2",
"@graphql-codegen/add": "5.0.3",
"@graphql-codegen/cli": "5.0.7",
"@graphql-codegen/typed-document-node": "5.1.2",
"@graphql-codegen/typescript": "4.1.6",
"@graphql-codegen/typescript-operations": "4.6.1",
"@graphql-codegen/add": "6.0.0",
"@graphql-codegen/cli": "6.1.0",
"@graphql-codegen/typed-document-node": "6.1.3",
"@graphql-codegen/typescript": "5.0.5",
"@graphql-codegen/typescript-operations": "5.0.5",
"@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.68",
"@intlify/unplugin-vue-i18n": "6.0.8",
"@iconify-json/lucide": "1.2.73",
"@import-meta-env/cli": "0.7.4",
"@intlify/unplugin-vue-i18n": "11.0.1",
"@relmify/jest-fp-ts": "2.1.1",
"@rushstack/eslint-patch": "1.14.0",
"@rushstack/eslint-patch": "1.15.0",
"@types/har-format": "1.2.16",
"@types/js-yaml": "4.0.9",
"@types/lodash-es": "4.17.12",
@ -142,43 +145,43 @@
"@types/postman-collection": "3.5.11",
"@types/qs": "6.14.0",
"@types/splitpanes": "2.2.6",
"@types/uuid": "10.0.0",
"@types/yargs-parser": "21.0.3",
"@typescript-eslint/eslint-plugin": "8.46.2",
"@typescript-eslint/parser": "8.46.2",
"@vitejs/plugin-vue": "5.1.4",
"@vue/compiler-sfc": "3.5.22",
"@typescript-eslint/eslint-plugin": "8.47.0",
"@typescript-eslint/parser": "8.47.0",
"@vitejs/plugin-vue": "6.0.2",
"@vue/compiler-sfc": "3.5.24",
"@vue/eslint-config-typescript": "13.0.0",
"@vue/runtime-core": "3.5.22",
"@vue/runtime-core": "3.5.24",
"autoprefixer": "10.4.21",
"cross-env": "10.1.0",
"dotenv": "17.2.3",
"eslint": "8.57.0",
"eslint-plugin-prettier": "5.5.4",
"eslint-plugin-vue": "10.5.1",
"glob": "11.0.3",
"jsdom": "26.1.0",
"glob": "13.0.0",
"jsdom": "27.2.0",
"npm-run-all": "4.1.5",
"openapi-types": "12.1.3",
"postcss": "8.5.6",
"prettier": "3.6.2",
"prettier-plugin-tailwindcss": "0.6.14",
"prettier-plugin-tailwindcss": "0.7.1",
"rollup-plugin-polyfill-node": "0.13.0",
"sass": "1.93.2",
"sass": "1.94.2",
"tailwindcss": "3.4.16",
"tsup": "8.5.1",
"typescript": "5.9.3",
"unplugin-fonts": "1.4.0",
"unplugin-icons": "22.2.0",
"unplugin-vue-components": "29.0.0",
"vite": "6.3.6",
"vite-plugin-checker": "0.10.3",
"unplugin-icons": "22.5.0",
"unplugin-vue-components": "30.0.0",
"vite": "7.2.4",
"vite-plugin-checker": "0.11.0",
"vite-plugin-fonts": "0.7.0",
"vite-plugin-html-config": "2.0.2",
"vite-plugin-pages": "0.33.1",
"vite-plugin-pages-sitemap": "1.7.1",
"vite-plugin-pwa": "1.1.0",
"vite-plugin-vue-layouts": "0.11.0",
"vitest": "3.2.4",
"vitest": "4.0.12",
"vue-tsc": "1.8.8"
}
}

View file

@ -117,14 +117,14 @@ async function populatePaneEvent() {
if (!props.layoutId) return
const verticalPaneData = await getPaneData("vertical")
if (verticalPaneData) {
if (verticalPaneData && Array.isArray(verticalPaneData)) {
const [mainPane, sidebarPane] = verticalPaneData
PANE_MAIN_SIZE.value = mainPane?.size
PANE_SIDEBAR_SIZE.value = sidebarPane?.size
}
const horizontalPaneData = await getPaneData("horizontal")
if (horizontalPaneData) {
if (horizontalPaneData && Array.isArray(horizontalPaneData)) {
const [mainTopPane, mainBottomPane] = horizontalPaneData
PANE_MAIN_TOP_SIZE.value = mainTopPane?.size
PANE_MAIN_BOTTOM_SIZE.value = mainBottomPane?.size

View file

@ -7,19 +7,23 @@ import {
import { createBaseRequest } from "./test-utils"
vi.mock("aws4fetch", () => ({
AwsV4Signer: vi.fn().mockImplementation((config) => ({
sign: vi.fn().mockResolvedValue({
headers: new Map([
[
"Authorization",
"AWS4-HMAC-SHA256 Credential=test-key/20240101/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=test-signature",
],
["X-Amz-Date", "20240101T120000Z"],
["Host", "s3.amazonaws.com"],
]),
url: new URL(config.url),
}),
})),
AwsV4Signer: vi.fn().mockImplementation(function (config) {
return {
sign: vi.fn().mockImplementation(function () {
return Promise.resolve({
headers: new Map([
[
"Authorization",
"AWS4-HMAC-SHA256 Credential=test-key/20240101/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=test-signature",
],
["X-Amz-Date", "20240101T120000Z"],
["Host", "s3.amazonaws.com"],
]),
url: new URL(config.url),
})
}),
}
}),
}))
vi.mock("~/helpers/utils/EffectiveURL", () => ({
@ -202,18 +206,19 @@ describe("AWS Signature Auth", () => {
test("should generate AWS signature query parameters correctly", async () => {
const { AwsV4Signer } = await import("aws4fetch")
vi.mocked(AwsV4Signer).mockImplementation(
(config) =>
({
sign: vi.fn().mockResolvedValue({
vi.mocked(AwsV4Signer).mockImplementation(function (config) {
return {
sign: vi.fn().mockImplementation(function () {
return Promise.resolve({
headers: new Map(),
url: new URL(
config.url +
"?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=test-key%2F20240101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240101T120000Z&X-Amz-SignedHeaders=host&X-Amz-Signature=test-signature"
),
}),
}) as any
)
})
}),
}
})
const auth = createBaseAuth({ addTo: "QUERY_PARAMS" })
const request = createBaseRequest()
@ -261,18 +266,19 @@ describe("AWS Signature Auth", () => {
test("should exclude original request parameters from result", async () => {
const { AwsV4Signer } = await import("aws4fetch")
vi.mocked(AwsV4Signer).mockImplementation(
(config) =>
({
sign: vi.fn().mockResolvedValue({
vi.mocked(AwsV4Signer).mockImplementation(function (config) {
return {
sign: vi.fn().mockImplementation(function () {
return Promise.resolve({
headers: new Map(),
url: new URL(
config.url +
"?original-param=value&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Signature=test-signature"
),
}),
}) as any
)
})
}),
}
})
const auth = createBaseAuth({ addTo: "QUERY_PARAMS" })
const request = createBaseRequest({
@ -301,18 +307,19 @@ describe("AWS Signature Auth", () => {
test("should handle template strings in endpoint", async () => {
const { AwsV4Signer } = await import("aws4fetch")
vi.mocked(AwsV4Signer).mockImplementation(
(config) =>
({
sign: vi.fn().mockResolvedValue({
vi.mocked(AwsV4Signer).mockImplementation(function (config) {
return {
sign: vi.fn().mockImplementation(function () {
return Promise.resolve({
headers: new Map(),
url: new URL(
config.url +
"?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Signature=test-signature"
),
}),
}) as any
)
})
}),
}
})
const auth = createBaseAuth({ addTo: "QUERY_PARAMS" })
@ -340,18 +347,19 @@ describe("AWS Signature Auth", () => {
test("should sort existing parameters alphabetically before signing", async () => {
const { AwsV4Signer } = await import("aws4fetch")
vi.mocked(AwsV4Signer).mockImplementation(
(config) =>
({
sign: vi.fn().mockResolvedValue({
vi.mocked(AwsV4Signer).mockImplementation(function (config) {
return {
sign: vi.fn().mockImplementation(function () {
return Promise.resolve({
headers: new Map(),
url: new URL(
config.url +
"?z-param=value1&a-param=value2&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Signature=test-signature"
),
}),
}) as any
)
})
}),
}
})
const auth = createBaseAuth({ addTo: "QUERY_PARAMS" })
const request = createBaseRequest({
@ -377,18 +385,19 @@ describe("AWS Signature Auth", () => {
test("should handle empty or missing session token", async () => {
const { AwsV4Signer } = await import("aws4fetch")
vi.mocked(AwsV4Signer).mockImplementation(
(config) =>
({
sign: vi.fn().mockResolvedValue({
vi.mocked(AwsV4Signer).mockImplementation(function (config) {
return {
sign: vi.fn().mockImplementation(function () {
return Promise.resolve({
headers: new Map(),
url: new URL(
config.url +
"?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Signature=test-signature"
),
}),
}) as any
)
})
}),
}
})
const auth = createBaseAuth({ addTo: "QUERY_PARAMS" })
const request = createBaseRequest()

View file

@ -14,8 +14,6 @@ import { getService } from "./dioc"
import FALLBACK_LANG_MESSAGES from "../../locales/en.json"
import messages from "@intlify/unplugin-vue-i18n/messages"
/*
In context of this file, we have 2 main kinds of things.
1. Locale -> A locale is termed as the i18n entries present in the /locales folder
@ -199,7 +197,7 @@ export default <HoppModule>{
fallbackLocale: "en",
legacy: false,
allowComposition: true,
messages,
messages: { [FALLBACK_LANG_CODE]: FALLBACK_LANG_MESSAGES },
})
app.use(i18n)

View file

@ -20,7 +20,7 @@ import axios, { CancelTokenSource } from "axios"
import SettingsAgentInterceptor from "~/components/settings/Agent.vue"
import AgentRootUIExtension from "~/components/interceptors/agent/RootExt.vue"
import { UIExtensionService } from "~/services/ui-extension.service"
import { x25519 } from "@noble/curves/ed25519"
import { x25519 } from "@noble/curves/ed25519.js"
import { base16 } from "@scure/base"
import { invokeAction } from "~/helpers/actions"
import { preProcessRequest } from "../helpers"

View file

@ -4,7 +4,7 @@ import * as E from "fp-ts/Either"
import axios from "axios"
import { Store } from "~/kernel/store"
import type { PluginRequest, PluginResponse } from "@hoppscotch/kernel"
import { x25519 } from "@noble/curves/ed25519"
import { x25519 } from "@noble/curves/ed25519.js"
import { base16 } from "@scure/base"
import {
InputDomainSetting,

View file

@ -1,10 +1,19 @@
import * as E from "fp-ts/Either"
import { Service } from "dioc"
import { MaybeRef, refWithControl } from "@vueuse/core"
import { refWithControl } from "@vueuse/core"
import { AxiosRequestConfig, AxiosResponse } from "axios"
import type { getI18n } from "~/modules/i18n"
import { throwError } from "~/helpers/functional/error"
import { Component, Ref, computed, reactive, watch, unref, markRaw } from "vue"
import {
Component,
MaybeRef,
Ref,
computed,
reactive,
watch,
unref,
markRaw,
} from "vue"
/**
* Defines the response data from an interceptor request run.

View file

@ -10,8 +10,10 @@ import { watchDebounced } from "@vueuse/core"
import { TestContainer } from "dioc/testing"
import { cloneDeep } from "lodash-es"
import superjson from "superjson"
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
import { getKernelMode, initKernel } from "@hoppscotch/kernel"
import { Store } from "~/kernel"
import { MQTTRequest$, setMQTTRequest } from "~/newstore/MQTTSession"
import { SSERequest$, setSSERequest } from "~/newstore/SSESession"
import { SIORequest$, setSIORequest } from "~/newstore/SocketIOSession"
@ -46,6 +48,7 @@ import {
performSettingsDataMigrations,
settingsStore,
} from "~/newstore/settings"
import { SecretEnvironmentService } from "~/services/secret-environment.service"
import { GQLTabService } from "~/services/tab/graphql"
import { RESTTabService } from "~/services/tab/rest"
import {
@ -70,9 +73,6 @@ import {
VUEX_DATA_MOCK,
WEBSOCKET_REQUEST_MOCK,
} from "./__mocks__"
import { SecretEnvironmentService } from "~/services/secret-environment.service"
import { getKernelMode, initKernel } from "@hoppscotch/kernel"
import { Store } from "~/kernel"
initKernel(getKernelMode())
@ -208,7 +208,7 @@ describe("PersistenceService", () => {
await Store.remove(STORE_NAMESPACE, STORE_KEYS.SCHEMA_VERSION)
})
afterAll(() => {
afterEach(() => {
// Clear all mocks
vi.clearAllMocks()

View file

@ -5,8 +5,7 @@ import {
type SpotlightSearcherSessionState,
} from "../.."
import MiniSearch from "minisearch"
import { Ref, computed, effectScope, ref, watch } from "vue"
import { resolveUnref } from "@vueuse/core"
import { Ref, computed, effectScope, ref, watch, toValue } from "vue"
/**
* Defines a search result and additional metadata returned by a StaticSpotlightSearcher
@ -175,6 +174,6 @@ export abstract class StaticSpotlightSearcherService<
public abstract onDocSelected(id: string, doc: Doc): void
public onResultSelect(result: SpotlightSearcherResult): void {
this.onDocSelected(result.id, resolveUnref(this._documents)[result.id])
this.onDocSelected(result.id, toValue(this._documents)[result.id])
}
}

View file

@ -36,17 +36,16 @@
"homepage": "https://github.com/hoppscotch/hoppscotch#readme",
"devDependencies": {
"@types/lodash": "4.17.20",
"@types/uuid": "10.0.0",
"typescript": "5.9.3",
"vite": "6.3.6"
"vite": "7.2.4"
},
"dependencies": {
"fp-ts": "2.16.11",
"io-ts": "2.2.22",
"jose": "6.1.0",
"jose": "6.1.2",
"lodash": "4.17.21",
"parser-ts": "0.7.0",
"uuid": "11.1.0",
"uuid": "13.0.0",
"verzod": "0.4.0",
"zod": "3.25.32"
}

View file

@ -24,8 +24,7 @@
},
"types": "./index.d.ts",
"engines": {
"node": ">=14",
"pnpm": ">=3"
"node": ">=22"
},
"scripts": {
"lint": "eslint --ext .ts,.js --ignore-path .gitignore .",
@ -53,7 +52,7 @@
"dependencies": {
"@hoppscotch/data": "workspace:^",
"@types/lodash-es": "4.17.12",
"chai": "6.2.0",
"chai": "6.2.1",
"faraday-cage": "0.1.0",
"fp-ts": "2.16.11",
"lodash": "4.17.21",
@ -62,23 +61,23 @@
"devDependencies": {
"@digitak/esrun": "3.2.26",
"@relmify/jest-fp-ts": "2.1.1",
"@types/chai": "5.2.2",
"@types/chai": "5.2.3",
"@types/jest": "30.0.0",
"@types/lodash": "4.17.20",
"@types/node": "24.9.1",
"@typescript-eslint/eslint-plugin": "8.44.1",
"@typescript-eslint/parser": "8.44.1",
"@types/node": "24.10.1",
"@typescript-eslint/eslint-plugin": "8.47.0",
"@typescript-eslint/parser": "8.47.0",
"eslint": "8.57.0",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-prettier": "5.5.4",
"io-ts": "2.2.22",
"prettier": "3.6.2",
"typescript": "5.9.3",
"vite": "6.3.6",
"vitest": "3.2.4"
"vite": "7.2.4",
"vitest": "4.0.12"
},
"peerDependencies": {
"isolated-vm": "5.0.1"
"isolated-vm": "6.0.2"
},
"peerDependenciesMeta": {
"isolated-vm": {

View file

@ -30,13 +30,13 @@
"@hoppscotch/data": "workspace:^",
"@hoppscotch/kernel": "workspace:^",
"@hoppscotch/ui": "0.2.5",
"@import-meta-env/unplugin": "0.6.2",
"@import-meta-env/unplugin": "0.6.3",
"@tauri-apps/api": "2.1.1",
"@tauri-apps/plugin-dialog": "2.0.1",
"@tauri-apps/plugin-fs": "2.0.2",
"@tauri-apps/plugin-shell": "2.2.1",
"@vueuse/core": "13.7.0",
"axios": "1.12.2",
"@vueuse/core": "14.0.0",
"axios": "1.13.2",
"buffer": "6.0.3",
"dioc": "3.0.2",
"fp-ts": "2.16.11",
@ -46,25 +46,25 @@
"util": "0.12.5",
"verzod": "0.4.0",
"vue": "3.5.22",
"workbox-window": "7.3.0",
"workbox-window": "7.4.0",
"zod": "3.25.32"
},
"devDependencies": {
"@graphql-codegen/add": "5.0.3",
"@graphql-codegen/cli": "5.0.7",
"@graphql-codegen/typed-document-node": "5.1.2",
"@graphql-codegen/typescript": "4.1.6",
"@graphql-codegen/typescript-operations": "4.6.1",
"@graphql-codegen/add": "6.0.0",
"@graphql-codegen/cli": "6.1.0",
"@graphql-codegen/typed-document-node": "6.1.3",
"@graphql-codegen/typescript": "5.0.5",
"@graphql-codegen/typescript-operations": "5.0.5",
"@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.68",
"@intlify/unplugin-vue-i18n": "6.0.8",
"@intlify/unplugin-vue-i18n": "11.0.1",
"@rushstack/eslint-patch": "1.14.0",
"@typescript-eslint/eslint-plugin": "8.44.1",
"@typescript-eslint/parser": "8.44.1",
"@vitejs/plugin-legacy": "5.4.2",
"@vitejs/plugin-vue": "5.1.4",
"@typescript-eslint/eslint-plugin": "8.47.0",
"@typescript-eslint/parser": "8.47.0",
"@vitejs/plugin-legacy": "7.2.1",
"@vitejs/plugin-vue": "6.0.2",
"@vue/eslint-config-typescript": "13.0.0",
"autoprefixer": "10.4.21",
"cross-env": "10.1.0",
@ -74,13 +74,13 @@
"eslint-plugin-vue": "10.5.1",
"npm-run-all": "4.1.5",
"postcss": "8.5.6",
"prettier-plugin-tailwindcss": "0.6.14",
"prettier-plugin-tailwindcss": "0.7.1",
"tailwindcss": "3.4.16",
"typescript": "5.9.3",
"unplugin-fonts": "1.4.0",
"unplugin-icons": "22.2.0",
"unplugin-vue-components": "29.0.0",
"vite": "6.3.5",
"vite": "7.2.4",
"vite-plugin-fonts": "0.7.0",
"vite-plugin-html-config": "2.0.2",
"vite-plugin-inspect": "11.3.3",

View file

@ -19,25 +19,25 @@
"@graphql-typed-document-node/core": "3.2.0",
"@hoppscotch/ui": "0.2.5",
"@hoppscotch/vue-toasted": "0.1.0",
"@intlify/unplugin-vue-i18n": "6.0.8",
"@intlify/unplugin-vue-i18n": "11.0.1",
"@types/cors": "2.8.19",
"@urql/exchange-auth": "3.0.0",
"@urql/vue": "2.0.0",
"@vueuse/core": "13.7.0",
"axios": "1.12.2",
"@vueuse/core": "14.0.0",
"axios": "1.13.2",
"cors": "2.8.5",
"date-fns": "4.1.0",
"fp-ts": "2.16.11",
"graphql": "16.11.0",
"graphql": "16.12.0",
"io-ts": "2.2.22",
"lodash-es": "4.17.21",
"postcss": "8.5.6",
"prettier-plugin-tailwindcss": "0.6.14",
"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-icons": "22.2.0",
"unplugin-icons": "22.5.0",
"unplugin-vue-components": "29.0.0",
"vue": "3.5.22",
"vue-i18n": "11.1.12",
@ -45,30 +45,30 @@
"vue-tippy": "6.7.1"
},
"devDependencies": {
"@graphql-codegen/cli": "5.0.7",
"@graphql-codegen/client-preset": "4.8.3",
"@graphql-codegen/introspection": "4.0.3",
"@graphql-codegen/typed-document-node": "5.1.2",
"@graphql-codegen/typescript": "4.1.6",
"@graphql-codegen/typescript-document-nodes": "4.0.16",
"@graphql-codegen/typescript-operations": "4.6.1",
"@graphql-codegen/cli": "6.1.0",
"@graphql-codegen/client-preset": "5.2.0",
"@graphql-codegen/introspection": "5.0.0",
"@graphql-codegen/typed-document-node": "6.1.3",
"@graphql-codegen/typescript": "5.0.5",
"@graphql-codegen/typescript-document-nodes": "5.0.5",
"@graphql-codegen/typescript-operations": "5.0.5",
"@graphql-codegen/urql-introspection": "3.0.1",
"@iconify-json/lucide": "1.2.68",
"@import-meta-env/cli": "0.7.3",
"@import-meta-env/unplugin": "0.6.2",
"@import-meta-env/cli": "0.7.4",
"@import-meta-env/unplugin": "0.6.3",
"@types/lodash-es": "4.17.12",
"@vitejs/plugin-vue": "5.1.4",
"@vue/compiler-sfc": "3.5.22",
"@vitejs/plugin-vue": "6.0.2",
"@vue/compiler-sfc": "3.5.24",
"autoprefixer": "10.4.21",
"dotenv": "17.2.3",
"graphql-tag": "2.12.6",
"hoppscotch-backend": "workspace:^",
"npm-run-all": "4.1.5",
"sass": "1.93.2",
"sass": "1.94.2",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"unplugin-fonts": "1.4.0",
"vite": "6.3.5",
"vite": "7.2.4",
"vite-plugin-pages": "0.33.1",
"vite-plugin-vue-layouts": "0.11.0",
"vue-tsc": "2.1.6"

View file

@ -51,11 +51,8 @@ declare module 'vue' {
OnboardingOAuthSetup: typeof import('./components/onboarding/OAuthSetup.vue')['default']
OnboardingSmtpSetup: typeof import('./components/onboarding/SmtpSetup.vue')['default']
OnboardingWelcomeScreen: typeof import('./components/onboarding/WelcomeScreen.vue')['default']
SettingsAuthConfiguration: typeof import('./components/settings/AuthConfiguration.vue')['default']
SettingsAuthConfigurations: typeof import('./components/settings/AuthConfigurations.vue')['default']
SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default']
SettingsAuthToken: typeof import('./components/settings/AuthToken.vue')['default']
SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default']
SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default']
SettingsHistoryConfiguration: typeof import('./components/settings/HistoryConfiguration.vue')['default']
SettingsMockServerConfig: typeof import('./components/settings/MockServerConfig.vue')['default']
@ -63,7 +60,6 @@ declare module 'vue' {
SettingsRateLimit: typeof import('./components/settings/RateLimit.vue')['default']
SettingsReset: typeof import('./components/settings/Reset.vue')['default']
SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default']
SettingsSettingsMockServer: typeof import('./components/settings/SettingsMockServer.vue')['default']
SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default']
SetupDataSharingAndNewsletter: typeof import('./components/setup/DataSharingAndNewsletter.vue')['default']
TeamsAdd: typeof import('./components/teams/Add.vue')['default']

File diff suppressed because it is too large Load diff

View file

@ -12,9 +12,9 @@ RUN expected="a9efa00c161922dd24650fd0bee2f4f8bb2fb69ff3e63dcc44f0694da64bb0cf"
echo "✅ Caddy Source Checksum OK" || \
(echo "❌ Caddy Source Checksum failed!" && exit 1)
# Install Go 1.25.3 from GitHub releases to fix CVE-2025-47907
# Install Go 1.25.4 from GitHub releases to fix CVE-2025-47907
ARG TARGETARCH
ENV GOLANG_VERSION=1.25.3
ENV GOLANG_VERSION=1.25.4
# Download and install Go from the official 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 && \
@ -27,8 +27,12 @@ ENV PATH="/usr/local/go/bin:${PATH}" \
WORKDIR /tmp/caddy-build
RUN tar xvf /tmp/caddy-build/src.tar.gz && \
# Patch to resolve CVE on quic-go
# Patch to resolve CVE-2025-59530 on quic-go
go get github.com/quic-go/quic-go@v0.55.0 && \
# Patch to resolve CVE-2025-62820 on nebula
go get github.com/slackhq/nebula@v1.9.7 && \
# Patch to resolve CVE-2025-47913 on crypto
go get golang.org/x/crypto@v0.45.0 && \
# Clean up any existing vendor directory and regenerate with updated deps
rm -rf vendor && \
go mod tidy && \
@ -48,9 +52,9 @@ RUN apk add --no-cache nodejs curl bash tini ca-certificates \
# Set working directory for NPM installation
WORKDIR /tmp/npm-install
# Download NPM tarball
RUN curl -fsSL https://registry.npmjs.org/npm/-/npm-11.6.2.tgz -o npm.tgz
RUN curl -fsSL https://registry.npmjs.org/npm/-/npm-11.6.3.tgz -o npm.tgz
# Verify checksum
RUN expected="585f95094ee5cb2788ee11d90f2a518a7c9ef6e083fa141d0b63ca3383675a20" \
RUN expected="f021e628209026669ec9e3881523a7efcf26934fd3fb5dd3fd9aa2a5030c7c41" \
&& actual=$(sha256sum npm.tgz | cut -d' ' -f1) \
&& [ "$actual" = "$expected" ] \
&& echo "✅ NPM Tarball Checksum OK" \
@ -58,10 +62,18 @@ RUN expected="585f95094ee5cb2788ee11d90f2a518a7c9ef6e083fa141d0b63ca3383675a20"
# Install NPM from verified tarball and global packages
RUN tar -xzf npm.tgz && \
cd package && \
node bin/npm-cli.js install -g npm@11.6.2 && \
node bin/npm-cli.js install -g npm@11.6.3 && \
cd / && \
rm -rf /tmp/npm-install && \
npm install -g pnpm@10.18.3 @import-meta-env/cli
npm install -g pnpm@10.23.0 @import-meta-env/cli && \
# Fix CVE-2025-64756 by replacing vulnerable glob with patched version
npm install -g glob@11.1.0 && \
# Replace glob in npm's node_modules
rm -rf /usr/lib/node_modules/npm/node_modules/glob && \
cp -r /usr/lib/node_modules/glob /usr/lib/node_modules/npm/node_modules/ && \
# Replace glob in @import-meta-env/cli's node_modules
rm -rf /usr/lib/node_modules/@import-meta-env/cli/node_modules/glob && \
cp -r /usr/lib/node_modules/glob /usr/lib/node_modules/@import-meta-env/cli/node_modules/