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
5 changes: 3 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@
"patterns": [
"**/../lib/**",
"mongodb-mock-server",
"node:*"
"node:*",
"os"
],
"paths": [
{
Expand Down Expand Up @@ -327,4 +328,4 @@
}
}
]
}
}
11 changes: 7 additions & 4 deletions src/cmap/auth/gssapi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as dns from 'dns';
import * as os from 'os';

import { getKerberos, type Kerberos, type KerberosClient } from '../../deps';
import { MongoInvalidArgumentError, MongoMissingCredentialsError } from '../../error';
Expand Down Expand Up @@ -69,9 +68,13 @@ export class GSSAPI extends AuthProvider {
}
}

async function makeKerberosClient(authContext: AuthContext): Promise<KerberosClient> {
const { hostAddress } = authContext.options;
const { credentials } = authContext;
async function makeKerberosClient({
options: {
hostAddress,
runtime: { os }
},
credentials
}: AuthContext): Promise<KerberosClient> {
if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
throw new MongoInvalidArgumentError(
'Connection must have host and port and credentials defined.'
Expand Down
3 changes: 3 additions & 0 deletions src/cmap/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { type MongoClientAuthProviders } from '../mongo_client_auth_providers';
import { MongoLoggableComponent, type MongoLogger, SeverityLevel } from '../mongo_logger';
import { type Abortable, type CancellationToken, TypedEventEmitter } from '../mongo_types';
import { ReadPreference, type ReadPreferenceLike } from '../read_preference';
import { type Runtime } from '../runtime_adapters';
import { ServerType } from '../sdam/common';
import { applySession, type ClientSession, updateSessionFromResponse } from '../sessions';
import { type TimeoutContext, TimeoutError } from '../timeout';
Expand Down Expand Up @@ -143,6 +144,8 @@ export interface ConnectionOptions
metadata: Promise<ClientMetadata>;
/** @internal */
mongoLogger?: MongoLogger | undefined;
/** @internal */
runtime: Runtime;
}

/** @public */
Expand Down
6 changes: 3 additions & 3 deletions src/cmap/handshake/client_metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as os from 'os';
import * as process from 'process';

import { BSON, type Document, Int32, NumberUtils } from '../../bson';
Expand Down Expand Up @@ -96,7 +95,8 @@ export class LimitedSizeDocument {
}
}

type MakeClientMetadataOptions = Pick<MongoOptions, 'appName'>;
type MakeClientMetadataOptions = Pick<MongoOptions, 'appName' | 'runtime'>;

/**
* From the specs:
* Implementors SHOULD cumulatively update fields in the following order until the document is under the size limit:
Expand All @@ -107,7 +107,7 @@ type MakeClientMetadataOptions = Pick<MongoOptions, 'appName'>;
*/
export async function makeClientMetadata(
driverInfoList: DriverInfo[],
{ appName = '' }: MakeClientMetadataOptions
{ appName = '', runtime: { os } }: MakeClientMetadataOptions
): Promise<ClientMetadata> {
const metadataDocument = new LimitedSizeDocument(512);

Expand Down
6 changes: 6 additions & 0 deletions src/connection_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { MongoLoggableComponent, MongoLogger, SeverityLevel } from './mongo_logger';
import { ReadConcern, type ReadConcernLevel } from './read_concern';
import { ReadPreference, type ReadPreferenceMode } from './read_preference';
import { resolveRuntimeAdapters } from './runtime_adapters';
import { ServerMonitoringMode } from './sdam/monitor';
import type { TagSet } from './sdam/server_description';
import {
Expand Down Expand Up @@ -538,6 +539,8 @@ export function parseOptions(
}
);

mongoOptions.runtime = resolveRuntimeAdapters(options);

return mongoOptions;
}

Expand Down Expand Up @@ -1061,6 +1064,9 @@ export const OPTIONS = {
default: true,
type: 'boolean'
},
runtimeAdapters: {
type: 'record'
},
serializeFunctions: {
type: 'boolean'
},
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ export type {
ReadPreferenceLikeOptions,
ReadPreferenceOptions
} from './read_preference';
export type { OsAdapter, Runtime, RuntimeAdapters } from './runtime_adapters';
export type { ClusterTime } from './sdam/common';
export type {
Monitor,
Expand Down
10 changes: 10 additions & 0 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { EndSessionsOperation } from './operations/end_sessions';
import { executeOperation } from './operations/execute_operation';
import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_concern';
import { ReadPreference, type ReadPreferenceMode } from './read_preference';
import { type Runtime, type RuntimeAdapters } from './runtime_adapters';
import type { ServerMonitoringMode } from './sdam/monitor';
import type { TagSet } from './sdam/server_description';
import { DeprioritizedServers, readPreferenceServerSelector } from './sdam/server_selection';
Expand Down Expand Up @@ -318,6 +319,12 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC
connectionType?: typeof Connection;
/** @internal */
__skipPingOnConnect?: boolean;
/**
* @experimental
*
* If provided, any adapters provided will be used in place of the corresponding Node.js module.
*/
runtimeAdapters?: RuntimeAdapters;
}

/** @public */
Expand Down Expand Up @@ -1152,4 +1159,7 @@ export interface MongoOptions
timeoutMS?: number;
/** @internal */
__skipPingOnConnect?: boolean;

/** @internal */
runtime: Runtime;
}
49 changes: 49 additions & 0 deletions src/runtime_adapters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable no-restricted-imports, @typescript-eslint/no-require-imports */

// We squash the restricted import errors here because we are using type-only imports, which
// do not impact the driver's actual runtime dependencies.
// We also allow restricted imports in this file, because we expect this file to be the only place actually importing restricted Node APIs.

import type * as os from 'os';

