Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 64 additions & 11 deletions .github/workflows/release-package.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,85 @@
name: Publish @epubknowledge/common package to Github Packages Registry
name: Publish @epubknowledge/common package
on:
push:
branches:
- main
release:
types:
- published
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- uses: actions/checkout@v4
# Setup .npmrc file to publish to GitHub Packages
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: 'https://npm.pkg.github.com'
always-auth: true
# Defaults to the user or organization that owns the workflow file
scope: '@epubknowledge'
- run: yarn install --frozen-lockfile
- name: Run Vitest and capture results
continue-on-error: true
run: yarn test --reporter=json --outputFile=.test-results.json
- name: Require 85% test pass rate
run: node .github/scripts/verify-test-pass-rate.mjs .test-results.json 85
- run: yarn publish
- name: Build package
run: npm run build
- name: Pack release artifact
id: pack
run: |
npm pack --json > pack-output.json
echo "filename=$(node -p 'JSON.parse(require(\"fs\").readFileSync(\"pack-output.json\", \"utf8\"))[0].filename')" >> "$GITHUB_OUTPUT"
- name: Verify packed dist assets
run: |
node -e "const pack = JSON.parse(require('fs').readFileSync('pack-output.json', 'utf8'))[0]; const files = pack.files.map(file => file.path); const hasJs = files.some(file => file.startsWith('dist/') && file.endsWith('.js')); const hasDts = files.some(file => file.startsWith('dist/') && file.endsWith('.d.ts')); if (!hasJs || !hasDts) { console.error('Packed tarball is missing compiled dist assets.'); process.exit(1); }"
- name: Consumer smoke test
run: |
tmp_dir="$(mktemp -d)"
npm init -y --prefix "$tmp_dir" >/dev/null
npm install --prefix "$tmp_dir" "$PWD/${{ steps.pack.outputs.filename }}" typescript
cat <<'EOF' > "$tmp_dir/runtime.mjs"
import { fileExists } from '@epubknowledge/common/file'

if (typeof fileExists !== 'function') {
throw new Error('Expected fileExists export to be a function.')
}
EOF
cat <<'EOF' > "$tmp_dir/types.mts"
import type { EpubObj } from '@epubknowledge/common/types'

const book: EpubObj | null = null
void book
EOF
cat <<'EOF' > "$tmp_dir/tsconfig.json"
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"noEmit": true
},
"include": ["types.mts"]
}
EOF
node "$tmp_dir/runtime.mjs"
(cd "$tmp_dir" && ./node_modules/.bin/tsc -p tsconfig.json)
- name: Set up npm registry auth
uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: 'https://registry.npmjs.org'
- name: Publish to npm
run: npm publish "${{ steps.pack.outputs.filename }}" --provenance --access public
- name: Set up GitHub Packages auth
uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: 'https://npm.pkg.github.com'
scope: '@epubknowledge'
- name: Publish to GitHub Packages
run: npm publish "${{ steps.pack.outputs.filename }}" --registry=https://npm.pkg.github.com
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 0 additions & 1 deletion .npmrc

This file was deleted.

74 changes: 22 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Shared runtime helpers for the Epub Knowledge package ecosystem.

## Install From NPM
## Install

After public testing is complete and this package is published to the public NPM registry, install it directly from NPM with no extra registry configuration or auth token:
This package is intended to be published to the public npm registry, so consuming repos can install it with no extra registry configuration or GitHub token:

pnpm:

Expand All @@ -26,71 +26,41 @@ npm install @epubknowledge/common

Requires Node.js `>= 22.0.0`.

## Install From GitHub Packages
## Publishing

This package is published to the GitHub Package Registry, so consuming repos must be configured to read the `@epubknowledge` scope from `https://npm.pkg.github.com`.
Maintainers publish this package to npm as the primary install target, and the release workflow mirrors the same version to GitHub Packages for authenticated consumers that still want it there.

### 1. Configure the registry
### Publish prerequisites

Add this to the consuming repo's `.npmrc`:
- The `@epubknowledge` scope must exist on npm and the publisher must have permission to publish under it.
- npm trusted publishing must be configured for the `release-package.yml` workflow on npmjs.com before CI publish will succeed.
- Local publishing uses `npm login`.
- GitHub Actions publishing uses GitHub OIDC trusted publishing for npm and the built-in `GITHUB_TOKEN` for the GitHub Packages mirror.

