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
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
- [ ] I added a `.tegami/` release entry, or explained why this pull request uses `release:none`.
- [ ] I ran `nub run typecheck`, `nub run lint`, `nub run format`, and `nub run test`.
- [ ] I did not include credentials, private data, internal URLs, or organization-specific defaults.
- [ ] I did not change production deploys, npm publish, or paid spend.
- [ ] I did not change production deploys, registry publish, or paid spend.
94 changes: 87 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@ concurrency:

jobs:
release:
name: Version or publish npm packages
name: Version or release SolStatus
if: >-
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_repository.full_name == github.repository
runs-on: ubuntu-latest
timeout-minutes: 15
# Writes go through the release app token. This job's GITHUB_TOKEN stays read-only.
# id-token: write stays for the npm publish step.
permissions:
contents: read
id-token: write
outputs:
published: ${{ steps.published.outputs.published }}
tag: ${{ steps.published.outputs.tag }}
sha: ${{ steps.published.outputs.sha }}
steps:
# The app opens tegami/version-packages, so pull_request workflows start.
- name: Create release app token
Expand Down Expand Up @@ -60,13 +62,26 @@ jobs:
nub-version: 0.9.6
node-version-file: .nvmrc
cache-dependency-path: nub.lock
registry-url: "https://registry.npmjs.org"

- name: Install dependencies
run: nub install --frozen-lockfile

