npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mohsinonxrm/dataverse-sdk-discovery

v1.0.0

Published

Global Discovery Service client for discovering Dataverse organizations across all regions in the Commercial cloud.

Readme

@mohsinonxrm/dataverse-sdk-discovery

Global Discovery Service client for discovering Dataverse organizations across all regions in the Commercial cloud.

Features

  • Multi-region discovery: Find organizations across all Dataverse regions (NA, EMEA, APAC, etc.)
  • Filtering support: Filter by state, region, or any organization property
  • Type-safe: Full TypeScript support with comprehensive types
  • OData queries: Use $filter, $select, and $orderby for precise queries
  • Helper methods: Convenient methods for common discovery scenarios

Installation

pnpm add @mohsinonxrm/dataverse-sdk-discovery @mohsinonxrm/dataverse-sdk-auth-msal-node

Quick Start

import { DiscoveryClient } from "@mohsinonxrm/dataverse-sdk-discovery";
import { MsalNodeTokenProvider } from "@mohsinonxrm/dataverse-sdk-auth-msal-node";

// Create token provider (using device code flow)
const tokenProvider = new MsalNodeTokenProvider({
  clientId: "your-client-id",
  authority: "https://login.microsoftonline.com/your-tenant-id",
  flow: "deviceCode",
});

// Create discovery client
const discovery = new DiscoveryClient(tokenProvider);

// List all organizations
const orgs = await discovery.listOrganizations();

console.log(`You have access to ${orgs.length} organizations`);
orgs.forEach((org) => {
  console.log(`${org.FriendlyName} (${org.UniqueName})`);
  console.log(`  Region: ${org.Geo}`);
  console.log(`  State: ${org.State}`);
  console.log(`  Web API: ${org.Endpoints.WebApiUrl}\n`);
});

Authentication Scopes

The Discovery Service requires the following scope:

const DISCOVERY_SCOPES = ["https://globaldisco.crm.dynamics.com/.default"];

This scope is automatically used by the DiscoveryClient when requesting tokens.

API Reference

DiscoveryClient

Constructor

new DiscoveryClient(tokenProvider: AccessTokenProvider, baseUrl?: string)

Parameters:

  • tokenProvider: An instance of a token provider (e.g., MsalNodeTokenProvider, MsalBrowserTokenProvider)
  • baseUrl (optional): Custom discovery endpoint. Defaults to Commercial cloud global discovery.

Example:

const discovery = new DiscoveryClient(tokenProvider);

Methods

listOrganizations(options?: DiscoveryOptions): Promise<OrganizationDetail[]>

Lists all Dataverse organizations the authenticated user has access to.

Parameters:

  • options.filter: OData filter expression (e.g., "State eq 'Enabled'")
  • options.select: Array of properties to return
  • options.orderby: Property to order results by

Examples:

// List all organizations
const allOrgs = await discovery.listOrganizations();

// Filter for enabled organizations only
const enabledOrgs = await discovery.listOrganizations({
  filter: "State eq 'Enabled'",
});

// Select specific properties
const basicInfo = await discovery.listOrganizations({
  select: ["UniqueName", "FriendlyName", "Geo", "Endpoints"],
});

// Order by friendly name
const orderedOrgs = await discovery.listOrganizations({
  orderby: "FriendlyName",
});

// Complex filter: Enabled North American organizations
const naEnabledOrgs = await discovery.listOrganizations({
  filter: "State eq 'Enabled' and Geo eq 'NA'",
});

getOrganization(uniqueName: string): Promise<OrganizationDetail | null>

Gets a specific organization by its unique name.

Parameters:

  • uniqueName: The unique name of the organization (e.g., 'contoso')

Returns: Organization detail if found, null otherwise

Example:

const org = await discovery.getOrganization("contoso");

if (org) {
  console.log(`Found: ${org.FriendlyName}`);
  console.log(`Web API: ${org.Endpoints.WebApiUrl}`);
  console.log(`Region: ${org.Geo}`);
} else {
  console.log("Organization not found");
}

getOrganizationsByRegion(geo: string): Promise<OrganizationDetail[]>

Gets all organizations in a specific geographic region.

Parameters:

  • geo: Geographic region code (e.g., 'NA', 'EMEA', 'APAC', 'SAM', 'OCE', 'JPN', 'IND', 'CAN', 'GCC', 'GCCHigh', 'DOD')

