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

@momentco-ai/moment-sdk

v0.4.0

Published

Embeddable calendar sync widget for external team websites

Readme

Moment SDK

Embeddable calendar sync widget for partner websites. Fans click a trigger on your site, pick Google Calendar or Outlook, and subscribe to games, lists, or full team schedules — without leaving your page.

Zero runtime dependencies. Works via a single <script> tag or npm import.

License: MIT npm version


What ships on npm

| Path | Format | Use case | | --------------------- | ----------------------- | --------------------------------------------------------------------- | | dist/moment-sdk.js | IIFE (UMD-style) | <script> tag — exposes MomentSdk and createMomentButton globals | | dist/moment-sdk.mjs | ESM | Bundler / import | | dist/types/ | TypeScript declarations | Type-safe integrations | | examples/ | Static HTML + CLI | Interactive demos (npx moment-sdk-examples) |

Pin a version in production (see Installation).


Installation

Script tag (recommended for partner sites)

Load from a public CDN and pin the version:

<script src="https://cdn.jsdelivr.net/npm/@momentco-ai/[email protected]"></script>

Alternatives:

<!-- unpkg -->
<script src="https://unpkg.com/@momentco-ai/[email protected]"></script>

npm / bundler

npm install @momentco-ai/moment-sdk
# or
pnpm add @momentco-ai/moment-sdk
import { MomentSdk, createMomentButton } from '@momentco-ai/moment-sdk';

const sdk = new MomentSdk({
  onSuccess: (result) => console.log('Synced!', result),
});

Quick start

Copy this into any page. Replace your-team-slug and your-event-slug with values provided by Moment.

<!-- 1. Trigger button -->
<button
  class="moment-sync-trigger"
  data-moment-team-slug="your-team-slug"
  data-moment-slug="your-event-slug"
  data-moment-trigger-type="moment"
>
  Add to Calendar
</button>

<!-- 2. Load SDK (pin version in production) -->
<script src="https://cdn.jsdelivr.net/npm/@momentco-ai/[email protected]"></script>
<script>
  const sdk = new MomentSdk({
    onSuccess: (result) => console.log('Synced!', result),
    onError: (result) => console.error('Failed', result),
    onClose: (result) => console.log('Closed', result),
  });
</script>

Clicking the button opens a modal where the fan selects Google Calendar or Outlook and completes OAuth in a popup. Your callbacks fire when sync succeeds, fails, or the modal closes.


Trigger types

Set data-moment-trigger-type (or triggerType in open() / createMomentButton()):

| Type | Required attributes | Subscribes to | | ------------------ | ------------------------------------------------------ | ----------------------------------------------------------------- | | moment (default) | data-moment-team-slug + data-moment-slug | One or more specific games/events | | list | data-moment-team-slug + data-moment-list-slug | A curated list of moments | | team | data-moment-team-slug | All published moments for the brand/team | | brand-playlist | data-moment-team-slug | The brand's default playlist (dynamic schedule thread) | | playlist | data-moment-team-slug + data-moment-playlist-slugs | One of several playlists (picker when >1 slug) | | schedule | data-moment-team-slug | Full schedule experience — user picks a mix of playlists + events |

For team, brand-playlist, and schedule, omit moment/list/ID and source-resolution attributes — only data-moment-team-slug is required.


Data attributes

Place these on any element matching the trigger selector (default: .moment-sync-trigger):