import { type MongoClientOptions } from './mongo_client';

/**
* @public
* @experimental
*
* Represents the set of dependencies that the driver uses from the [Node.js OS module](https://nodejs.org/api/os.html).
*/
export type OsAdapter = Pick<typeof os, 'release' | 'platform' | 'arch' | 'type'>;

/**
* @public
* @experimental
*
* This type represents the set of dependencies that the driver needs from the Javascript runtime in order to function.
*/
export interface RuntimeAdapters {
os?: OsAdapter;
}

/**
* @internal
*
* Represents a complete, parsed set of runtime adapters. After options parsing, all adapters
* are always present (either using the user's provided adapter, or defaulting to the Node.js module).
*/
export interface Runtime {
os: OsAdapter;
}

/**
* @internal
*
* Given a MongoClientOptions, this function resolves the set of runtime options, providing Nodejs implementations if
* not provided by in `options`, and returns a `Runtime`.
*/
export function resolveRuntimeAdapters(options: MongoClientOptions): Runtime {
return {
os: options.runtimeAdapters?.os ?? require('os')
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { LEGACY_HELLO_COMMAND } from '../../../src/constants';
import { Topology } from '../../../src/sdam/topology';
import { HostAddress, ns } from '../../../src/utils';
import * as mock from '../../tools/mongodb-mock/index';
import { processTick, sleep } from '../../tools/utils';
import { processTick, runtime, sleep } from '../../tools/utils';
import { assert as test, setupDatabase } from '../shared';

const commonConnectOptions = {
Expand All @@ -49,7 +49,10 @@ describe('Connection', function () {
...commonConnectOptions,
connectionType: Connection,
...this.configuration.options,
metadata: makeClientMetadata([], {})
metadata: makeClientMetadata([], {
runtime
}),
runtime
};

let conn;
Expand All @@ -71,7 +74,8 @@ describe('Connection', function () {
connectionType: Connection,
...this.configuration.options,
monitorCommands: true,
metadata: makeClientMetadata([], {})
runtime,
metadata: makeClientMetadata([], { runtime })
};

let conn;
Expand Down Expand Up @@ -102,7 +106,10 @@ describe('Connection', function () {
connectionType: Connection,
...this.configuration.options,
monitorCommands: true,
metadata: makeClientMetadata([], {})
runtime,
metadata: makeClientMetadata([], {
runtime
})
};

let conn;
Expand Down
7 changes: 7 additions & 0 deletions test/tools/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import {
type HostAddress,
MongoClient,
type MongoClientOptions,
type Runtime,
type ServerApiVersion,
type TopologyOptions
} from '../../src';
import { OP_MSG } from '../../src/cmap/wire_protocol/constants';
import { resolveRuntimeAdapters } from '../../src/runtime_adapters';
import { Topology } from '../../src/sdam/topology';
import { processTimeMS } from '../../src/utils';
import { type TestConfiguration } from './runner/config';
Expand Down Expand Up @@ -604,3 +606,8 @@ export function configureMongocryptdSpawnHooks(
port
};
}

/**
* A `Runtime` that resolves to entirely Nodejs modules, useful when tests must provide a default `runtime` object to an API.
*/
export const runtime: Runtime = resolveRuntimeAdapters({});
Comment thread
PavelSafronov marked this conversation as resolved.
9 changes: 8 additions & 1 deletion test/unit/assorted/optional_require.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { GSSAPI } from '../../../src/cmap/auth/gssapi';
import { compress } from '../../../src/cmap/wire_protocol/compression';
import { MongoMissingDependencyError } from '../../../src/error';
import { HostAddress } from '../../../src/utils';
import { runtime } from '../../tools/utils';

function moduleExistsSync(moduleName) {
return existsSync(resolve(__dirname, `../../../node_modules/${moduleName}`));
Expand Down Expand Up @@ -41,7 +42,13 @@ describe('optionalRequire', function () {
const gssapi = new GSSAPI();

const error = await gssapi
.auth(new AuthContext(null, true, { hostAddress: new HostAddress('a'), credentials: true }))
.auth(
new AuthContext(null, true, {
hostAddress: new HostAddress('a'),
credentials: true,
runtime
})
)
.then(
() => null,
e => e
Expand Down
19 changes: 15 additions & 4 deletions test/unit/cmap/connect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { CancellationToken } from '../../../src/mongo_types';
import { HostAddress, isHello } from '../../../src/utils';
import { genClusterTime } from '../../tools/common';
import * as mock from '../../tools/mongodb-mock/index';
import { runtime } from '../../tools/utils';

const CONNECT_DEFAULTS = {
id: 1,
Expand Down Expand Up @@ -210,7 +211,9 @@ describe('Connect Tests', function () {
connection: {},
options: {
...CONNECT_DEFAULTS,
metadata: makeClientMetadata([], {})
metadata: makeClientMetadata([], {
runtime
})
}
};
});
Expand Down Expand Up @@ -239,7 +242,10 @@ describe('Connect Tests', function () {
name: 's'.repeat(128)
}
],
{ appName: longAppName }
{
appName: longAppName,
runtime
}
);
const longAuthContext = {
connection: {},
Expand Down Expand Up @@ -267,7 +273,9 @@ describe('Connect Tests', function () {
connection: {},
options: {
...CONNECT_DEFAULTS,
metadata: makeClientMetadata([], {})
metadata: makeClientMetadata([], {
runtime
})
}
};
});
Expand Down Expand Up @@ -296,7 +304,10 @@ describe('Connect Tests', function () {
name: 's'.repeat(128)
}
],
{ appName: longAppName }
{
appName: longAppName,
runtime
}
);
const longAuthContext = {
connection: {},
Expand Down
Loading