Common Region Codes:

  • NA - North America
  • EMEA - Europe, Middle East, and Africa
  • APAC - Asia Pacific
  • SAM - South America
  • OCE - Oceania
  • JPN - Japan
  • IND - India
  • CAN - Canada
  • GCC - US Government Community Cloud
  • GCCHigh - US Government Community Cloud High
  • DOD - US Department of Defense

Example:

// Get all North American organizations
const naOrgs = await discovery.getOrganizationsByRegion("NA");

// Get all European organizations
const emeaOrgs = await discovery.getOrganizationsByRegion("EMEA");

console.log(`Found ${naOrgs.length} organizations in North America`);
console.log(`Found ${emeaOrgs.length} organizations in EMEA`);

getEnabledOrganizations(): Promise<OrganizationDetail[]>

Gets all enabled organizations.

Example:

const enabledOrgs = await discovery.getEnabledOrganizations();

console.log(`You have access to ${enabledOrgs.length} enabled organizations`);

// Pick the first enabled organization
if (enabledOrgs.length > 0) {
  const org = enabledOrgs[0];
  console.log(`Using: ${org.FriendlyName}`);
  console.log(`Web API: ${org.Endpoints.WebApiUrl}`);
}

Types

OrganizationDetail

interface OrganizationDetail {
  Id: string; // Unique identifier
  UniqueName: string; // Unique name (e.g., 'contoso')
  FriendlyName: string; // Display name (e.g., 'Contoso Corporation')
  Endpoints: OrganizationEndpoints; // API endpoints
  State: string; // 'Enabled' or 'Disabled'
  Version: string; // Dataverse version
  UrlName: string; // URL name
  Geo: string; // Geographic region code
  TenantId: string; // Azure AD tenant ID
  EnvironmentId: string; // Environment ID
  Region: string; // Data center region code
}

OrganizationEndpoints

interface OrganizationEndpoints {
  WebApiUrl: string; // Web API endpoint (e.g., 'https://contoso.api.crm.dynamics.com')
  WebApplicationUrl: string; // Web app endpoint (e.g., 'https://contoso.crm.dynamics.com')
}

Complete Example: Interactive Organization Selector

import { DiscoveryClient } from "@mohsinonxrm/dataverse-sdk-discovery";
import { MsalNodeTokenProvider } from "@mohsinonxrm/dataverse-sdk-auth-msal-node";
import { DataverseClient } from "@mohsinonxrm/dataverse-sdk-core";

async function selectOrganization() {
  // Create token provider for discovery
  const tokenProvider = new MsalNodeTokenProvider({
    clientId: process.env.CLIENT_ID!,
    authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
    flow: "deviceCode",
  });

  // Create discovery client
  const discovery = new DiscoveryClient(tokenProvider);

  // Get all enabled organizations
  const orgs = await discovery.getEnabledOrganizations();

  if (orgs.length === 0) {
    console.log("No organizations found");
    return;
  }

  // Display organizations
  console.log("\nAvailable organizations:");
  orgs.forEach((org, index) => {
    console.log(`${index + 1}. ${org.FriendlyName} (${org.UniqueName}) - ${org.Geo}`);
  });

  // User selects organization (simplified - use readline in real app)
  const selectedIndex = 0; // First org for demo

  const selectedOrg = orgs[selectedIndex];
  console.log(`\nSelected: ${selectedOrg.FriendlyName}`);
  console.log(`Web API: ${selectedOrg.Endpoints.WebApiUrl}`);

  // Create Dataverse client for selected organization
  const client = new DataverseClient({
    baseUrl: selectedOrg.Endpoints.WebApiUrl,
    tokenProvider: tokenProvider,
  });

  // Now you can use the client with the selected organization
  const whoami = await client.api("/WhoAmI").get();
  console.log("User ID:", whoami.UserId);
}

selectOrganization().catch(console.error);

Error Handling

try {
  const orgs = await discovery.listOrganizations();
  console.log(`Found ${orgs.length} organizations`);
} catch (error) {
  if (error instanceof Error) {
    if (error.message.includes("401")) {
      console.error("Authentication failed. Check your credentials.");
    } else if (error.message.includes("403")) {
      console.error("Access denied. You may not have permission to use the discovery service.");
    } else {
      console.error("Discovery request failed:", error.message);
    }
  }
}

Related Packages

License

AGPL-3.0-only