Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Description: Example of .env file

# MongoDB URI
MONGO_URI=mongodb://localhost:27017/your-database-name
MONGO_URI=mongodb://localhost:27017/example

# Auth Plugin
AUTH_DISCOVERY_URL=https://login.microsoftonline.com/c917f3e2-9322-4926-9bb3-daca730413ca/v2.0/.well-known/openid-configuration
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,6 @@ jobs:
with:
node-version: 24

- name: Remove existing MongoDB container
run: docker rm -f mongodb-actions || true

- uses: supercharge/mongodb-github-action@1.12.1
with:
mongodb-version: 7
mongodb-container-name: mongodb-actions

- run: |
corepack enable
corepack install
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"private": true,
"scripts": {
"dev": "fastify start --import=tsx --watch --log-level=debug --pretty-logs --options src/app.ts",
"test": "tsx --test --test-timeout=5000 --experimental-test-coverage test/**/*.test.ts",
"test": "tsx --test --experimental-test-coverage test/**/*.test.ts",
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test timeout flag (--test-timeout=5000) has been removed from the test script. With the MongoDB memory server being created per test, initialization could take longer than the default Node.js test timeout (30 seconds should be fine). However, if tests start failing due to timeout issues during MongoDB initialization, consider adding this flag back or increasing it. Monitor test execution times after this change.

Suggested change
"test": "tsx --test --experimental-test-coverage test/**/*.test.ts",
"test": "tsx --test --test-timeout=30000 --experimental-test-coverage test/**/*.test.ts",

Copilot uses AI. Check for mistakes.
"compile": "tsgo --noEmit && tsgo -p test/tsconfig.json --noEmit",
"lint": "eslint --fix .",
"lint:check": "eslint .",
Expand Down Expand Up @@ -53,7 +53,7 @@
"devDependencies": {
"@commitlint/cli": "^20.4.2",
"@commitlint/config-conventional": "^20.4.2",
"@eslint/js": "^10.0.1",
"@eslint/js": "^9.39.2",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^25.3.0",
Expand All @@ -62,6 +62,7 @@
"eslint-config-prettier": "^10.1.8",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"mongodb-memory-server": "11.0.1",
"prettier": "^3.8.1",
"prettier-plugin-jsdoc": "^1.8.0",
"rimraf": "^6.1.3",
Expand Down
12 changes: 3 additions & 9 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import packageJson from "../package.json" with { type: "json" };
import { AuthPluginOptions } from "./plugins/auth.js";
import { InitMongoPluginOptions } from "./plugins/init-mongo.js";
import AutoLoad, { AutoloadPluginOptions } from "@fastify/autoload";
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
import {
Expand All @@ -19,10 +20,9 @@ const __dirname = path.dirname(__filename);

export type AppOptions = {
// Place your custom options for app below here.
// MongoDB URI (Optional)
// mongoUri: string;
} & FastifyServerOptions &
Partial<AutoloadPluginOptions> &
InitMongoPluginOptions &
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AppOptions type includes InitMongoPluginOptions without making it optional (Partial wrapper). This means every consumer of AppOptions must provide a mongoUri, contradicting the PR's stated goal of optional MongoDB support. To align with the PR description, change this to: Partial<InitMongoPluginOptions> & AuthPluginOptions so that mongoUri becomes an optional field in AppOptions.

Suggested change
InitMongoPluginOptions &
Partial<InitMongoPluginOptions> &

Copilot uses AI. Check for mistakes.
AuthPluginOptions;

const missingOptions: string[] = [];
Expand Down Expand Up @@ -63,7 +63,7 @@ const options: AppOptions = {
// This increases the timeout for plugins to 5 minutes.
pluginTimeout: 5 * 60 * 1000,

// mongoUri: getOption("MONGO_URI")!,
mongoUri: getOption("MONGO_URI")!,
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mongoUri field is retrieved as required using getOption with the non-null assertion operator (!). However, based on the PR description stating MongoDB should be "optional", this should use getOption with required=false to allow undefined values. This should be: mongoUri: getOption("MONGO_URI", false) without the non-null assertion.

Copilot uses AI. Check for mistakes.
authDiscoveryURL: getOption("AUTH_DISCOVERY_URL")!,
authClientID: getOption("AUTH_CLIENT_ID")!,
authSkip: getBooleanOption("AUTH_SKIP", false),
Expand Down Expand Up @@ -138,12 +138,6 @@ const app: FastifyPluginAsync<AppOptions> = async (
await fastify.register(import("@fastify/swagger-ui"));
await fastify.register(import("@scalar/fastify-api-reference"));

// Register MongoDB (Optional)
// await fastify.register(import("@fastify/mongodb"), {
// url: opts.mongoUri,
// forceClose: true,
// });

// Do not touch the following lines

// This loads all plugins defined in plugins
Expand Down
33 changes: 20 additions & 13 deletions src/plugins/init-mongo.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import fp from "fastify-plugin";
import { Collection, Document } from "mongodb";

// import { Collection, Document } from "mongodb";

export type InitMongoPluginOptions = Record<never, unknown>;
export type InitMongoPluginOptions = {
// MongoDB URI
mongoUri: string;
};
Comment on lines +4 to +7
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description states "optional MongoDB support" and mentions "Registers @fastify/mongodb only when mongoUri is provided", but the implementation makes mongoUri a required field. The plugin unconditionally registers @fastify/mongodb without checking if mongoUri is provided. To make MongoDB truly optional, mongoUri should be optional in the type definition (mongoUri?: string), and the plugin should conditionally register based on whether the URI is provided. Consider adding a guard condition at the start of the plugin to skip registration when opts.mongoUri is undefined.

Copilot uses AI. Check for mistakes.

// The use of fastify-plugin is required to be able
// to export the decorators to the outer scope
export default fp<InitMongoPluginOptions>(async (fastify, opts) => {
await fastify.register(import("@fastify/mongodb"), {
url: opts.mongoUri,
forceClose: true,
});
fastify.addHook("onReady", async () => {
// Initialize the MongoDB database
// await fastify.mongo
// .db!.collection("example")
// .createIndex({ example: 1 });
fastify.decorate("collections", {
example: fastify.mongo.db!.collection("example"),
});
await fastify.collections.example.createIndex({ example: 1 });
Comment on lines 16 to +21
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plugin unconditionally decorates the fastify instance with collections and creates an index on the example collection. If MongoDB support becomes truly optional (as described in the PR), these operations should be conditional. When mongoUri is not provided, this will fail because fastify.mongo.db will be undefined. Add a guard to check if the MongoDB plugin was registered before decorating and creating indexes.

Copilot uses AI. Check for mistakes.
});
});

// declare module "fastify" {
// export interface FastifyInstance {
// collections: {
// example: Collection<Document>;
// };
// }
// }
declare module "fastify" {
export interface FastifyInstance {
collections: {
example: Collection<Document>;
};
}
}
26 changes: 17 additions & 9 deletions test/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This file contains code that we reuse between our tests.
import app, { AppOptions, options } from "../src/app.js";
import Fastify from "fastify";
import { MongoMemoryServer } from "mongodb-memory-server";
import * as test from "node:test";

export type TestContext = {
Expand All @@ -9,9 +10,9 @@ export type TestContext = {

// Fill in this config with all the configurations
// needed for testing the application
async function config(): Promise<AppOptions> {
async function config(mongoUri: string): Promise<AppOptions> {
return {
// mongoUri: "mongodb://localhost:27017",
mongoUri,
authDiscoveryURL: "",
authClientID: "",
authSkip: true,
Expand All @@ -20,17 +21,24 @@ async function config(): Promise<AppOptions> {

// Automatically build and tear down our instance
async function build(t: TestContext) {
const mongod = await MongoMemoryServer.create();
const fastify = Fastify({ pluginTimeout: options.pluginTimeout });
const appConfig = await config();
await fastify.register(app, appConfig);
await fastify.ready();

// Tear down our app after we are done
t.after(async () => {
const cleanup = async () => {
await fastify.close();
});
await mongod.stop();
};
t.after(cleanup);

return fastify;
try {
const appConfig = await config(mongod.getUri("example-test"));
await fastify.register(app, appConfig);
await fastify.ready();
return fastify;
} catch (error) {
await cleanup();
throw error;
}
}

export { config, build };
Loading