This repository uses independent package versions, Changesets release pull requests, npm trusted publishing, and package-specific GitHub Releases.
| Directory | npm package | Status |
|---|---|---|
packages/imessage-sdk |
imessage-sdk |
Public |
packages/providers/blooio |
@imessage-sdk/blooio |
Public |
packages/providers/comms |
@imessage-sdk/comms |
Public |
packages/providers/photon |
@imessage-sdk/photon |
Public |
packages/providers/sendblue |
@imessage-sdk/sendblue |
Public |
packages/chat-adapter |
@imessage-sdk/chat-adapter |
Public |
packages/cli |
imessage-cli |
Public |
Install the declared Node.js and pnpm versions, then install dependencies:
corepack enable
pnpm install --frozen-lockfileLocal npm authentication is needed only when claiming a brand-new package name before its trusted publisher can be configured:
npm login
npm whoamiNormal releases run in GitHub Actions through OIDC and need neither a local
NPM_TOKEN nor a repository npm token.
- Create or confirm ownership of the
imessage-sdknpm organization. - Keep prereleases on the
betadist-tag. - Bootstrap a new package name manually before configuring OIDC for it.
- Configure trusted publishing separately for every public package.
A package's first prerelease may also receive latest as a consequence of npm
bootstrap. Its first stable release replaces that tag; no dist-tag removal is
required.
Create a fine-grained GitHub personal access token or GitHub App token with access to this repository and these permissions:
- Contents: read and write
- Pull requests: read and write
Store it under:
Repository Settings
→ Secrets and variables
→ Actions
→ New repository secret
→ CHANGESETS_TOKEN
The dedicated token lets the generated Version Packages pull request run CI without manual workflow approval.
Create this GitHub environment:
Repository Settings
→ Environments
→ New environment
→ npm-production
The current combined version-or-publish workflow uses this environment on
every push to main. Adding required reviewers therefore pauses both Version
Packages PR creation and actual publication. Leave it without required
reviewers initially unless that extra approval on every main push is desired.
Protect main, require pull requests, and require these CI checks:
- Node.js 20
- Node.js 22
- Node.js 24
- Package smoke test
- Verify changeset
The changeset check is intentionally skipped for changeset-release/*
branches because those files have already been converted into versions and
changelogs.
Configure trusted publishing separately in the settings for imessage-sdk,
@imessage-sdk/blooio, @imessage-sdk/comms, @imessage-sdk/photon,
@imessage-sdk/sendblue, @imessage-sdk/chat-adapter, and imessage-cli:
Provider: GitHub Actions
Organization or user: jmisilo
Repository: imessage-sdk
Workflow filename: release.yml
Environment: npm-production
Allowed action: npm publish
For the existing core package, replace the old publish.yml trusted publisher
configuration. Provider trusted publishing can only be configured after each
provider package has been bootstrapped on npm.
The release workflow pins Node.js 24 and installs npm 11 before publishing so the npm CLI supports OIDC trusted publishing.
After the first automated release succeeds, npm recommends requiring 2FA and disallowing traditional tokens in each package’s publishing-access settings.
npm cannot configure a trusted publisher for a package that does not exist. For the first version of a future provider or adapter:
- Merge its package and changeset through the normal reviewed PR flow.
- Review and merge the generated Version Packages pull request. The first
automated publish can fail with npm
E404because trusted publishing cannot be configured until the package exists. - Check out the resulting
maincommit, then build and pack the versioned package from that exact commit. - Inspect and publish the tarball locally under the intended dist-tag.
- Configure that package's npm trusted publisher.
- Backfill the matching Git tag and GitHub Release if automation did not create them. Mark the GitHub Release as a prerelease only for a prerelease version.
For example:
pnpm install --frozen-lockfile
pnpm lint
pnpm build
pnpm typecheck
pnpm test
pnpm package:check
PACKAGE_DIR=$(mktemp -d)
pnpm --filter @imessage-sdk/<provider> pack --pack-destination "$PACKAGE_DIR"
npm publish "$PACKAGE_DIR/<tarball>.tgz" --access public --provenance=falseFor the first imessage-cli beta, enter Changesets prerelease mode before the Version Packages
pull request is generated:
pnpm changeset pre enter betaAfter that pull request versions the package, bootstrap its exact tarball locally with --tag beta,
then configure imessage-cli as another trusted publisher using the settings above:
PACKAGE_DIR=$(mktemp -d)
pnpm --filter imessage-cli pack --pack-destination "$PACKAGE_DIR"
npm publish "$PACKAGE_DIR/imessage-cli-0.1.0-beta.0.tgz" \
--tag beta \
--access public \
--provenance=falseAdd --tag beta when bootstrapping a prerelease. For an initial stable provider release, use:
PACKAGE_DIR=$(mktemp -d)
pnpm --filter @imessage-sdk/<provider> pack --pack-destination "$PACKAGE_DIR"
npm publish "$PACKAGE_DIR/imessage-sdk-<provider>-0.1.0.tgz" \
--access public \
--provenance=falseDirect package publishing commands can incorrectly request provenance outside GitHub Actions. Publishing the already-built tarball avoids package-manager configuration leakage during this one-time bootstrap. All subsequent releases use OIDC automation.
For every pull request that changes a public package:
- Implement and verify the change.
- Run
pnpm changeset. - Select only affected public packages.
- Choose conventional SemVer: patch for fixes, minor for compatible features, major for breaking changes.
- Commit the generated
.changeset/*.mdfile with the code. - Open and merge the pull request after CI succeeds.
- Wait for Changesets to update the Version Packages pull request.
- Review generated versions, changelogs, and internal dependency ranges.
- Merge the Version Packages pull request when ready to release.
- Verify npm and GitHub Releases after automated publication.
Do not manually edit package versions during normal releases.
The release automation runs after every push to main, but a normal feature
merge and a Version Packages merge have different effects.
The pull request contains the implementation and, when a public package is
affected, one or more committed .changeset/*.md files. CI installs the frozen
lockfile, runs linting, builds, type-checks, tests, validates the changeset, and
checks packed public packages as real consumers would install them.
Nothing is published at this stage. Package versions and npm dist-tags remain unchanged.
The Release workflow starts because main received a push. Changesets sees
pending changeset files, so it opens or updates the Version Packages pull
request instead of publishing.
That generated pull request consumes the pending changesets and prepares:
- new versions for affected public packages;
- package changelog entries;
- compatible internal dependency range updates where required;
- removal of changeset files that have been incorporated.
Additional feature pull requests can be merged before releasing. Their changesets are accumulated into the same Version Packages pull request.
This is the release gate. Review the proposed versions, changelogs, internal dependency ranges, and CI results. Leaving this pull request open batches more changes; merging it authorizes publication of everything it currently contains.
Nothing has been published merely because the Version Packages pull request exists.
The merge creates another push to main, so the Release workflow runs again.
This time the version and changelog changes are already committed and there are
no pending changesets to turn into another release pull request. The workflow
runs pnpm release, which verifies the repository and asks Changesets to
publish package versions that are not yet present on npm.
The release command is self-contained: it lints, builds once, type-checks,
tests, and packs every public package. Each tarball must pass Publint, Are the
Types Wrong, strict TypeScript consumer compilation, and runtime import checks
before npm publication is invoked. Package-level prepack builds are omitted
so concurrent independent-package publication cannot race declaration builds.
npm authenticates the GitHub Actions job through trusted publishing with OIDC.
No repository NPM_TOKEN is used. Each changed package is published under the
dist-tag appropriate to the release mode:
- prerelease mode
betapublishes versions such as0.1.0-beta.1underbeta; - stable releases publish under
latest.
scripts/publish-packages.mjs reads .changeset/pre.json and explicitly
passes --tag beta while prerelease mode is active. It omits the tag in stable
mode, allowing npm's normal latest behavior. This keeps later beta cycles
from moving latest after a stable version exists.
Unchanged public packages are not republished.
After successful publication, the Changesets action creates package-specific
Git tags and GitHub Releases through the GitHub API. The
CHANGESETS_TOKEN authorizes the release pull request, commits, tags, and
GitHub Releases; OIDC separately authorizes npm publication.
For an independently versioned monorepo, a single release run can therefore produce several tags and releases, for example:
imessage-sdk@0.1.0-beta.1
@imessage-sdk/blooio@0.1.0-beta.1
Confirm that npm versions and dist-tags match the generated package versions:
npm view imessage-sdk version
npm dist-tag ls imessage-sdk
npm view @imessage-sdk/blooio version
npm dist-tag ls @imessage-sdk/blooio
npm view @imessage-sdk/sendblue version
npm dist-tag ls @imessage-sdk/sendblue
npm view imessage-cli@beta version
npm dist-tag ls imessage-cliThen install the release in a clean external project using @beta during the
prerelease period, or without a tag after a stable version owns latest.
Before opening a pull request, run:
pnpm format
pnpm lint
pnpm build
pnpm typecheck
pnpm test
pnpm package:check
pnpm changeset statusIf a package was initially published with a prerelease version without entering
Changesets prerelease mode, add a normal patch Changeset for that package. For
example, a patch release from 0.1.0-beta.3 resolves to stable 0.1.0. Review
that target in the Version Packages pull request before merging it. Stable
publication moves the package to npm’s latest tag.
If .changeset/pre.json exists because the repository is in Changesets
prerelease mode, leave that mode instead:
pnpm changeset pre exitBetas are optional. Ordinary fixes and backward-compatible features use the
regular Changesets flow and publish stable patch or minor versions directly to
latest. A beta is not required before every stable release.
Start another beta cycle only when a change benefits from prerelease testing:
pnpm changeset pre enter betaCommit the prerelease-state change through a reviewed pull request. While the
mode is active, generated versions use -beta.N and publish only to beta;
latest remains the last stable release. Promote the line back to stable with:
pnpm changeset pre exitAfter that change and the generated Version Packages pull request are merged,
the stable publication updates latest.
pnpm pack creates a .tgz tarball: the compressed archive that npm uploads
and consumers install. It contains the built JavaScript, declarations,
metadata, README, and license—not the entire repository.
CI and the publish command check each real tarball with:
- Publint, which validates package metadata, exports, file inclusion, and JavaScript/type entry-point consistency.
- Are the Types Wrong?, which validates TypeScript resolution under ESM and bundler module-resolution modes.
- A clean TypeScript consumer that installs the tarballs, imports every public package, and checks provider-specific generic inference.