- name: Build
run: nub run build
# Only the version commit releases, so the registry package publishes only from it.
- name: Skip registry publish when the version tag exists
id: published
env:
GH_TOKEN: ${{ github.token }}
RELEASE_COMMIT: ${{ startsWith(github.event.workflow_run.head_commit.message, 'Version Packages') && github.event.workflow_run.head_commit.author.email == '341870119+solzero-bot[bot]@users.noreply.github.com' }}
run: |
set -euo pipefail
version="$(tr -d '[:space:]' < VERSION)"
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
if [ "$RELEASE_COMMIT" = "true" ] && [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && ! gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/v${version}" >/dev/null 2>&1; then
echo "tag=v${version}" >> "$GITHUB_OUTPUT"
echo "published=true" >> "$GITHUB_OUTPUT"
else
echo "published=false" >> "$GITHUB_OUTPUT"
fi

# Only the merge of the Tegami version pull request publishes, because only its Validate
# run tests the release. Another master push only opens or updates the version pull
Expand All @@ -80,5 +95,70 @@ jobs:
fi
env:
GITHUB_TOKEN: ${{ steps.release-token.outputs.token }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
RELEASE_COMMIT: ${{ startsWith(github.event.workflow_run.head_commit.message, 'Version Packages') && github.event.workflow_run.head_commit.author.email == '341870119+solzero-bot[bot]@users.noreply.github.com' }}

# The only job that requests id-token. The alchemy.new trusted publisher matches this
# repository, release.yml, the alchemy-new environment, and refs/heads/master.
registry:
name: Publish alchemy.new registry package
needs: release
if: needs.release.result == 'success' && needs.release.outputs.published == 'true'
runs-on: ubuntu-latest
timeout-minutes: 60
environment: alchemy-new
permissions:
contents: read
id-token: write
steps:
- name: Check out release commit
uses: actions/checkout@v7
with:
ref: ${{ needs.release.outputs.sha }}

- name: Set up Nub
uses: nubjs/setup-nub@v0
with:
nub-version: 0.9.6
node-version-file: .nvmrc
cache-dependency-path: nub.lock

- name: Install, build, and prune production dependencies
env:
# Nub's global virtual store symlinks node_modules/.store at a cache
# directory outside the repository. The publish action rejects those
# links. This install materializes the store inside the workspace.
NPM_CONFIG_ENABLE_GLOBAL_VIRTUAL_STORE: "false"
run: |
nub install --frozen-lockfile
nub run build
nub prune --prod

# Keep the exclude list identical to registry-dry-run.yml.
- name: Publish to alchemy.new
uses: SolZeroAI/alchemy-new-publish-action@v1
with:
version: ${{ needs.release.outputs.tag }}
exclude: |
**/*.md
**/*.map
node_modules/**/*.ts
node_modules/**/*.tsx
node_modules/**/*.mts
node_modules/**/*.cts
# Alchemy's Node export for this subpath is the TypeScript source.
!node_modules/**/alchemy/src/Runtime/Bootstrap/**
!node_modules/**/alchemy/src/Runtime/Bootstrap/**/*.ts
node_modules/.store/drizzle-kit@*
node_modules/.store/@electric-sql+*
node_modules/.store/workerd@*/node_modules/workerd/bin/workerd
# The 1.20261002.1 binary ships as @cloudflare/workerd-linux-64.
node_modules/.store/@cloudflare+workerd-linux-64@*/node_modules/@cloudflare/workerd-linux-64/bin/workerd
# esbuild's JavaScript API loads @esbuild/linux-x64. This path is a second copy.
node_modules/.store/esbuild@*/node_modules/esbuild/bin/esbuild
# TypeScript's native binary. Alchemy transpiles the stack with Oxc.
node_modules/.store/@typescript+typescript-linux-x64@*
# musl build of libsql. The deploy runner is glibc. D1 does not load libsql.
node_modules/.store/@libsql+linux-x64-musl@*
# Alchemy loads Cloudflare, not the GCP client.
node_modules/.store/@distilled.cloud+gcp@*
docs/dashboard-demo.gif
3 changes: 1 addition & 2 deletions .tegami/2026-10-02-drop-unused-uptime-orphans.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
packages:
"@solstatus/common":
type: major
"release:solstatus": patch
---

## Drop unused uptime check ID and patch schema
Expand Down
6 changes: 1 addition & 5 deletions .tegami/2026-10-19-alchemy-beta-83.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
---
packages:
solstatus: patch
"@solstatus/common": patch
"@solstatus/api": patch
"@solstatus/app": patch
"@solstatus/infra": patch
"release:solstatus": patch
---

## Bump Alchemy to 2.0.0-beta.83
Expand Down
6 changes: 1 addition & 5 deletions .tegami/2026-10-19-deps-patch.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
---
packages:
"solstatus": patch
"@solstatus/api": patch
"@solstatus/app": patch
"@solstatus/common": patch
"@solstatus/infra": patch
"release:solstatus": patch
---

### Update minor and patch dependencies
Expand Down
3 changes: 1 addition & 2 deletions .tegami/2026-10-20-harden-api-auth.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
packages:
"@solstatus/app": patch
"@solstatus/common": patch
"release:solstatus": patch
---

## Harden API authentication and query parameterization
Expand Down
3 changes: 1 addition & 2 deletions .tegami/2026-10-22-deps-dotenv-workers-recharts.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
packages:
solstatus: patch
"@solstatus/app": patch
"release:solstatus": patch
---

## Update dotenv and dashboard chart dependencies
Expand Down
4 changes: 1 addition & 3 deletions .tegami/2026-11-07-alchemy-dev-stack.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
packages:
"@solstatus/app": patch
"@solstatus/api": patch
"@solstatus/infra": patch
"release:solstatus": patch
---

## Run local development on the Alchemy dev stack
Expand Down
6 changes: 2 additions & 4 deletions .tegami/2026-11-07-effect-httpapi-tanstack-query.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
---
packages:
"@solstatus/app": minor
"@solstatus/api": patch
"@solstatus/common": patch
"release:solstatus": minor
---

## Serve the API with Effect HttpApi and load data with TanStack Query

The dashboard API is now an Effect `HttpApi` with typed requests, responses, and errors. Signed-in users can read the OpenAPI document at `/api/openapi.json` and the API docs at `/api/docs`. The dashboard loads and refreshes data with TanStack Query, and the list filters, sorting, paging, and the detail time range are kept in the URL.

`POST /api/endpoint-monitors/{id}/execute-check` replaces the `GET` form of that endpoint. The Zod schemas exported from `@solstatus/common/db` are removed; use the Drizzle row types `EndpointMonitorRow` and `EndpointMonitorPatch` from `@solstatus/common/db/schema`.
`POST /api/endpoint-monitors/{id}/execute-check` replaces the `GET` form of that endpoint.
2 changes: 1 addition & 1 deletion .tegami/2026-11-07-shared-lint-dashboard-renders.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
packages:
"@solstatus/app": patch
"release:solstatus": patch
---

## Dashboard renders follow the React Compiler rules
Expand Down
6 changes: 1 addition & 5 deletions .tegami/2026-11-07-solzeroai-repository.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
---
packages:
solstatus: patch
"@solstatus/app": patch
"@solstatus/api": patch
"@solstatus/common": patch
"@solstatus/infra": patch
"release:solstatus": patch
---

## Point package and app links at SolZeroAI/solstatus
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ A cloud-agent pull request that changes user-visible behavior must attach proof.

## Release management

- Follow `docs/releasing.md`. Add a Tegami release entry under `.tegami/` when a change has an observable effect on a published package.
- Follow `docs/releasing.md`. Add a Tegami release entry under `.tegami/` that targets `"release:solstatus"` when a change has an observable effect on a deployment. SolStatus publishes only to the alchemy.new registry. The workspace packages are private.
- Use the `release:none` label for a change with no observable effect, and explain that choice in the pull request.
- Do not edit `VERSION`, package versions, `CHANGELOG.md`, or `.tegami/publish-lock.yaml` on a feature branch. The automated version pull request owns those files.
- Do not edit `VERSION`, `CHANGELOG.md`, or `.tegami/publish-lock.yaml` on a feature branch. The automated version pull request owns those files.

## Architecture

Expand Down
15 changes: 2 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,5 @@ See the [infra README](./packages/infra/README.md#database-management) for more
### Dependency Management
Renovate opens dependency pull requests from the shared `SolZeroAI/renovate-config` preset and merges them when CI passes.

### npm Publishing
Tegami versions and publishes the npm packages after Validate succeeds on `master`:
- `solstatus` - Main CLI package
- `@solstatus/common` - Shared utilities and schemas
- `@solstatus/api` - API workers
- `@solstatus/app` - Web application
- `@solstatus/infra` - Infrastructure tools

See [docs/releasing.md](./docs/releasing.md). To enable npm publishing:
1. Create an npm access token at https://www.npmjs.com/
2. Add it as a GitHub secret named `NPM_TOKEN`
3. Enable **Allow GitHub Actions to create and approve pull requests**
4. Create the `release:none` label for toolchain-only pull requests
### Releases
Tegami versions SolStatus after Validate succeeds on `master`. Merging the version pull request tags `v<version>` and publishes that version to the [alchemy.new](https://alchemy.new) registry as `solzero/solstatus`, through GitHub OIDC trusted publishing. The workspace packages are private and are not published to npm. See [docs/releasing.md](./docs/releasing.md).
11 changes: 6 additions & 5 deletions alchemy.new.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
"name": "SolStatus",
"description": "Self host a low-cost, globally-distributed uptime monitoring service on Cloudflare.",
"publisher": {
"name": "SolStatus",
"github": "jonbeckman",
"name": "SolZero",
"github": "SolZeroAI",
"website": "https://solzero.dev",
},
"source": {
"kind": "registry",
"org": "jonbeckman",
"org": "solzero",
"project": "solstatus",
},
"deployment": {
Expand Down Expand Up @@ -42,8 +43,8 @@
{
"name": "BETTER_AUTH_SECRET",
"label": "Session signing secret",
"description": "Signs dashboard sessions. SolStatus reads BETTER_AUTH_SECRET when it deploys. Leave this empty to deploy; the worker then receives an empty secret.",
"required": false,
"description": "Signs dashboard sessions. Use a random value of at least 32 characters, for example the output of `openssl rand -hex 32`. Keep the same value on later deploys, or every session ends.",
"required": true,
"secret": true,
"type": "string",
},
Expand Down
Loading
Loading