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

@xrmforge/cli

v0.10.8

Published

CLI for XrmForge - TypeScript type generator for Dynamics 365

Readme

@xrmforge/cli

npm version license

The command-line entry point for XrmForge -- type-safe TypeScript for Dynamics 365 CE / Model-Driven Apps.

XrmForge reads your Dataverse metadata and generates TypeScript declarations that turn runtime errors into compile-time errors, so you catch typos, wrong types, missing fields, and bad action parameters before they reach production. This package provides the xrmforge command: scaffold a project, generate types, and build deployable Web Resources.

This is the CLI. It is the recommended starting point for most users. For the full framework documentation (concepts, deployment, debugging, troubleshooting), see the XrmForge repository on GitHub.


Installation

Global (gives you the xrmforge command everywhere):

npm install -g @xrmforge/cli

Or per project (recommended for reproducible CI builds; run it via npx xrmforge):

npm install --save-dev @xrmforge/cli @types/xrm typescript esbuild

Reproducible CLI version. After a local install, npx xrmforge ... runs the version pinned in your package.json. Avoid npx @xrmforge/cli@latest ... without a local install: npx caches the first download and may keep serving a stale version. For one-off runs, pin an exact version (npx @xrmforge/cli@<version> ...).

Requirements: Node.js 20 or higher.


Commands

The CLI exposes three commands:

| Command | Purpose | |---------|---------| | xrmforge init | Scaffold a new XrmForge project (tsconfig, build config, AGENT.md, example structure). | | xrmforge generate | Read Dataverse metadata and generate typed .ts declarations. | | xrmforge build | Bundle form scripts into IIFE Web Resources for D365 upload. |

Run xrmforge <command> --help for the full, authoritative flag list of any command.


xrmforge init

Scaffolds a ready-to-use project: tsconfig.json, xrmforge.config.json, an AGENT.md (instructions for AI coding assistants), a .gitignore, a .gitattributes pinning generated files to LF line endings, and an example source layout.

mkdir my-d365-project
cd my-d365-project
xrmforge init

Use --force to scaffold into a non-empty directory. Existing files are skipped (only the missing ones are written), so --force never overwrites your existing work.


xrmforge generate

Reads entity, form, OptionSet, and Custom API metadata from your environment and writes typed .ts files into the output directory.

xrmforge generate \
  --url https://myorg.crm4.dynamics.com \
  --auth interactive \
  --tenant-id YOUR_TENANT_ID \
  --client-id 51f81489-12ee-4a9e-aaae-a2591f45987d \
  --entities account,contact,opportunity \
  --output ./generated \
  --secondary-language 1031

The client ID above is Microsoft's well-known sample App ID, so no own App Registration is needed for interactive and device-code auth.

Frequently used flags:

| Flag | Description | Default | |------|-------------|---------| | --url <url> | Dataverse environment URL. Falls back to XRMFORGE_URL. | Required | | --auth <method> | interactive, client-credentials, device-code, or token. | Required | | --tenant-id <id> | Azure AD tenant ID. Falls back to XRMFORGE_TENANT_ID. | Required (most methods) | | --client-id <id> | Azure AD application (client) ID. Falls back to XRMFORGE_CLIENT_ID. | Required (most methods) | | --client-secret <secret> | Client secret (client-credentials). Prefer XRMFORGE_CLIENT_SECRET. | -- | | --token <token> | Pre-acquired Bearer token (token auth). Prefer XRMFORGE_TOKEN. | -- | | --entities <list> | Comma-separated entity logical names. | -- | | --solutions <list> | Comma-separated solution unique names (discovers all their entities). | -- | | --output <dir> | Output directory for generated files. | ./generated | | --label-language <code> | Primary label language LCID. | 1033 | | --secondary-language <code> | Secondary label LCID for dual-language JSDoc. | -- | | --actions | Generate typed Custom API Action/Function executors. | Off | | --actions-filter <prefix> | Filter Custom APIs by unique-name prefix. | -- | | --cache | Metadata caching for incremental generation (much faster reruns). | Off | | --check | Drift check: compare against output without writing. Exit 0/1/2. | Off | | -v, --verbose | Verbose/debug logging. | Off |

Either --entities or --solutions (or both) must be specified. Connection values also resolve from XRMFORGE_* environment variables and a local .env file, so secrets never need to appear on the command line.

Drift detection. xrmforge generate --check runs the full generation in memory and compares it byte-for-byte against the output directory without writing anything. Exit codes follow the terraform plan -detailed-exitcode convention: 0 = up to date, 1 = error, 2 = drift detected. Ideal as a nightly CI gate against silent metadata drift.


xrmforge build

Produces IIFE bundles (the format D365 needs for global form event binding) from a declarative build section in xrmforge.config.json -- no esbuild.config.js or build.mjs required.

// xrmforge.config.json
{
  "build": {
    "outDir": "./dist/contoso_/JS",
    "target": "es2020",
    "sourcemap": true,
    "minify": true,
    "entries": {
      "account_form": {
        "input": "./src/forms/account-form.ts",
        "namespace": "Contoso.AccountForm",
        "out": "Account/OnLoad.js"
      }
    }
  }
}
xrmforge build              # Build all entries (parallel IIFE bundles)
xrmforge build --watch      # Watch mode, ~10ms incremental rebuilds
xrmforge build --minify     # Override: minify output
xrmforge build --no-sourcemap

Bundling is powered by @xrmforge/devkit.


Five-minute quick start

# 1. Scaffold
mkdir my-d365-project && cd my-d365-project
npx xrmforge init

# 2. Generate types from your environment
npx xrmforge generate \
  --url https://myorg.crm4.dynamics.com \
  --auth interactive \
  --tenant-id YOUR_TENANT_ID \
  --client-id 51f81489-12ee-4a9e-aaae-a2591f45987d \
  --entities account,contact \
  --output ./generated

# 3. Type-check
npx tsc --noEmit

# 4. Build deployable Web Resources
npx xrmforge build

Then write a form script using the generated types:

import type { AccountMainFormTypeInfo } from '../../generated/forms/account.js';
import { typedForm } from '@xrmforge/helpers';

export function onLoad(executionContext: Xrm.Events.EventContext): void {
  const form = typedForm<AccountMainFormTypeInfo>(executionContext.getFormContext());
  if (!form.name.getValue()) {
    form.$context.ui.setFormNotification('Account name is required.', 'WARNING', 'name-warning');
  }
}

The XrmForge packages

@xrmforge/cli ties the framework together. The other packages can also be used on their own:

| Package | Role | |---------|------| | @xrmforge/typegen | Metadata reading and type-generation engine (used by generate). | | @xrmforge/helpers | Browser-safe runtime: select(), parseLookup(), typedForm(), Xrm constants, action executors. | | @xrmforge/webapi | Type-safe Xrm.WebApi client with a fluent query builder. | | @xrmforge/testing | Type-safe form-script mocks: createFormMock(), setupXrmMock(). | | @xrmforge/devkit | Build orchestration and scaffolding (used by build and init). | | @xrmforge/eslint-plugin | D365-specific ESLint rules. |


Documentation

Full guide -- authentication, Azure App Registration, generated-type patterns, building, deployment, debugging, troubleshooting -- lives in the main README on GitHub.

License

MIT (c) XrmForge Contributors.