From 7f619f3407719681d2ad54c83a48fe837d788837 Mon Sep 17 00:00:00 2001 From: George Oastler Date: Thu, 4 Dec 2025 11:57:55 +0000 Subject: [PATCH 1/5] fix mongoose connection setup parameters --- .../src/utils/connection.ts | 18 +++++++++++++++++- packages/database/src/base/mongo.ts | 15 ++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/demos/client-example-server/src/utils/connection.ts b/demos/client-example-server/src/utils/connection.ts index a93f1ce27b..3bdc43b3ae 100644 --- a/demos/client-example-server/src/utils/connection.ts +++ b/demos/client-example-server/src/utils/connection.ts @@ -15,11 +15,27 @@ import { AutoIncrementID, type AutoIncrementIDOptions, } from "@typegoose/auto-increment"; +import { ServerApiVersion } from "mongodb"; import mongoose, { type Connection } from "mongoose"; +import { fileURLToPath } from "url"; import UserSchema from "../models/user.js"; function connectionFactory(uri: string): Connection { - const conn = mongoose.createConnection(uri); + const appName = fileURLToPath(import.meta.url); + const conn = mongoose.createConnection(uri, { + serverApi: { + version: ServerApiVersion.v1, + strict: true, + deprecationErrors: true, + }, + serverSelectionTimeoutMS: 20000, + socketTimeoutMS: 30000, + minPoolSize: 0, + maxIdleTimeMS: 300000, + connectTimeoutMS: 10000, + maxPoolSize: 10, + appName, + }); if (!conn.models.user) { UserSchema.plugin(AutoIncrementID, { field: "id", diff --git a/packages/database/src/base/mongo.ts b/packages/database/src/base/mongo.ts index ddf2b4edbb..5e7a9167f2 100644 --- a/packages/database/src/base/mongo.ts +++ b/packages/database/src/base/mongo.ts @@ -15,6 +15,7 @@ import { type Logger, ProsopoDBError, getLogger } from "@prosopo/common"; import type { IDatabase } from "@prosopo/types-database"; import { ServerApiVersion } from "mongodb"; import mongoose, { type Connection } from "mongoose"; +import { fileURLToPath } from "url"; mongoose.set("strictQuery", false); @@ -99,9 +100,21 @@ export class MongoDatabase implements IDatabase { // Start a new connection this.connecting = new Promise((resolve, reject) => { + const appName = fileURLToPath(import.meta.url); const connection = mongoose.createConnection(this.url, { dbName: this.dbname, - serverApi: ServerApiVersion.v1, + serverApi: { + version: ServerApiVersion.v1, + strict: true, + deprecationErrors: true, + }, + serverSelectionTimeoutMS: 20000, + socketTimeoutMS: 30000, + minPoolSize: 0, + maxIdleTimeMS: 300000, + connectTimeoutMS: 10000, + maxPoolSize: 10, + appName, }); const onConnected = () => { From ca1b546649c2c918d2a6465bab633c8ac2206471 Mon Sep 17 00:00:00 2001 From: George Oastler Date: Thu, 4 Dec 2025 12:49:08 +0000 Subject: [PATCH 2/5] make util fn for getting mongoose connection options, deduce compressors from url --- .../src/utils/connection.ts | 24 ++-- packages/database/src/base/mongo.ts | 26 ++-- packages/database/src/index.ts | 1 + packages/database/src/mongooseOptions.ts | 136 ++++++++++++++++++ .../src/tests/mongooseOptions.unit.test.ts | 126 ++++++++++++++++ 5 files changed, 282 insertions(+), 31 deletions(-) create mode 100644 packages/database/src/mongooseOptions.ts create mode 100644 packages/database/src/tests/mongooseOptions.unit.test.ts diff --git a/demos/client-example-server/src/utils/connection.ts b/demos/client-example-server/src/utils/connection.ts index 3bdc43b3ae..c1c9f718ad 100644 --- a/demos/client-example-server/src/utils/connection.ts +++ b/demos/client-example-server/src/utils/connection.ts @@ -15,27 +15,21 @@ import { AutoIncrementID, type AutoIncrementIDOptions, } from "@typegoose/auto-increment"; -import { ServerApiVersion } from "mongodb"; +import { getMongoConnectionOptions } from "@prosopo/database"; import mongoose, { type Connection } from "mongoose"; import { fileURLToPath } from "url"; import UserSchema from "../models/user.js"; function connectionFactory(uri: string): Connection { const appName = fileURLToPath(import.meta.url); - const conn = mongoose.createConnection(uri, { - serverApi: { - version: ServerApiVersion.v1, - strict: true, - deprecationErrors: true, - }, - serverSelectionTimeoutMS: 20000, - socketTimeoutMS: 30000, - minPoolSize: 0, - maxIdleTimeMS: 300000, - connectTimeoutMS: 10000, - maxPoolSize: 10, - appName, - }); + + const conn = mongoose.createConnection( + uri, + getMongoConnectionOptions({ + url: uri, + appName, + }), + ); if (!conn.models.user) { UserSchema.plugin(AutoIncrementID, { field: "id", diff --git a/packages/database/src/base/mongo.ts b/packages/database/src/base/mongo.ts index 5e7a9167f2..a0643ec9c8 100644 --- a/packages/database/src/base/mongo.ts +++ b/packages/database/src/base/mongo.ts @@ -13,7 +13,7 @@ // limitations under the License. import { type Logger, ProsopoDBError, getLogger } from "@prosopo/common"; import type { IDatabase } from "@prosopo/types-database"; -import { ServerApiVersion } from "mongodb"; +import { getMongoConnectionOptions } from "../mongooseOptions.js"; import mongoose, { type Connection } from "mongoose"; import { fileURLToPath } from "url"; @@ -101,21 +101,15 @@ export class MongoDatabase implements IDatabase { // Start a new connection this.connecting = new Promise((resolve, reject) => { const appName = fileURLToPath(import.meta.url); - const connection = mongoose.createConnection(this.url, { - dbName: this.dbname, - serverApi: { - version: ServerApiVersion.v1, - strict: true, - deprecationErrors: true, - }, - serverSelectionTimeoutMS: 20000, - socketTimeoutMS: 30000, - minPoolSize: 0, - maxIdleTimeMS: 300000, - connectTimeoutMS: 10000, - maxPoolSize: 10, - appName, - }); + + const connection = mongoose.createConnection( + this.url, + getMongoConnectionOptions({ + url: this.url, + appName, + dbName: this.dbname, + }), + ); const onConnected = () => { this.logger.debug(() => ({ diff --git a/packages/database/src/index.ts b/packages/database/src/index.ts index 89e415e337..6d180785f3 100644 --- a/packages/database/src/index.ts +++ b/packages/database/src/index.ts @@ -16,3 +16,4 @@ import makeDir from "make-dir"; console.debug(makeDir); export * from "./base/index.js"; export * from "./databases/index.js"; +export * from "./mongooseOptions.js"; diff --git a/packages/database/src/mongooseOptions.ts b/packages/database/src/mongooseOptions.ts new file mode 100644 index 0000000000..b1313c7429 --- /dev/null +++ b/packages/database/src/mongooseOptions.ts @@ -0,0 +1,136 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { ServerApiVersion } from "mongodb"; +import type { ConnectOptions } from "mongoose"; + +/** + * Determines MongoDB compression settings based on whether the connection URL is a remote domain. + * Remote domains (e.g., abc.com, x.y.com) will use compression, while local connections + * (e.g., localhost, container names like "database", "db", "mongo", or IP addresses) will not. + * + * @param url - The MongoDB connection URL string + * @param compressors - Optional array of compressor strings. Defaults to ["zstd", "snappy", "zlib", "none"] + * @returns Array of compressor strings if the URL is a remote domain, empty array otherwise + */ +export const getMongoCompressors = ( + url: string, + compressors: ("zstd" | "none" | "snappy" | "zlib")[] = [ + "zstd", + "snappy", + "zlib", + "none", + ], +): ("zstd" | "none" | "snappy" | "zlib")[] => { + try { + // Extract the part after "://" to handle any protocol (mongodb://, mongodb+srv://, etc.) + const protocolIndex = url.indexOf("://"); + const urlWithoutProtocol = + protocolIndex !== -1 ? url.slice(protocolIndex + 3) : url; + const parsedUrl = new URL(`mongodb://${urlWithoutProtocol}`); + const hostname = parsedUrl.hostname; + + // Localhost variants should not use compression + const isLocalhost = + hostname === "localhost" || + hostname === "127.0.0.1" || + hostname === "::1" || + hostname === "[::1]"; + + // If it's localhost, no compression + if (isLocalhost) { + return []; + } + + // Domains and IP addresses (IPv4/IPv6) include dots or colons + return hostname.includes(".") || + hostname.includes(":") + ? compressors + : []; + } catch { + // If URI parsing fails, default to compression + return compressors; + } +}; + +export interface MongoConnectionOptions extends Partial { + serverApi: { + version: ServerApiVersion; + strict: boolean; + deprecationErrors: boolean; + }; + maxPoolSize: number; + minPoolSize: number; + connectTimeoutMS: number; + socketTimeoutMS: number; + maxIdleTimeMS: number; + appName: string; + serverSelectionTimeoutMS: number; + compressors: ("zstd" | "none" | "snappy" | "zlib")[]; + dbName?: string; +} + +/** + * Returns default mongoose connection options with the ability to override specific values. + * + * @param options - Configuration options + * @param options.url - MongoDB connection URL string + * @param options.appName - Application name (typically from fileURLToPath(import.meta.url)) + * @param options.maxPoolSize - Maximum pool size (default: 10) + * @param options.dbName - Optional database name + * @returns Mongoose connection options object + */ +export const getMongoConnectionOptions = ( + options: { + url: string; + appName: string; + maxPoolSize?: number; + dbName?: string; + }, +): MongoConnectionOptions => { + const { + url, + appName, + maxPoolSize = 10, + dbName, + } = options; + + if (!url || url.trim() === "") { + throw new Error("MongoDB connection URL is required and cannot be empty"); + } + + const compressors = getMongoCompressors(url); + + const connectionOptions: MongoConnectionOptions = { + serverApi: { + version: ServerApiVersion.v1, + strict: true, + deprecationErrors: true, + }, + maxPoolSize, // allow up to N connections at any given time. >1 connection allows parallel db operations + minPoolSize: 0, // allow pool to close idle connections down to this amount, 0 keep no connections open if they've been idle for longer than maxIdleTimeMS + connectTimeoutMS: 10000, // max time to connect to the database + socketTimeoutMS: 30000, // max time to wait for a response from the database when doing an operation + maxIdleTimeMS: 300000, // max time spent idle before closing the connection + appName, + serverSelectionTimeoutMS: 20000, // max time to wait for a response from the database + compressors, + }; + + if (dbName) { + connectionOptions.dbName = dbName; + } + + return connectionOptions; +}; + diff --git a/packages/database/src/tests/mongooseOptions.unit.test.ts b/packages/database/src/tests/mongooseOptions.unit.test.ts new file mode 100644 index 0000000000..e5266b0014 --- /dev/null +++ b/packages/database/src/tests/mongooseOptions.unit.test.ts @@ -0,0 +1,126 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { describe, expect, it } from "vitest"; +import { getMongoCompressors } from "../mongooseOptions.js"; + +describe("getMongoCompressors", () => { + it("returns default compressors for remote domains", () => { + const urls = [ + "mongodb://user:pass@example.com:27017/db", + "mongodb://abc.com/db", + "mongodb://x.y.com:27017/db", + "mongodb://cluster.mongodb.net/db", + "mongodb://subdomain.example.com/db", + ]; + const expected = ["zstd", "snappy", "zlib", "none"]; + urls.forEach((url) => { + expect(getMongoCompressors(url)).toEqual(expected); + }); + }); + + it("returns empty array for local hostnames without dots", () => { + const urls = [ + "mongodb://database:27017/db", + "mongodb://db/db", + "mongodb://mongo:27017/db", + "mongodb://container-name/db", + ]; + urls.forEach((url) => { + expect(getMongoCompressors(url)).toEqual([]); + }); + }); + + it("returns empty array for localhost variants", () => { + const urls = [ + "mongodb://localhost:27017/db", + "mongodb://127.0.0.1:27017/db", + "mongodb://[::1]:27017/db", + "mongodb://::1:27017/db", + ]; + urls.forEach((url) => { + expect(getMongoCompressors(url)).toEqual([]); + }); + }); + + it("returns compressors for IP addresses (treated as remote)", () => { + const urls = [ + "mongodb://192.168.1.1:27017/db", + "mongodb://10.0.0.1/db", + "mongodb://172.16.0.1:27017/db", + ]; + const expected = ["zstd", "snappy", "zlib", "none"]; + urls.forEach((url) => { + expect(getMongoCompressors(url)).toEqual(expected); + }); + }); + + it("returns compressors for IPv6 addresses (treated as remote)", () => { + const urls = [ + "mongodb://[2001:0db8::1]:27017/db", + "mongodb://[2001:0db8:85a3::8a2e:0370:7334]/db", + "mongodb://[::ffff:192.168.1.1]:27017/db", + ]; + const expected = ["zstd", "snappy", "zlib", "none"]; + urls.forEach((url) => { + expect(getMongoCompressors(url)).toEqual(expected); + }); + }); + + it("uses custom compressors when provided", () => { + const customCompressors = ["zstd", "snappy"]; + const url = "mongodb://example.com:27017/db"; + expect(getMongoCompressors(url, customCompressors)).toEqual( + customCompressors, + ); + }); + + it("returns empty array for local connections even with custom compressors", () => { + const customCompressors = ["zstd", "snappy"]; + const url = "mongodb://localhost:27017/db"; + expect(getMongoCompressors(url, customCompressors)).toEqual([]); + }); + + it("handles mongodb+srv:// URLs", () => { + const url = "mongodb+srv://cluster.mongodb.net/db"; + const expected = ["zstd", "snappy", "zlib", "none"]; + expect(getMongoCompressors(url)).toEqual(expected); + }); + + it("returns default compressors for invalid URLs", () => { + const invalidUrls = [ + "not-a-url", + "", + "mongodb://", + "invalid://example.com", + ]; + const expected = ["zstd", "snappy", "zlib", "none"]; + invalidUrls.forEach((url) => { + expect(getMongoCompressors(url)).toEqual(expected); + }); + }); + + it("handles URLs with authentication", () => { + const url = "mongodb://user:password@example.com:27017/db"; + const expected = ["zstd", "snappy", "zlib", "none"]; + expect(getMongoCompressors(url)).toEqual(expected); + }); + + it("handles URLs with query parameters", () => { + const url = + "mongodb://example.com:27017/db?authSource=admin&retryWrites=true"; + const expected = ["zstd", "snappy", "zlib", "none"]; + expect(getMongoCompressors(url)).toEqual(expected); + }); +}); + From 51798939ac5782829d6df0a2681967468f34a741 Mon Sep 17 00:00:00 2001 From: George Oastler Date: Thu, 4 Dec 2025 14:03:30 +0000 Subject: [PATCH 3/5] fix deps --- demos/client-example-server/package.json | 1 + demos/client-example-server/tsconfig.cjs.json | 3 ++ demos/client-example-server/tsconfig.json | 3 ++ packages/database/package.json | 4 ++- packages/database/vite.test.config.ts | 33 +++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/database/vite.test.config.ts diff --git a/demos/client-example-server/package.json b/demos/client-example-server/package.json index ba6c2dc8c5..a3688a3dc2 100644 --- a/demos/client-example-server/package.json +++ b/demos/client-example-server/package.json @@ -41,6 +41,7 @@ "@polkadot/util": "13.5.7", "@polkadot/util-crypto": "13.5.7", "@prosopo/common": "3.1.27", + "@prosopo/database": "3.6.4", "@prosopo/dotenv": "3.0.32", "@prosopo/keyring": "2.8.43", "@prosopo/server": "2.9.51", diff --git a/demos/client-example-server/tsconfig.cjs.json b/demos/client-example-server/tsconfig.cjs.json index a46ad800a9..dea846db8b 100644 --- a/demos/client-example-server/tsconfig.cjs.json +++ b/demos/client-example-server/tsconfig.cjs.json @@ -13,6 +13,9 @@ { "path": "../../packages/common" }, + { + "path": "../../packages/database" + }, { "path": "../../packages/dotenv" }, diff --git a/demos/client-example-server/tsconfig.json b/demos/client-example-server/tsconfig.json index d939fa9518..27c1158184 100644 --- a/demos/client-example-server/tsconfig.json +++ b/demos/client-example-server/tsconfig.json @@ -19,6 +19,9 @@ { "path": "../../packages/common" }, + { + "path": "../../packages/database" + }, { "path": "../../packages/dotenv" }, diff --git a/packages/database/package.json b/packages/database/package.json index 51dddbf41b..4b2fdbc4ab 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -21,7 +21,8 @@ "build": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.esm.config.ts --mode $NODE_ENV", "build:tsc": "tsc --build --verbose", "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV", - "typecheck": "tsc --project tsconfig.types.json" + "typecheck": "tsc --project tsconfig.types.json", + "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts" }, "repository": { "type": "git", @@ -52,6 +53,7 @@ "@vitest/coverage-v8": "3.2.4", "concurrently": "9.0.1", "del-cli": "6.0.0", + "dotenv": "16.4.5", "npm-run-all": "4.1.5", "tslib": "2.7.0", "tsx": "4.20.3", diff --git a/packages/database/vite.test.config.ts b/packages/database/vite.test.config.ts new file mode 100644 index 0000000000..d65f122a16 --- /dev/null +++ b/packages/database/vite.test.config.ts @@ -0,0 +1,33 @@ +import fs from "node:fs"; +import path from "node:path"; +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { ViteTestConfig } from "@prosopo/config"; +import dotenv from "dotenv"; +process.env.NODE_ENV = "test"; +// if .env.test exists at this level, use it, otherwise use the one at the root +const envFile = `.env.${process.env.NODE_ENV || "development"}`; +let envPath = envFile; +if (fs.existsSync(envFile)) { + envPath = path.resolve(envFile); +} else if (fs.existsSync(`../../${envFile}`)) { + envPath = path.resolve(`../../${envFile}`); +} else { + throw new Error(`No ${envFile} file found`); +} + +dotenv.config({ path: envPath }); + +export default ViteTestConfig(); + From 5cb4631d75bd93c814656ef13f019b8882b67721 Mon Sep 17 00:00:00 2001 From: George Oastler Date: Thu, 4 Dec 2025 14:10:18 +0000 Subject: [PATCH 4/5] lint --- package-lock.json | 335 ++++++++++++----------- packages/database/src/mongooseOptions.ts | 6 + 2 files changed, 185 insertions(+), 156 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63b02513ea..056f73766a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@prosopo/captcha", - "version": "3.5.16", + "version": "3.5.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@prosopo/captcha", - "version": "3.5.16", + "version": "3.5.17", "license": "Apache-2.0", "workspaces": [ "dev/*", @@ -71,6 +71,7 @@ "@polkadot/util": "13.5.7", "@polkadot/util-crypto": "13.5.7", "@prosopo/common": "3.1.27", + "@prosopo/database": "3.6.4", "@prosopo/dotenv": "3.0.32", "@prosopo/keyring": "2.8.43", "@prosopo/server": "2.9.51", @@ -643,17 +644,17 @@ } }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular-devkit/build-angular": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.12.tgz", - "integrity": "sha512-HPepPbJA5vprYTWJaSCfpk0s1bPT6Ui6VjFOSb9oY+p9iq+MGkuB1I+swNcRcMLttyMD+FpbMd27F8jSeX5XVw==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.13.tgz", + "integrity": "sha512-wEM5UHc37XGtH9FFVXZPwlZooccveL1VnFUbd2ArECGi4ylW+YgjeVSe0m6uJDvWOXULNVAoHlabXTXvmqV09A==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.12", - "@angular-devkit/build-webpack": "0.2003.12", - "@angular-devkit/core": "20.3.12", - "@angular/build": "20.3.12", + "@angular-devkit/architect": "0.2003.13", + "@angular-devkit/build-webpack": "0.2003.13", + "@angular-devkit/core": "20.3.13", + "@angular/build": "20.3.13", "@babel/core": "7.28.3", "@babel/generator": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", @@ -664,7 +665,7 @@ "@babel/preset-env": "7.28.3", "@babel/runtime": "7.28.3", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "20.3.12", + "@ngtools/webpack": "20.3.13", "ansi-colors": "4.1.3", "autoprefixer": "10.4.21", "babel-loader": "10.0.0", @@ -719,7 +720,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.12", + "@angular/ssr": "^20.3.13", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0 || ^30.2.0", @@ -776,14 +777,14 @@ } }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/build": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.12.tgz", - "integrity": "sha512-iAZve4VPviC8y6RFctyh3qFXSlP5mth9K46/0zasB4LV4pcmu8BrzIHERxIn/jCDNdVdPh973kxo1ksO4WpyuA==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.13.tgz", + "integrity": "sha512-/5pM3ZS+lLkZgA+n6TMmNV8I6t9Ow1C6Vkj6bXqWeOgFDH5LwnIEZFAKzEDBkCGos0m2gPKPcREcDD5tfp9h4g==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.12", + "@angular-devkit/architect": "0.2003.13", "@babel/core": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -825,7 +826,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.12", + "@angular/ssr": "^20.3.13", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^20.0.0", @@ -874,6 +875,18 @@ } } }, + "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/build/node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", @@ -887,13 +900,20 @@ "vite": "^6.0.0 || ^7.0.0" } }, + "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/build/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT", + "optional": true + }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/build/node_modules/vite": { "version": "7.1.11", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -981,9 +1001,9 @@ } }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/compiler-cli": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.14.tgz", - "integrity": "sha512-lFg9ikwRClzDPjdFiwynbVFIi1RJZf/0i+OHa3Ns2gzXxJeHNKMJrHHjWZ2DU4N2UpxH0YAPe22N9Bie28IuQQ==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.15.tgz", + "integrity": "sha512-8sJoxodxsfyZ8eJ5r6Bx7BCbazXYgsZ1+dE8t5u5rTQ6jNggwNtYEzkyReoD5xvP+MMtRkos3xpwq4rtFnpI6A==", "dev": true, "license": "MIT", "peer": true, @@ -1005,7 +1025,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.14", + "@angular/compiler": "20.3.15", "typescript": ">=5.8 <6.0" }, "peerDependenciesMeta": { @@ -1190,9 +1210,9 @@ } }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@ngtools/webpack": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.12.tgz", - "integrity": "sha512-ePuofHOtbgvEq2t+hcmL30s4q9HQ/nv9ABwpLiELdVIObcWUnrnizAvM7hujve/9CQL6gRCeEkxPLPS4ZrK9AQ==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.13.tgz", + "integrity": "sha512-7GyH55pOy8XUwo1lVWHzjZoAmSLtRT/vQbMn43x7WDl8pymAbi5zfwE/cnIX+5xgUOvkmT8sW9gJAD19rkASag==", "dev": true, "license": "MIT", "engines": { @@ -1212,7 +1232,6 @@ "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -2130,13 +2149,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2003.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.12.tgz", - "integrity": "sha512-5H40lAFF4CKY32C4HOp6bTlOF1f4WsGCwe7FjFQp9A+T7yoCBiHpIWt2JKTwV4sBoTKVDZOnuf0GG+UVKjQT4A==", + "version": "0.2003.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.13.tgz", + "integrity": "sha512-JyH6Af6PNC1IHJToColFk1RaXDU87mpPjz7M5sWDfn8bC+KBipw6dSdRkCEuw0D9HY1lZkC9EBV9k9GhpvHjCQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.12", + "@angular-devkit/core": "20.3.13", "rxjs": "7.8.2" }, "engines": { @@ -2146,13 +2165,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.2003.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.12.tgz", - "integrity": "sha512-IkhCU0nAsXYBQOfHu2gQBcYBKhaV1c8wYtu7MmelBcN/iUrG8hRf1sZx+ppUgsdZuBYxCiDiLpcfRVRCIASkvw==", + "version": "0.2003.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.13.tgz", + "integrity": "sha512-k57PdWOB64/u2MQYPylQNCKDSAHGsV0T2bvvZid2wfPJ7anvSUCU15OQMCMU1JMR0JENZEyIsLw9teShAO9w0Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.12", + "@angular-devkit/architect": "0.2003.13", "rxjs": "7.8.2" }, "engines": { @@ -2166,9 +2185,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.12.tgz", - "integrity": "sha512-ReFxd/UOoVDr3+kIUjmYILQZF89qg62POdY7a7OqBH7plmInFlYVSEDouJvGqj3LVCPiqTk2ZOSChbhS/eLxXA==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.13.tgz", + "integrity": "sha512-/D84T1Caxll3I2sRihPDR9UaWBhF50M+tAX15PdP6uSh/TxwAlLl9p7Rm1bD0mPjPercqaEKA+h9a9qLP16hug==", "dev": true, "license": "MIT", "dependencies": { @@ -2194,13 +2213,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.12.tgz", - "integrity": "sha512-JqJ1u59y+Ud51k/8MHYzSP+aQOeC2PJBaDmMnvqfWVaIt6n3x4gc/VtuhqhpJ0SKulbFuOWgAfI6QbPFrgUYQQ==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.13.tgz", + "integrity": "sha512-hdMKY4rUTko8xqeWYGnwwDYDomkeOoLsYsP6SdaHWK7hpGvzWsT6Q/aIv8J8NrCYkLu+M+5nLiKOooweUZu3GQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.12", + "@angular-devkit/core": "20.3.13", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "8.2.0", @@ -2213,19 +2232,19 @@ } }, "node_modules/@angular/cli": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.12.tgz", - "integrity": "sha512-vqVyVjbFPCRMjA5evL7tV2JeR6Anuzb9WcXTMB17fr7uzKNNAvo7KyRaOJjp+TU4JDARTNyGPy0aywfPx7R60A==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.13.tgz", + "integrity": "sha512-G78I/HDJULloS2LSqfUfbmBlhDCbcWujIRWfuMnGsRf82TyGA2OEPe3IA/F8MrJfeOzPQim2fMyn24MqHL40Vg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.12", - "@angular-devkit/core": "20.3.12", - "@angular-devkit/schematics": "20.3.12", + "@angular-devkit/architect": "0.2003.13", + "@angular-devkit/core": "20.3.13", + "@angular-devkit/schematics": "20.3.13", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", - "@modelcontextprotocol/sdk": "1.17.3", - "@schematics/angular": "20.3.12", + "@modelcontextprotocol/sdk": "1.24.0", + "@schematics/angular": "20.3.13", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", "ini": "5.0.0", @@ -2236,7 +2255,7 @@ "resolve": "1.22.10", "semver": "7.7.2", "yargs": "18.0.0", - "zod": "3.25.76" + "zod": "4.1.13" }, "bin": { "ng": "bin/ng.js" @@ -2266,9 +2285,9 @@ } }, "node_modules/@angular/cli/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "dev": true, "license": "MIT", "funding": { @@ -2276,9 +2295,9 @@ } }, "node_modules/@angular/common": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.14.tgz", - "integrity": "sha512-OOUvjTtnpktJLsNupA+GFT2q5zNocPdpOENA8aSrXvAheNybLjgi+otO3U3sQsvB1VwaoEZ9GT5O3lZlstnA/A==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.15.tgz", + "integrity": "sha512-k4mCXWRFiOHK3bUKfWkRQQ8KBPxW8TAJuKLYCsSHPCpMz6u0eA1F0VlrnOkZVKWPI792fOaEAWH2Y4PTaXlUHw==", "license": "MIT", "peer": true, "dependencies": { @@ -2288,14 +2307,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.14", + "@angular/core": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.14.tgz", - "integrity": "sha512-KFbfPPAbclzGDujCVruflCD9j4Zwwxvrg7Y4C9GJYs3LZ85t+BfIMDDnvpBUM07ZLnfY4TO4gQdHmJAcaGGXDQ==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.15.tgz", + "integrity": "sha512-lMicIAFAKZXa+BCZWs3soTjNQPZZXrF/WMVDinm8dQcggNarnDj4UmXgKSyXkkyqK5SLfnLsXVzrX6ndVT6z7A==", "devOptional": true, "license": "MIT", "peer": true, @@ -2307,9 +2326,9 @@ } }, "node_modules/@angular/core": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.14.tgz", - "integrity": "sha512-rpyEbhWF6Fj/xI9IvNLZh5QBUYnoXuF7vX54CCtyQ2MHALxRR/aa1WRxjRM96cF2OqodQ/Gj3oYW8ei8hlBh4w==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.15.tgz", + "integrity": "sha512-NMbX71SlTZIY9+rh/SPhRYFJU0pMJYW7z/TBD4lqiO+b0DTOIg1k7Pg9ydJGqSjFO1Z4dQaA6TteNuF99TJCNw==", "license": "MIT", "peer": true, "dependencies": { @@ -2319,7 +2338,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.14", + "@angular/compiler": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" }, @@ -2333,9 +2352,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.14.tgz", - "integrity": "sha512-Lviz9GfsIyOIBDal8QhIBKU8OMH29A0RhFw2opTC50sqKadXLN9CD7iSaAwQbNLc4mc3JAF4zth0AzKdHLbz7Q==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.15.tgz", + "integrity": "sha512-TxRM/wTW/oGXv/3/Iohn58yWoiYXOaeEnxSasiGNS1qhbkcKtR70xzxW6NjChBUYAixz2ERkLURkpx3pI8Q6Dw==", "license": "MIT", "peer": true, "dependencies": { @@ -2345,9 +2364,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.3.14", - "@angular/common": "20.3.14", - "@angular/core": "20.3.14" + "@angular/animations": "20.3.15", + "@angular/common": "20.3.15", + "@angular/core": "20.3.15" }, "peerDependenciesMeta": { "@angular/animations": { @@ -2356,9 +2375,9 @@ } }, "node_modules/@angular/router": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.14.tgz", - "integrity": "sha512-gi7/NuHRS9n9RCwh03VuVFizVMa2lKL/s+7yP3Ecq2nQ5uSeTMWb/91OmGEBwncI3wKPkYdQ9g3n6PvK/O8uDQ==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.15.tgz", + "integrity": "sha512-6+qgk8swGSoAu7ISSY//GatAyCP36hEvvUgvjbZgkXLLH9yUQxdo77ij05aJ5s0OyB25q/JkqS8VTY0z1yE9NQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -2367,9 +2386,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.14", - "@angular/core": "20.3.14", - "@angular/platform-browser": "20.3.14", + "@angular/common": "20.3.15", + "@angular/core": "20.3.15", + "@angular/platform-browser": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -7175,13 +7194,14 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz", - "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.24.0.tgz", + "integrity": "sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.6", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", @@ -7189,13 +7209,26 @@ "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } } }, "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { @@ -7212,23 +7245,6 @@ "node": ">= 0.6" } }, - "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", @@ -7297,20 +7313,21 @@ } }, "node_modules/@modelcontextprotocol/sdk/node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -7357,9 +7374,9 @@ } }, "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { @@ -7371,7 +7388,11 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { @@ -7384,13 +7405,6 @@ "node": ">= 0.8" } }, - "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -7522,9 +7536,9 @@ } }, "node_modules/@modelcontextprotocol/sdk/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "dev": true, "license": "MIT", "peer": true, @@ -12210,14 +12224,14 @@ } }, "node_modules/@schematics/angular": { - "version": "20.3.12", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.12.tgz", - "integrity": "sha512-ikl+nkWUab/Z4eSkBHgq9FLIUH8qh4OcYKeBQ0fyWqIUFHyjjK0JOfwmH1g/3zAmuUMtkthHCehAtyKzCTQjVA==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.13.tgz", + "integrity": "sha512-ETJ1budKmrkdxojo5QP6TPr6zQZYGxtWWf8NrX1cBIS851zPCmFkKyhSFLZsoksariYF/LP8ljvm8tlcIzt/XA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.12", - "@angular-devkit/schematics": "20.3.12", + "@angular-devkit/core": "20.3.13", + "@angular-devkit/schematics": "20.3.13", "jsonc-parser": "3.3.1" }, "engines": { @@ -12445,7 +12459,6 @@ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", @@ -14612,9 +14625,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.32", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz", - "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.0.tgz", + "integrity": "sha512-Mh++g+2LPfzZToywfE1BUzvZbfOY52Nil0rn9H1CPC5DJ7fX+Vir7nToBeoiSbB1zTNeGYbELEvJESujgGrzXw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -14987,9 +15000,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -15007,11 +15020,11 @@ "license": "MIT", "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -15324,9 +15337,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001757", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", - "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "version": "1.0.30001759", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", + "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", "funding": [ { "type": "opencollective", @@ -18002,9 +18015,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.262", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", - "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", + "version": "1.5.264", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.264.tgz", + "integrity": "sha512-1tEf0nLgltC3iy9wtlYDlQDc5Rg9lEKVjEmIHJ21rI9OcqkvD45K1oyNIRA4rR1z3LgJ7KeGzEBojVcV6m4qjA==", "license": "ISC" }, "node_modules/elliptic": { @@ -18580,9 +18593,9 @@ } }, "node_modules/esrap": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.0.tgz", - "integrity": "sha512-WBmtxe7R9C5mvL4n2le8nMUe4mD5V9oiK2vJpQ9I3y20ENPUomPcphBXE8D1x/Bm84oN1V+lOfgXxtqmxTp3Xg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.1.tgz", + "integrity": "sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -21814,6 +21827,16 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "license": "MIT" }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-cleanup": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/js-cleanup/-/js-cleanup-1.2.0.tgz", @@ -22040,12 +22063,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -22588,7 +22611,6 @@ "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -24115,9 +24137,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { @@ -29907,9 +29929,9 @@ } }, "node_modules/svelte": { - "version": "5.45.2", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.45.2.tgz", - "integrity": "sha512-yyXdW2u3H0H/zxxWoGwJoQlRgaSJLp+Vhktv12iRw2WRDlKqUPT54Fi0K/PkXqrdkcQ98aBazpy0AH4BCBVfoA==", + "version": "5.45.5", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.45.5.tgz", + "integrity": "sha512-2074U+vObO5Zs8/qhxtBwdi6ZXNIhEBTzNmUFjiZexLxTdt9vq96D/0pnQELl6YcpLMD7pZ2dhXKByfGS8SAdg==", "license": "MIT", "peer": true, "dependencies": { @@ -29923,7 +29945,7 @@ "clsx": "^2.1.1", "devalue": "^5.5.0", "esm-env": "^1.2.1", - "esrap": "^2.2.0", + "esrap": "^2.2.1", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", @@ -31120,9 +31142,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", + "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", "funding": [ { "type": "opencollective", @@ -33294,6 +33316,7 @@ "@vitest/coverage-v8": "3.2.4", "concurrently": "9.0.1", "del-cli": "6.0.0", + "dotenv": "16.4.5", "npm-run-all": "4.1.5", "tslib": "2.7.0", "tsx": "4.20.3", diff --git a/packages/database/src/mongooseOptions.ts b/packages/database/src/mongooseOptions.ts index b1313c7429..574e97e856 100644 --- a/packages/database/src/mongooseOptions.ts +++ b/packages/database/src/mongooseOptions.ts @@ -76,6 +76,9 @@ export interface MongoConnectionOptions extends Partial { maxIdleTimeMS: number; appName: string; serverSelectionTimeoutMS: number; + keepAlive: boolean; + keepAliveInitialDelay: number; + maxConnecting: number; compressors: ("zstd" | "none" | "snappy" | "zlib")[]; dbName?: string; } @@ -119,11 +122,14 @@ export const getMongoConnectionOptions = ( }, maxPoolSize, // allow up to N connections at any given time. >1 connection allows parallel db operations minPoolSize: 0, // allow pool to close idle connections down to this amount, 0 keep no connections open if they've been idle for longer than maxIdleTimeMS + maxConnecting: 2, // maximum number of concurrent connection attempts connectTimeoutMS: 10000, // max time to connect to the database socketTimeoutMS: 30000, // max time to wait for a response from the database when doing an operation maxIdleTimeMS: 300000, // max time spent idle before closing the connection appName, serverSelectionTimeoutMS: 20000, // max time to wait for a response from the database + keepAlive: true, // enable keep-alive + keepAliveInitialDelay: 120000, // initial delay before sending keep-alive probes (2 minutes) compressors, }; From 9fe3c063700e42010baf82fd84c4558c3c858dcb Mon Sep 17 00:00:00 2001 From: George Oastler Date: Thu, 4 Dec 2025 14:10:45 +0000 Subject: [PATCH 5/5] docs(changeset): make util fn for mongoose connection config, standardise mongoose connections --- .changeset/humble-lions-appear.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/humble-lions-appear.md diff --git a/.changeset/humble-lions-appear.md b/.changeset/humble-lions-appear.md new file mode 100644 index 0000000000..f4319b80ec --- /dev/null +++ b/.changeset/humble-lions-appear.md @@ -0,0 +1,7 @@ +--- +"@prosopo/client-example-server": patch +"@prosopo/database": patch +--- + +make util fn for mongoose connection config, standardise mongoose connections + \ No newline at end of file