Skip to content

chore: switch to @mongodb-js/device-id #196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 8, 2025
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 eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default defineConfig([
"coverage",
"global.d.ts",
"eslint.config.js",
"jest.config.ts",
"jest.config.cjs",
"src/types/*.d.ts",
]),
eslintPluginPrettierRecommended,
Expand Down
2 changes: 1 addition & 1 deletion jest.config.ts → jest.config.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} **/
export default {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I ran into jestjs/jest#15312, possibly because of a TypeScript update, so just going to keep it as a .cjs file for the time being

module.exports = {
preset: "ts-jest/presets/default-esm",
testEnvironment: "node",
extensionsToTreatAsEsm: [".ts"],
Expand Down
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.8.0",
"@mongodb-js/device-id": "^0.2.1",
"@mongodb-js/devtools-connect": "^3.7.2",
"@mongosh/service-provider-node-driver": "^3.6.0",
"bson": "^6.10.3",
Expand Down
58 changes: 0 additions & 58 deletions src/helpers/deferred-promise.ts

This file was deleted.

56 changes: 20 additions & 36 deletions src/telemetry/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import logger, { LogId } from "../logger.js";
import { ApiClient } from "../common/atlas/apiClient.js";
import { MACHINE_METADATA } from "./constants.js";
import { EventCache } from "./eventCache.js";
import { createHmac } from "crypto";
import nodeMachineId from "node-machine-id";
import { DeferredPromise } from "../helpers/deferred-promise.js";
import { getDeviceId } from "@mongodb-js/device-id";

type EventResult = {
success: boolean;
Expand All @@ -19,7 +18,8 @@ export const DEVICE_ID_TIMEOUT = 3000;
export class Telemetry {
private isBufferingEvents: boolean = true;
/** Resolves when the device ID is retrieved or timeout occurs */
public deviceIdPromise: DeferredPromise<string> | undefined;
public deviceIdPromise: Promise<string> | undefined;
private deviceIdAbortController = new AbortController();
private eventCache: EventCache;
private getRawMachineId: () => Promise<string>;

Expand All @@ -39,7 +39,6 @@ export class Telemetry {
{
commonProperties = { ...MACHINE_METADATA },
eventCache = EventCache.getInstance(),

getRawMachineId = () => nodeMachineId.machineId(true),
}: {
eventCache?: EventCache;
Expand All @@ -57,50 +56,35 @@ export class Telemetry {
if (!this.isTelemetryEnabled()) {
return;
}
this.deviceIdPromise = DeferredPromise.fromPromise(this.getDeviceId(), {
timeout: DEVICE_ID_TIMEOUT,
onTimeout: (resolve) => {
resolve("unknown");
logger.debug(LogId.telemetryDeviceIdTimeout, "telemetry", "Device ID retrieval timed out");
this.deviceIdPromise = getDeviceId({
getMachineId: () => this.getRawMachineId(),
onError: (reason, error) => {
switch (reason) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

honestly seeing this used like this does make me think we should instead throw typed error objects and check instanceof as reason feels a bit redundant but this is fine

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I was debating between the two for a while - ended up going with a reason because that was more explicit about the possible values as opposed to Error inheritors, where you'd need to figure out what the options are.

case "resolutionError":
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
break;
case "timeout":
logger.debug(LogId.telemetryDeviceIdTimeout, "telemetry", "Device ID retrieval timed out");
break;
case "abort":
// No need to log in the case of aborts
break;
}
},
abortSignal: this.deviceIdAbortController.signal,
});

this.commonProperties.device_id = await this.deviceIdPromise;

this.isBufferingEvents = false;
}

public async close(): Promise<void> {
this.deviceIdPromise?.resolve("unknown");
this.deviceIdAbortController.abort();
this.isBufferingEvents = false;
await this.emitEvents(this.eventCache.getEvents());
}

/**
* @returns A hashed, unique identifier for the running device or `"unknown"` if not known.
*/
private async getDeviceId(): Promise<string> {
try {
if (this.commonProperties.device_id) {
return this.commonProperties.device_id;
}

const originalId: string = await this.getRawMachineId();

// Create a hashed format from the all uppercase version of the machine ID
// to match it exactly with the denisbrodbeck/machineid library that Atlas CLI uses.
const hmac = createHmac("sha256", originalId.toUpperCase());

/** This matches the message used to create the hashes in Atlas CLI */
const DEVICE_ID_HASH_MESSAGE = "atlascli";

hmac.update(DEVICE_ID_HASH_MESSAGE);
return hmac.digest("hex");
} catch (error) {
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
return "unknown";
}
}

/**
* Emits events through the telemetry pipeline
* @param events - The events to emit
Expand Down
72 changes: 0 additions & 72 deletions tests/unit/deferred-promise.test.ts

This file was deleted.

Loading