| Attribute | Required | Description | | ------------------------------- | -------------- | ------------------------------------------------------------------------------- | | data-moment-team-slug | Yes | Team/brand slug provided by Moment | | data-moment-slug | For moment | Brand-level moment slug (resolved server-side) | | data-moment-list-slug | For list | List slug | | data-moment-trigger-type | No | moment (default), list, team, brand-playlist, playlist, or schedule | | data-moment-playlist-slugs | For playlist | Comma-separated playlist slugs (picker shown when more than one) | | data-moment-ids | No | Comma-separated moment IDs (fallback if slugs don't resolve) | | data-moment-game-id | No | Alias for data-moment-ids | | data-moment-calendar | No | Pre-select provider: google or outlook | | data-api-source-id | No | Sync-subscription source ID (pairs with external id attributes) | | data-external-event-id | No | Exact external id (event_id:showing_id) resolved against source | | data-external-event-id-prefix | No | Upstream event id only — user picks a showing in the embed modal |

When data-api-source-id is set with either data-external-event-id (one showing) or data-external-event-id-prefix (all showings for an event), Live resolves moments server-side — useful when your CMS emits native event IDs instead of Moment slugs.


Init options

| Option | Type | Default | Description | | ----------------- | ------------------- | ---------------------- | ---------------------------------------------------- | | triggerSelector | string | .moment-sync-trigger | CSS selector for trigger elements | | onSuccess | (payload) => void | — | Called on successful calendar sync | | onError | (payload) => void | — | Called on sync failure | | onClose | (payload) => void | — | Called when modal closes (success, error, or cancel) | | onAnalytics | (event) => void | — | Called for every analytics event |


Programmatic API

Open the modal without data attributes:

const sdk = new MomentSdk({
  /* callbacks */
});

// Single moment
sdk.open({
  teamSlug: 'your-team-slug',
  momentSlug: 'your-event-slug',
  triggerType: 'moment',
});

// Source-based resolution (CMS event ID — single showing)
sdk.open({
  teamSlug: 'your-team-slug',
  triggerType: 'moment',
  apiSourceId: 'your-sync-source-id',
  externalEventId: '1420:2706',
});

// Source-based resolution (event with multiple showings — user picks date)
sdk.open({
  teamSlug: 'your-team-slug',
  triggerType: 'moment',
  apiSourceId: 'your-sync-source-id',
  externalEventIdPrefix: '1420',
});

// Follow full team schedule
sdk.open({
  teamSlug: 'your-team-slug',
  triggerType: 'team',
});

// Follow default playlist
sdk.open({
  teamSlug: 'your-team-slug',
  triggerType: 'brand-playlist',
});

sdk.close(); // Close modal
sdk.rebind(); // Re-bind triggers after dynamic DOM updates
sdk.destroy(); // Tear down instance

createMomentButton()

Build a trigger button in JavaScript:

const btn = createMomentButton({
  teamSlug: 'your-team-slug',
  momentSlug: 'your-event-slug',
  triggerType: 'moment',
  label: 'Add to Calendar',
  className: 'my-calendar-btn', // optional — partner CSS
});

document.getElementById('container').appendChild(btn);

The button gets the .moment-sync-trigger class and the correct data-moment-* attributes. Style it with your own CSS or rely on the SDK's minimal default button styles.

Styling

  • Trigger buttons — fully themeable on your page. The SDK injects minimal defaults via :where(.moment-sync-trigger) so your classes win.
  • Modal UI — hosted in a secure iframe on Moment Live; not styled by your page CSS.
<style>
  .my-calendar-btn {
    font-family: Inter, system-ui, sans-serif;
    font-weight: 600;
    border-radius: 9999px;
    padding: 10px 18px;
    background: #1d4ed8;
    color: #fff;
    border: none;
    cursor: pointer;
  }
</style>

Or use plain HTML triggers with your own classes:

<button
  class="my-calendar-btn moment-sync-trigger"
  data-moment-team-slug="your-team-slug"
  data-moment-slug="your-event-slug"
  data-moment-trigger-type="moment"
>
  Add This Game to My Calendar
</button>

Analytics events

The onAnalytics callback receives:

| Event | When | | --------------------- | ----------------------------------- | | embed.init | SDK initialized | | embed.trigger.click | User clicked a trigger | | embed.open | Modal opened | | oauth.start | OAuth popup requested | | oauth.popup.blocked | Browser blocked the popup | | oauth.popup.closed | User closed popup before completing | | subscribe.success | Calendar sync succeeded | | subscribe.error | Calendar sync failed | | embed.close | Modal closed |


Result payload

onSuccess, onError, and onClose receive:

{
  "source": "moment-live-embed",
  "type": "moment.embed.result",
  "result": "success",
  "provider": "google",
  "triggerType": "moment",
  "momentIds": ["..."],
  "message": "optional details"
}

result is one of success, error, cancelled, or partial (schedule trigger, when only some resources synced). provider is google, outlook, or apple when applicable. triggerType echoes the trigger (moment, list, team, brand-playlist, playlist, or schedule). For schedule, an optional counts: { requested, succeeded, failed } reports the aggregate outcome.


Integration patterns

Single game / event page

<button
  class="moment-sync-trigger"
  data-moment-team-slug="your-team-slug"
  data-moment-slug="your-moment-slug"
  data-moment-trigger-type="moment"
>
  Sync to Calendar
</button>

CMS with native event IDs

When Moment provides a sync-subscription source ID for your feed:

<button
  class="moment-sync-trigger"
  data-moment-team-slug="your-team-slug"
  data-moment-trigger-type="moment"
  data-api-source-id="your-source-id"
  data-external-event-id="0022400123"
>
  Sync to Calendar
</button>

Follow the full schedule

<button
  class="moment-sync-trigger"
  data-moment-team-slug="your-team-slug"
  data-moment-trigger-type="team"
>
  Sync Full Schedule
</button>

Dynamic buttons (SPA / React / Vue)

After rendering new trigger elements, call sdk.rebind() so click handlers attach to the new DOM nodes.


Examples playground

After installing the package, run the bundled demos (no repo clone required):

npx moment-sdk-examples

Opens http://localhost:5051 with moment, collection, and brand-schedule triggers wired to the sdk-demo fixture brand.

Repo maintainers: pnpm examples runs the same server from a local clone.

See examples/README.md for routes and fixture slugs.


Security

OAuth tokens never touch your site — authorization happens on Moment Live's backend. The SDK validates postMessage origin on every iframe and popup message.

See SECURITY.md for the full security model and vulnerability reporting.


Changelog

See CHANGELOG.md for version history and migration notes.


Support

License

MIT — Moment Co.