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

@pattern-stack/codegen-crm

v0.2.1

Published

L2 CRM surface package for @pattern-stack/codegen — type-shaped CRM ports (field/picklist/association readers) and DI tokens. See ADR-036.

Readme

@pattern-stack/codegen-crm

The L2 CRM surface package for @pattern-stack/codegen.

A surface package ships the type-shaped ports and DI tokens for one integration surface (here: CRM — account, contact, opportunity). The code generator emits an L3 composing port (CrmPort) that injects these ports; consumers implement them against a specific provider (Salesforce, HubSpot, …). The full rationale — why surface vocabulary lives in a per-surface package rather than in the codegen core — is in ADR-036 — Surface packages.

Layers

L1  @pattern-stack/codegen        — codegen subsystems (IChangeSource, registries)
L2  @pattern-stack/codegen-crm    — THIS PACKAGE: type-shaped CRM ports + tokens
L3  generated CrmPort             — composes the L2 ports (Track C · C6)
    consumer adapters             — implement the ports per provider

Exports

| Export | Kind | Since | |---|---|---| | IFieldDefinitionReader | port — lists a provider's CRM field definitions (standard + custom) | C1 (#330) | | CrmFieldDescriptor, CrmFieldType, CrmEntity | type vocab | C1 (#330) | | CRM_FIELD_DEFINITION_READER | DI token (Symbol.for) | C1 (#330) | | IPicklistReader, CrmPicklistValue | port — resolves picklist/multipicklist field values | C2 (#331) | | CRM_PICKLIST_READER | DI token (Symbol.for) | C2 (#331) | | IAssociationReader, CrmAssociation, CrmEntityType | port — reads cross-entity associations | C3 (#332) | | CRM_ASSOCIATION_READER | DI token (Symbol.for) | C3 (#332) | | CrmCapabilities, NO_CRM_CAPABILITIES | per-adapter capability descriptor | C4 (#333) | | CRM_CAPABILITIES | DI token (Symbol.for) | C4 (#333) | | CrmPort | L3 composing port — the contract an adapter implements (entity-agnostic) | C6 (#337) | | CRM_PORT | DI token (Symbol.for) | C6 (#337) | | assertCrmAdapter (from @pattern-stack/codegen-crm/testing) | conformance helper | C6 (#337) |

CrmEntityType (C3) is an alias of the canonical CrmEntity (C1) — the union 'account' | 'contact' | 'opportunity' has one source of truth; both names are exported.

import {
  IFieldDefinitionReader,
  CRM_FIELD_DEFINITION_READER,
  type CrmFieldDescriptor,
} from '@pattern-stack/codegen-crm';

This package ships ports only — no implementing classes. Implementations are consumer-side (e.g. pattern-stack/integration-patterns).

Declaring capabilities

An adapter declares which ports it implements and which entities it serves by spreading on top of NO_CRM_CAPABILITIES, and registers the descriptor under the CRM_CAPABILITIES token:

import {
  type CrmCapabilities,
  NO_CRM_CAPABILITIES,
  CRM_CAPABILITIES,
} from '@pattern-stack/codegen-crm';

export const HUBSPOT_CRM_CAPABILITIES: CrmCapabilities = {
  ...NO_CRM_CAPABILITIES,
  fieldDefinitions: true,
  picklists: true,
  associations: true,
  entities: ['account', 'contact', 'opportunity'],
};

// in the adapter's NestJS module:
// { provide: CRM_CAPABILITIES, useValue: HUBSPOT_CRM_CAPABILITIES }

A consumer queries capabilities at runtime to gate behaviour:

if (caps.fieldDefinitions && caps.entities.includes('lead')) {
  // safe to read custom fields for `lead` on this provider
}

entities is runtime coverage data, not a type bound on the L3 CrmPort — the port stays entity-agnostic (ADR-036 §6). C6's assertCrmAdapter() checks each declared entity has a registered changeSources entry.

The composing port — CrmPort

CrmPort is the single L3 contract a provider adapter implements. It composes L1 strategies (auth, the per-entity changeSources contributions) and the L2 ports (fields, picklists, associations) plus the runtime capabilities descriptor. It is entity-agnostic — no entity name appears in its type. The adapter contributes changeSources[entityName]; the surface aggregator folds every provider's contributions into the entity-keyed CRM_ENTITY_SOURCES registry that consumers read at runtime. Per-consumer typed views are codegen-emitted (Track D), not encoded here.

Conformance testing

@pattern-stack/codegen-crm/testing ships assertCrmAdapter — a structural check for adapter tests:

import { assertCrmAdapter } from '@pattern-stack/codegen-crm/testing';

it('hubspot adapter conforms to CrmPort', () => {
  assertCrmAdapter(hubspotCrmAdapter); // throws AggregateError listing every gap
});

It verifies required L1 slots resolve, that capabilities flags match the present ports, and that every capabilities.entities entry has a registered changeSources entry — so an adapter declaring an entity it can't source fails the test rather than failing at runtime.

Roadmap

  • Surface-only CrmPort methods — added only when a consumer feature drives one.
  • Track D D3/D4 — codegen-emitted adapter scaffolds + per-consumer typed views.

License

MIT