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

@hubspot/quote-dev-sdk

v0.1.1

Published

TypeScript types for HubSpot Commerce Hub quote templates.

Readme

@hubspot/quote-dev-sdk

TypeScript types for developers building custom React modules for HubSpot Commerce Hub quote templates.

It exports QuoteTemplateContext and its member types. Use them to type the quote data you pipe from HubL into your React module so autocomplete works and typos on property names become compile errors instead of runtime blanks.

Install

npm install --save-dev @hubspot/quote-dev-sdk

Background

When HubSpot renders a Commerce Hub quote, the quote template has a quoteTemplateContext HubL variable in scope. It exposes a curated subset of HubSpot's built-in properties on the quote and its associated CRM records — already populated, with no API calls needed. The set of fields is fixed: custom properties defined on those records in your portal are not included. If your module needs custom properties — or built-in fields not exposed by quoteTemplateContext — fetch them server-side inside your hublDataTemplate using the crm_object and crm_associations HubL functions, then pipe the results through to your module.

To get that data into a React module, export a hublDataTemplate from the module. It's a HubL string that runs on the server; whatever object it builds becomes the hublData prop the React Component receives. This SDK types the shape of quoteTemplateContext so you can type both sides of that bridge against the same contract.

For the underlying framework — React modules, hublDataTemplate, and server-rendered hublData props — see the HubSpot developer docs: CMS React + HubL overview.

Example A — pass the whole context through

When a module needs broad access (totals, line items, contacts, signers), forward the whole quoteTemplateContext and type hublData with QuoteTemplateContext directly.

// src/cms-assets/my-react-assets/components/modules/QuoteSummary/index.tsx
import {
  ModuleFields,
  TextField,
} from '@hubspot/cms-components/fields';
import type { QuoteTemplateContext } from '@hubspot/quote-dev-sdk';

interface FieldValues {
  headline: string;
}

interface HublData {
  quoteContext: QuoteTemplateContext;
}

interface Props {
  fieldValues: FieldValues;
  hublData: HublData;
}

export function Component({ fieldValues, hublData }: Props) {
  const { quote, lineItems, signers } = hublData.quoteContext;

  const subtotal = lineItems.reduce<number>(
    (sum, item) => sum + (item.amount ?? 0),
    0,
  );

  return (
    <section>
      <h2>{fieldValues.headline}</h2>
      <p>
        {quote.hs_title} — {quote.hs_currency} {subtotal.toFixed(2)}
      </p>
      <ul>
        {signers.map((signer) => (
          <li key={signer.email}>
            {signer.firstName} {signer.lastName}
          </li>
        ))}
      </ul>
    </section>
  );
}

export const fields = (
  <ModuleFields>
    <TextField name="headline" label="Headline" default="Quote summary" />
  </ModuleFields>
);

export const meta = {
  label: 'Quote Summary',
  content_types: ['QUOTE', 'QUOTE_BLUEPRINT'],
};

export const hublDataTemplate = `
  {% set hublData = {
      "quoteContext": quoteTemplateContext
    }
  %}
`;

Example B — pass a slice and narrow the type

When a module only touches part of the context, pipe just that slice through HubL and use a TypeScript utility type (Pick, Omit, Partial, etc.) so the type on the React side matches exactly what you sent.

// src/cms-assets/my-react-assets/components/modules/ExpirationBanner/index.tsx
import {
  ModuleFields,
  TextField,
} from '@hubspot/cms-components/fields';
import type { QuoteTemplateContext } from '@hubspot/quote-dev-sdk';

interface FieldValues {
  headline: string;
}

interface HublData {
  quote: Pick<QuoteTemplateContext['quote'], 'hs_title'>;
  expirationDateFormatted: string;
}

interface Props {
  fieldValues: FieldValues;
  hublData: HublData;
}

export function Component({ fieldValues, hublData }: Props) {
  const { expirationDateFormatted, quote } = hublData;

  return (
    <aside>
      <h3>{fieldValues.headline}</h3>
      <p>
        {quote.hs_title} expires on {expirationDateFormatted}.
      </p>
    </aside>
  );
}

export const fields = (
  <ModuleFields>
    <TextField name="headline" label="Headline" default="Act before it expires" />
  </ModuleFields>
);

export const meta = {
  label: 'Expiration Banner',
  content_types: ['QUOTE', 'QUOTE_BLUEPRINT'],
};

export const hublDataTemplate = `
  {% set hublData = {
      "quote": {
        "hs_title": quoteTemplateContext.quote.hs_title
      },
      "expirationDateFormatted": quoteTemplateContext.quote.hs_expiration_date|format_date('long')
    }
  %}
`;

Other handy utility-type patterns:

import type { QuoteTemplateContext, LineItemProperties } from '@hubspot/quote-dev-sdk';

// Line items only.
type LineItemsOnly = Pick<QuoteTemplateContext, 'lineItems'>;

// Everything except documents.
type WithoutDocuments = Omit<QuoteTemplateContext, 'quoteDocuments'>;

// A specific line-item subset.
type BillingFields = Pick<
  LineItemProperties,
  'name' | 'amount' | 'hs_recurring_billing_period' | 'hs_term_in_months'
>;

Versioning

Follows semver. Adding optional fields is a minor release; adding a required field to QuoteTemplateContext or narrowing an existing field is a major release.

License

MIT