{"_rev":"6-dd342af7444ba1cab92152672d326430","time":{"created":"2026-05-27T05:55:14.378Z","modified":"2026-05-27T05:55:14.898Z","0.1.0":"2026-05-26T22:56:47.826Z","0.2.0":"2026-05-27T03:12:12.715Z","0.1.1":"2026-05-27T05:55:14.712Z"},"_id":"@ashwch/relay","name":"@ashwch/relay","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.1":{"name":"@ashwch/relay","version":"0.1.1","description":"Relay: CI-agnostic release finalization framework for teams with mixed release workflows.","license":"MIT","publishConfig":{"access":"public"},"type":"module","engines":{"node":"20.x"},"bin":{"relay":"dist/cli/main.js"},"exports":{"./plugin-sdk":{"types":"./dist/plugin-sdk/index.d.ts","import":"./dist/plugin-sdk/index.js"}},"scripts":{"build":"tsc -p tsconfig.json","clean":"rm -rf dist coverage","lint":"eslint .","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","action":"npm run build"},"dependencies":{"@actions/core":"^1.11.1","ajv":"^8.17.1","commander":"^14.0.0","semver":"^7.7.2","smol-toml":"^1.6.1","yaml":"^2.8.1"},"devDependencies":{"@eslint/js":"^9.39.1","@types/node":"^24.10.1","@types/semver":"^7.7.1","eslint":"^9.39.1","typescript":"^5.9.3","typescript-eslint":"^8.46.2","vitest":"^4.0.8"},"_id":"@ashwch/relay@0.1.1","gitHead":"6beb299bfc99b2244200a48de2a0f289feb0846f","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-ulX6iUnn8DLmS/ShEy+iL4nJ31qqkRodTGHs8r9bxg0Oscd8NZjy+HG5KOptgz6GZW7y44vym55MSQZISuV6ew==","shasum":"72b7f445c184cce37b85c7a7ebc19ecb1e42704e","tarball":"https://registry.npmjs.org/@ashwch/relay/-/relay-0.1.1.tgz","fileCount":151,"unpackedSize":554504,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC5uuiXkTTkiVbFFhoazoRELfGCmt18ojDubLzfAr/SjQIgAg4zouPwh/SeTRvshx2nl2Od0IJXtWLEI7B/nG2V5rc="}]},"_npmUser":{"name":"ashwch","email":"ashwch3018@gmail.com"},"directories":{},"maintainers":[{"name":"ashwch","email":"ashwch3018@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/relay_0.1.1_1779861314519_0.5456303787480545"},"_hasShrinkwrap":false}},"maintainers":[{"name":"ashwch","email":"ashwch3018@gmail.com"}],"description":"Relay: CI-agnostic release finalization framework for teams with mixed release workflows.","license":"MIT","readme":"# Relay\n\nRelay is a CI-agnostic release finalization framework.\n\nIt is designed for teams that use different build and release flows across repositories but still want one shared **last mile** for:\n\n- GitHub Release creation or observation\n- artifact/package verification\n- metadata enrichment\n- notifications\n\nRelay does **not** replace your CI pipeline or your release tool. It standardizes what happens after a release is ready.\n\n## What Relay does\n\nRelay takes release state from a provider, resolves release behavior from a profile, and runs a shared finalization flow.\n\n```text\nprovider -> normalize -> plan -> release record -> verify/publish -> enrich -> notify\n```\n\n## Core concepts\n\n- **Provider**: where the release run came from (`builtin:github-actions`, `builtin:circleci`, `builtin:generic-env`)\n- **Profile**: what “done” means for this repo (`deploy-release`, `semantic-release`, `asset-release`, etc.)\n- **Release mode**:\n  - `framework-managed` — Relay creates/updates the GitHub Release\n  - `tool-observe` — another tool owns the release record; Relay observes it\n  - `tool-wrap` — reserved, not implemented yet\n\n## Built-in support\n\n### Providers\n- GitHub Actions\n- CircleCI\n- generic env/manual invocation\n\n### Profiles\n- deploy-release\n- manual-release-pr\n- semantic-release\n- npm-package\n- asset-release\n- tag-only-module\n\n### Common extensions\n- Slack webhook notifications\n- GitHub Release asset verification\n- npm package visibility verification\n- PR metadata enrichment from GitHub/release notes\n\n### Version source options\n- date / date-sha / date-time\n- date-counter / backend-date-release\n- template / explicit\n- file / env / git-tag\n- conventional-commits / changesets\n\n`file` is the generic static file-backed option for JSON, YAML, and TOML\nversion files. It does not evaluate dynamic Python versioning, Cargo workspace\ninheritance, or Go module version rules.\n\n## Quick start\n\n### Requirements\n\n- Node.js 20.x\n- npm\n- `GITHUB_TOKEN` for real GitHub Release mutations\n- any plugin-specific secrets you configure, such as `SLACK_WEBHOOK_URL`\n\n### Install and build\n\n```bash\nnpm ci\nnpm run build\n```\n\nExamples below use `node dist/cli/main.js`, which works directly from this repo checkout. If you install Relay as a package, use the `relay` command instead.\n\n### Minimal config\n\nCreate `.github/relay.yml`:\n\n```yaml\napi_version: 1\nproduct_name: Example Web App\nrelease_profile: deploy-release\nrelease_mode: framework-managed\nprovider_plugin: builtin:github-actions\nprofile_plugin: builtin:deploy-release\nstable_branches:\n  - main\nversion_source:\n  type: date-sha\ntag_template: production-{date}-{short_sha}\nnotifiers:\n  - plugin: builtin:slack-webhook\nslack:\n  enabled: true\n  webhook_secret: SLACK_WEBHOOK_URL\n```\n\n### Inspect the resolved plan\n\n```bash\nnode dist/cli/main.js inspect-config --config .github/relay.yml\n```\n\n### Preview normalized release JSON\n\n```bash\nnode dist/cli/main.js normalize \\\n  --config .github/relay.yml \\\n  --provider builtin:generic-env \\\n  --repo ExampleOrg/web-app \\\n  --sha 9f3c1d2f5b1c9f7a8f4d2e1b0c6a5d4e3f2a1b0c \\\n  --branch main \\\n  --dry-run\n```\n\n### Finalize a real release\n\n```bash\nGITHUB_TOKEN=your-token \\\nSLACK_WEBHOOK_URL=https://hooks.slack.com/services/... \\\nnode dist/cli/main.js finalize --config .github/relay.yml\n```\n\n## CLI commands\n\nIf you are running from this repo checkout instead of an installed package, replace `relay` with `node dist/cli/main.js`.\n\n- `relay inspect-config` — validate config and show resolved plan\n- `relay normalize` — emit normalized release JSON\n- `relay finalize` — run the full finalization flow\n- `relay render-notification` — preview notifier output without sending\n- `relay list-plugins` — list built-in plugins\n- `relay validate-plugin` — validate a plugin manifest/config/runtime contract\n\n## GitHub usage\n\n### Composite action\n\n```yaml\n- uses: ashwch/relay/actions/release-finalize@v1\n  with:\n    config_path: .github/relay.yml\n```\n\n### Reusable workflow\n\n```yaml\njobs:\n  release:\n    uses: ashwch/relay/.github/workflows/release-finalize.yml@v1\n    with:\n      config_path: .github/relay.yml\n    secrets: inherit\n```\n\n## Plugins\n\nRelay supports built-in plugins and external plugins.\n\nExternal plugin refs are intentionally explicit:\n\n```text\nbuiltin:... -> code ships inside Relay\nnpm:...     -> code comes from an installed package\ngit:...     -> code comes from a Git repo checkout cached by Relay\npath:...    -> code comes from a local directory relative to relay.yml\n```\n\nWhy add `git:` support?\n\n```text\nbefore:\n  CI had to clone a plugin repo manually\n  then install that plugin manually\n  then point Relay at a local path\n\nafter:\n  relay.yml can point at the plugin repo directly\n```\n\nExample:\n\n```yaml\nplugin_allowlist:\n  - git:github.com/acme/relay-plugins//slack-notify@main\n\nnotifiers:\n  - plugin: git:github.com/acme/relay-plugins//slack-notify@main\n```\n\nIf the plugin needs plugin-local config, key it by the exact same full ref:\n\n```yaml\nplugin_config:\n  git:github.com/acme/relay-plugins//slack-notify@main:\n    channel: releases\n```\n\nRef format:\n\n```text\ngit:<host>/<owner>/<repo>//<optional/subdir>@<optional-ref>\n```\n\nExamples:\n\n```text\ngit:github.com/acme/relay-plugins//slack-notify@main\ngit:github.com/acme/relay-plugins//slack-notify@v1.2.3\ngit:github.com/acme/relay-plugins//slack-notify@9f3c1d2\ngit:github.com/acme/relay-plugins\n```\n\nThese are placeholder refs for documentation. Replace `acme/relay-plugins`\nwith a real reachable repository before running Relay against them.\n\nExternal plugins are still executed through the same small JSON contract over\nstdin/stdout after Relay resolves them to a plugin root. Use the plugin SDK for\nJavaScript/TypeScript plugins:\n\n- package export: `@ashwch/relay/plugin-sdk`\n- authoring guide: [`docs/plugin-authoring.md`](docs/plugin-authoring.md)\n- git ref guide: [`docs/git-plugin-refs.md`](docs/git-plugin-refs.md)\n- examples: [`examples/plugins/`](examples/plugins/)\n\n## Repository layout\n\n```text\nsrc/        TypeScript source\nactions/    GitHub Action wrapper\ndocs/       focused documentation\nexamples/   example configs and example plugins\nschemas/    JSON schemas\n```\n\n## Versioning examples\n\n- [`examples/version-package-json.yml`](examples/version-package-json.yml) — observe a static JSON version from `package.json`\n- [`examples/version-pyproject-toml.yml`](examples/version-pyproject-toml.yml) — observe a static Python version from `pyproject.toml`\n- [`examples/version-cargo-toml.yml`](examples/version-cargo-toml.yml) — observe a static Rust version from `Cargo.toml`\n- [`examples/version-custom-yaml.yml`](examples/version-custom-yaml.yml) — observe a static version from a custom YAML file\n- [`examples/version-env.yml`](examples/version-env.yml) — use a CI-provided version\n- [`examples/version-git-tag.yml`](examples/version-git-tag.yml) — derive from the current tag\n- [`examples/version-conventional-commits.yml`](examples/version-conventional-commits.yml) — infer semver from conventional commits\n- [`examples/version-changesets.yml`](examples/version-changesets.yml) — infer semver from pending Changesets\n\nFor full details, see [`docs/versioning.md`](docs/versioning.md).\n\n## Documentation map\n\n- [Config guide](docs/config.md)\n- [Runtime surfaces](docs/runtime-surfaces.md)\n- [Plugins overview](docs/plugins.md)\n- [Plugin authoring](docs/plugin-authoring.md)\n- [Finalize phases and notifications](docs/finalize-phases-and-notifications.md)\n- [Git plugin refs](docs/git-plugin-refs.md)\n- [Release records](docs/release-records.md)\n- [Types](docs/types.md)\n- [Versioning](docs/versioning.md)\n- [Validate plugin](docs/validate-plugin.md)\n- [Examples](examples/README.md)\n\n## Development\n\n```bash\nnpm run build\nnpm run lint\nnpm run typecheck\nnpm test\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}