@kurtbruns/kestrel 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dev.vars.example +5 -17
- package/CHANGELOG.md +26 -1
- package/README.md +1 -1
- package/dist/public/dashboard/app.js +196 -193
- package/dist/public/dashboard/app.js.map +4 -4
- package/dist/public/dashboard/index.html +2 -2
- package/dist/public/dashboard/styles.css +40 -0
- package/dist/worker/index.js +210 -69
- package/docs/README.md +3 -3
- package/docs/get-started/02-deploy.md +29 -13
- package/docs/get-started/03-access.md +3 -3
- package/docs/get-started/04-resend.md +8 -6
- package/docs/get-started/05-verify.md +2 -2
- package/docs/get-started/06-go-live.md +2 -2
- package/docs/guides/02-ses.md +2 -2
- package/docs/guides/08-try-locally.md +108 -0
- package/docs/reference/01-configuration.md +17 -6
- package/docs/reference/02-sending-domain-dns.md +1 -1
- package/package.json +2 -2
- package/template/wrangler.jsonc +7 -6
- package/docs/get-started/01-overview.md +0 -47
package/.dev.vars.example
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
# Copy to `.dev.vars` (gitignored) for local development
|
|
2
|
-
#
|
|
1
|
+
# Copy to `.dev.vars` (gitignored) for local development: `npm run dev` reads it, and
|
|
2
|
+
# nothing in it is ever deployed. It holds only what local development uses. A deployed
|
|
3
|
+
# environment's secrets (Access, and the email provider's keys) are stored with
|
|
4
|
+
# `npx wrangler secret put NAME --env production` instead; the Configuration reference
|
|
5
|
+
# (docs/reference/01-configuration.md) lists them. Restart `npm run dev` after a change.
|
|
3
6
|
|
|
4
7
|
# --- Admin API auth ---
|
|
5
8
|
# Local dev authenticates with a JWT signed by DEV_AUTH_SECRET (the app verifies it
|
|
@@ -10,21 +13,6 @@
|
|
|
10
13
|
# is the only gate.
|
|
11
14
|
DEV_AUTH_SECRET="dev-insecure-do-not-deploy"
|
|
12
15
|
|
|
13
|
-
# --- Cloudflare Access (JWT validation; the deployed gate — optional locally) ---
|
|
14
|
-
ACCESS_TEAM_DOMAIN="" # e.g. your-team.cloudflareaccess.com
|
|
15
|
-
ACCESS_AUD="" # the Access application's AUD tag
|
|
16
|
-
ACCESS_ALLOWED_EMAILS="" # optional CSV allowlist of human admin emails, e.g. you@example.com
|
|
17
|
-
|
|
18
|
-
# --- Amazon SES (SigV4 over HTTPS via aws4fetch) ---
|
|
19
|
-
AWS_ACCESS_KEY_ID=""
|
|
20
|
-
AWS_SECRET_ACCESS_KEY=""
|
|
21
|
-
SES_CONFIGURATION_SET="" # config set that publishes bounce/complaint to SNS
|
|
22
|
-
SNS_TOPIC_ARN="" # the topic the SES webhook accepts; every other topic is refused
|
|
23
|
-
|
|
24
|
-
# --- Resend (alternate transport) ---
|
|
25
|
-
RESEND_API_KEY=""
|
|
26
|
-
RESEND_WEBHOOK_SECRET="" # Svix signing secret for webhook verification
|
|
27
|
-
|
|
28
16
|
# --- Minimum lead ---
|
|
29
17
|
# How long every send stays visible and cancelable before it fires (docs/SPEC.md §6).
|
|
30
18
|
# Deployed environments default to 300 (five minutes); local dev uses the one-minute floor
|
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,30 @@ To move a running instance from one version to another, follow [Upgrade to a new
|
|
|
10
10
|
|
|
11
11
|
<!-- Add entries under Added / Changed / Fixed / Breaking. One operator-facing line each; see .claude/rules/changelog.md. Upgrade steps (a migration, a new setting) go once, in the Upgrading paragraph, never on an entry. -->
|
|
12
12
|
|
|
13
|
+
## [1.7.0] - 2026-10-12
|
|
14
|
+
|
|
15
|
+
**Upgrading from 1.6.0.** If your `production` block in `wrangler.jsonc` sets `PROVIDER` to `resend` or `ses`, nothing changes. If it still sets `fake` (as Get started's Deploy step set it until you connected a provider), delete that line before you deploy, so the instance runs with no provider connected rather than recording sends it never delivers, and [connect an email provider](docs/get-started/04-resend.md) when you're ready. If it sets no `PROVIDER` at all, the instance used to run on `fake` and now refuses to send; connect a provider first if it has readers. A send already scheduled on such an instance is held, with no one marked sent, until a provider is connected; it then goes out at its first retry after that, which may be long after its fire time, and it can't be canceled meanwhile, since it is already sending. A local development config that leaves `PROVIDER` unset needs `"PROVIDER": "fake"` in its top-level `vars`, as a new instance's has. If only one of the `ACCESS_TEAM_DOMAIN` and `ACCESS_AUD` secrets is stored (`npx wrangler secret list --env production` shows which), store the other before you deploy: this release refuses that configuration, and until both are stored its public pages say the newsletter is temporarily unavailable and nothing is sent. If any of `APP_ORIGIN`, `ARCHIVE_ORIGIN`, `MEDIA_PUBLIC_BASE`, `SENDING_DOMAIN`, or `FROM_ADDRESS` in your `production` block is still on `example.com` (the template's placeholder), replace it with your own before you deploy, whatever `PROVIDER` says: this release refuses it on every provider but `fake`, and until it's fixed the public pages say the newsletter is temporarily unavailable.
|
|
16
|
+
|
|
17
|
+
### Breaking
|
|
18
|
+
|
|
19
|
+
- An unset `PROVIDER` now means no email provider is connected, not the `fake` stand-in. Such a deployment runs, and refuses everything that would send with a 409 `provider_not_connected`: scheduling, send now, a test email, a test notification through the provider, and adding a subscriber; its public subscribe page says signups aren't open yet instead of taking an address it can't confirm. A send scheduled before is held, consuming no one, as a `refused` condition with the new cause `not_connected` and advice to connect a provider. `fake` now runs only where it is named, as local development and a demo do, and a new instance's production settings ship without `PROVIDER` until Get started's Connect an email provider step sets it (SPEC §9).
|
|
20
|
+
- A deployment with no email provider connected is now refused while any origin or sending setting is still on the template's `example.com` placeholder, as one with a real provider already was, so a missed edit shows at Deploy's check instead of at the provider step. Only `fake` may keep the example names (SPEC §9).
|
|
21
|
+
- A deployment with only one of `ACCESS_TEAM_DOMAIN` and `ACCESS_AUD` stored is now refused, naming the one that's missing, like any other configuration the app can't run on: its public pages say the newsletter is temporarily unavailable, and nothing is sent, until the other is stored. It used to keep serving readers and sending while the editor and Claude were locked out without saying why (SPEC §9).
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Reader pages, post pages included, show the publication's logo as the browser tab's icon when one is set; with no logo, the browser's default icon stays (SPEC §5).
|
|
26
|
+
- A setup guide, **Try Kestrel locally first**, runs a new instance locally with the demo publication, with no Cloudflare account or Git host, and shows how the folder becomes your instance's repository when you deploy.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- A new instance's `.dev.vars.example` holds only what local development uses (the local sign-in secret, the minimum lead, and the send simulation). The blank Access and email-provider entries are gone: they did nothing locally, and setting an Access value there turned local sign-in off. A deployed instance's secrets are listed in the Configuration reference.
|
|
31
|
+
- The setup guide's Overview page is folded into Deploy the app: what Get started needs is now Deploy's Before you begin, followed by choosing your hostnames. Get started is five steps, and Connect Resend, now step 3, is renamed Connect an email provider: it still walks through Resend, and points to the SES guide.
|
|
32
|
+
- While the configuration is refused, the public pages readers see answer a plain "temporarily unavailable" page (503) that names no setting, instead of the JSON error naming it; the API, `/health`, and the webhooks still answer `invalid_config` with the variable. The editor shows one page saying what's wrong, with a link to that setting in the Configuration reference, instead of failing call by call (SPEC §9).
|
|
33
|
+
- `auth.mode` in `/api/whoami`, and `authMode` in the Settings deployment reflection, now say how the request signed in (through Access, or with the local dev token), rather than whether Access is configured.
|
|
34
|
+
- The dashboard's first-run checklist orders its steps by what each needs first: name the publication, connect a provider (or confirm the sending domain), write the first post, then share the subscribe link. Writing used to come second, and starting a draft ends the checklist, so the steps after it were lost.
|
|
35
|
+
- While no email provider is connected, the editor says so wherever a send would be refused, each time with a "Connect an email provider" link to the setup step: the dashboard's health block and the Sent page carry an amber warning that nothing can be sent yet, the first-run checklist asks you to connect a provider in place of confirming the sending domain and says signups open once one is, Settings' Email provider row reads "No email provider connected" and its Ways to subscribe says signups aren't open yet, and the Send-a-test, Schedule, and Add subscriber dialogs say so in amber before you commit, with their act disabled and nothing to fill in (no recipients, time picker, Send now, or address), until a provider is set. A send held for want of a provider says no provider is connected, on its page, in the dashboard's attention line, and in the notification, rather than that the provider is refusing the account. Local development keeps its "nothing is delivered" wording.
|
|
36
|
+
|
|
13
37
|
## [1.6.0] - 2026-10-11
|
|
14
38
|
|
|
15
39
|
**Upgrading from 1.5.0.** One database migration: run `npm run sync-migrations`, then `npx wrangler d1 migrations apply DB --remote --env production` (and `--local` for local development) before deploying. Existing posts keep their slugs and read as set by hand; tick *Auto-generate from subject* on a draft to have its slug follow the subject again. On npm 12, to end `npm install` without the blocked-install-scripts warning, add this to your `package.json` (a new instance has it already): `"allowScripts": { "esbuild": true, "fsevents": true, "workerd": true }`.
|
|
@@ -287,7 +311,8 @@ The first tagged release: a self-contained newsletter app on a Cloudflare Worker
|
|
|
287
311
|
- A build-version stamp: every instance reports its version, commit, and build time, read-only in the editor and at `GET /api/version`.
|
|
288
312
|
- This changelog and a semantic-versioning release process.
|
|
289
313
|
|
|
290
|
-
[Unreleased]: https://github.com/kurtbruns/kestrel/compare/v1.
|
|
314
|
+
[Unreleased]: https://github.com/kurtbruns/kestrel/compare/v1.7.0...HEAD
|
|
315
|
+
[1.7.0]: https://github.com/kurtbruns/kestrel/releases/tag/v1.7.0
|
|
291
316
|
[1.6.0]: https://github.com/kurtbruns/kestrel/releases/tag/v1.6.0
|
|
292
317
|
[1.5.0]: https://github.com/kurtbruns/kestrel/releases/tag/v1.5.0
|
|
293
318
|
[1.4.0]: https://github.com/kurtbruns/kestrel/releases/tag/v1.4.0
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Kestrel installs from npm as [`@kurtbruns/kestrel`](https://www.npmjs.com/packag
|
|
|
12
12
|
npx @kurtbruns/kestrel init
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
[Get started](docs/get-started
|
|
15
|
+
To look around before you deploy, [Try Kestrel locally first](docs/guides/08-try-locally.md) runs it with demo content and no Cloudflare account. [Get started](docs/README.md#get-started) takes you from an empty repository to a live newsletter, and [Upgrade to a new release](docs/guides/07-upgrade.md) moves an instance to a newer one. The same guide is in the editor's **Docs** tab.
|
|
16
16
|
|
|
17
17
|
## Work on Kestrel
|
|
18
18
|
|