```ini
@epubknowledge:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
```
### Publish from CI

Commit the file, but never commit the token itself.

If the consuming repo uses Yarn Berry (`v2+`), add the equivalent to `.yarnrc.yml`:
The release workflow runs when a GitHub release is published or when it is started manually. Before any publish step, it runs tests, builds the package, verifies the tarball contains compiled `dist/*.js` and `dist/*.d.ts` assets, and smoke-tests a temporary consumer install for both runtime and type-only imports. It then publishes that tarball to `https://registry.npmjs.org` with provenance and mirrors the same tarball to `https://npm.pkg.github.com`.

```yaml
npmScopes:
epubknowledge:
npmRegistryServer: 'https://npm.pkg.github.com'
npmAuthToken: '${GITHUB_TOKEN}'
on:
release:
types: [published]
workflow_dispatch:
```

### 2. Provide a token

The token needs `read:packages`. If the org uses SSO, the token must also be authorized for `epubknowledge`.

Local development:
### Publish locally

```sh
export GITHUB_TOKEN=ghp_your_token_here
npm publish --access public
```

GitHub Actions:
### Optional GitHub Packages mirror install

```yaml
permissions:
contents: read
packages: read

steps:
- run: npm install
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### 3. Install the package

pnpm:
Most consumers should use the public npm install shown above. If a repo intentionally wants the GitHub Packages mirror instead, configure that consuming repo with:

```sh
pnpm add @epubknowledge/common
```

yarn:

```sh
yarn add @epubknowledge/common
```

npm:

```sh
npm install @epubknowledge/common
```ini
@epubknowledge:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
```

## Importing
Expand Down
14 changes: 7 additions & 7 deletions docs/importing.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
# Import Readiness Plan

This package is intended to be consumed from other repositories through GitHub Packages.
This package is intended to be consumed from other repositories through the public npm registry. The release workflow also mirrors the same package version to GitHub Packages for authenticated consumers that still depend on that registry.

## Completed In This Repo

- The build now emits `dist/` output instead of type-checking only.
- The package export map matches the documented subpath modules.
- The README now documents private-registry setup, supported import paths, and TypeScript usage.
- The release workflow now runs tests, builds the package, verifies packed `dist/*.js` and `dist/*.d.ts` assets, smoke-tests a temporary consumer install, publishes to npm with provenance, and mirrors the same tarball to GitHub Packages.
- The README documents public npm install usage, release-driven dual-registry publishing, supported import paths, and TypeScript usage.

## Remaining Checklist

1. Add a publish verification step in CI that runs `npm run build` and fails if `dist/` is missing.
2. Add a packaging smoke test that runs `npm pack` and verifies the tarball contains `dist/*.js` and `dist/*.d.ts`.
3. Add a consumer smoke test that installs the packed tarball into a temporary project and imports at least one runtime module plus one type-only module.
4. Publish a new package version to GitHub Packages after the packaging checks pass.
5. Verify install and import from a real consuming private repo using the README setup instructions.
1. Publish a new package version to npm and mirror it to GitHub Packages after the packaging checks pass.
2. Verify install and import from a real consuming repo with a plain `npm`, `pnpm`, or `yarn` install and no private-registry setup.
3. Optionally verify the GitHub Packages mirror from a repo that already has authenticated `@epubknowledge` registry access configured.

## TypeScript Notes

Expand All @@ -30,3 +29,4 @@ Optional follow-up:

- Add `typesVersions` if you need compatibility with older TypeScript package resolution behavior.
- Add a root barrel export if consumers should be able to write `import { ... } from '@epubknowledge/common'` instead of subpath imports.
- Add a local or CI check that fails early if the publishing account does not have access to the `@epubknowledge` npm scope.
17 changes: 12 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@
"engines": {
"node": ">=22.0.0"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com",
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/epubknowledge/common.git"
Expand Down Expand Up @@ -131,5 +127,16 @@
"types": "./dist/resetMemory.d.ts",
"import": "./dist/resetMemory.js"
}
}
},
"main": "index.js",
"directories": {
"doc": "docs"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/epubknowledge/common/issues"
},
"homepage": "https://github.com/epubknowledge/common#readme"
}
Loading