Commit Graph

71 Commits

Author SHA1 Message Date
emdashbot[bot] 4c3edadeec ci: release (#2419)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-18 13:26:49 +01:00
emdashbot[bot] a891d73232 ci: release (#2350)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-11 15:49:52 +01:00
emdashbot[bot] 4255b04355 ci: release (#2244)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-06 00:24:20 +01:00
emdashbot[bot] 53dbf22555 ci: release (#2226) 2026-07-24 15:37:09 +01:00
emdashbot[bot] 09e5b5ca5b ci: release (#2176)
Auto Extract / Extract (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Version Check (push) Has been cancelled
CI / Changeset Validation (push) Has been cancelled
CI / Tests (push) Has been cancelled
CI / Smoke Tests (push) Has been cancelled
CI / Integration Tests (push) Has been cancelled
CI / Browser Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / E2E tests (1/8) (push) Has been cancelled
CI / E2E tests (2/8) (push) Has been cancelled
CI / E2E tests (3/8) (push) Has been cancelled
CI / E2E tests (4/8) (push) Has been cancelled
CI / E2E tests (5/8) (push) Has been cancelled
CI / E2E tests (6/8) (push) Has been cancelled
CI / E2E tests (7/8) (push) Has been cancelled
CI / E2E tests (8/8) (push) Has been cancelled
CI / E2E Cloudflare (1/8) (push) Has been cancelled
CI / E2E Cloudflare (2/8) (push) Has been cancelled
CI / E2E Cloudflare (3/8) (push) Has been cancelled
CI / E2E Cloudflare (4/8) (push) Has been cancelled
CI / E2E Cloudflare (5/8) (push) Has been cancelled
CI / E2E Cloudflare (6/8) (push) Has been cancelled
CI / E2E Cloudflare (7/8) (push) Has been cancelled
CI / E2E Cloudflare (8/8) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Format / Format (push) Has been cancelled
Preview Releases / Publish Preview (push) Has been cancelled
Release / Release (push) Has been cancelled
Release / Sync Templates (push) Has been cancelled
zizmor / Run zizmor (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-22 11:47:04 +00:00
emdashbot[bot] 3c555590ab ci: release (#1930)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-21 11:26:37 +01:00
jc e52dea9b72 feat(plugins): allow explicit MCP tool declarations (#2002)
* feat(plugins): add explicit MCP tool declarations

* fix(plugins): harden MCP request and consent handling

* fix(admin): send marketplace capability consent flag
2026-07-21 07:02:20 +01:00
Kevin Kyburz 82827d3f8f feat(backups): admin backups — one-click download and scheduled archives to storage (#1890)
* feat(backups): admin backups — one-click download and scheduled archives to storage

Adds a Backups page under admin settings: download a complete content
backup (all content including drafts and trash, schema, taxonomies,
menus, widgets, media metadata, site settings — never users or secrets),
plus optional daily automatic backups written to the site's storage
bucket with configurable retention. Scheduled runs piggyback on the
existing maintenance tick. New admin-only backups:manage permission.
The public media route now denies keys under backups/.

Ref: Discussion #142

* fix(backups): make archive listing work on LocalStorage, doc bucket-exposure caveat

LocalStorage.list matches directory + filename prefix rather than flat
keys, so include the emdash-backup- filename prefix in the list call.
Docs now warn that publicly exposed buckets serve archives by URL.

* chore: revert local typegen churn in demo

* refactor(backups): address review — Kumo tokens, central ErrorCode, localized dates

- Error/warning callouts use Kumo semantic tokens (DialogError,
  kumo-warning) instead of raw Tailwind colors and dark: prefixes
- Backup error codes registered in the central ErrorCode object and
  referenced from handler and routes
- Archive timestamps formatted through the active Lingui locale

* docs: drop the stacked note aside, keep the cron detail as body text
2026-07-11 13:58:18 +01:00
Afonso Jorge Ramos 4c57ee216f feat: accept invites via OAuth (Google/GitHub), not just passkeys (#1868)
* feat: accept invites via OAuth (Google/GitHub), not just passkeys

An invited user can complete their invite by signing in with a configured
OAuth provider. The invite token is carried through the OAuth state, and the
callback completes the invite (creating the user with the invited role and
linking the account) only when the provider-verified email matches the invited
address. The invite-accept page renders the configured providers under an
'Or continue with' divider.

* fix: consume invite token when linking existing account; distinct unverified-email error

Addresses review on #1868:
- acceptInviteViaOAuth now deletes the invite token in the existing-user and
  existing-account branches, preserving the single-use guarantee.
- Unverified provider email throws a new invite_email_unverified code with its
  own callback message, instead of the misleading email-mismatch message.

* fix: address review — linked-user email guard, invite-token validation, changeset

- acceptInviteViaOAuth: in the already-linked branch, require the linked user's
  email to match the invite before consuming, so an identity whose email changed
  after linking can't consume someone else's invite.
- oauth/[provider]: validate the ?invite= token shape/length before persisting
  to the (unauthenticated) OAuth state store.
- changeset: rewrite as a single user-facing sentence.

* ci: update query-count snapshots

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-07-10 22:14:28 +01:00
emdashbot[bot] baf4d8394f ci: release (#1871)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-10 17:29:37 +01:00
emdashbot[bot] c67e177b13 ci: release (#1856)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-07 19:01:37 +00:00
emdashbot[bot] 5f9a1ba769 ci: release (#1734)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-07 06:27:29 +01:00
emdashbot[bot] b291f1cc67 ci: release (#1700)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 07:32:03 +01:00
emdashbot[bot] 71a148db9f ci: release (#1677)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-01 17:08:52 +01:00
emdashbot[bot] bc9f1b6111 ci: release (#1668)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-30 15:30:39 +01:00
emdashbot[bot] e7552e0c44 ci: release (#1660)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-30 14:36:20 +01:00
emdashbot[bot] 761164105d ci: release (#1653)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-29 12:42:00 +00:00
emdashbot[bot] 647cfe4da0 ci: release (#1629)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-29 12:43:55 +01:00
emdashbot[bot] b66f697aa3 ci: release (#1592)
* ci: release

* format

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <m@mk.gg>
2026-06-25 19:35:58 +00:00
emdashbot[bot] 6b036c43d0 ci: release (#1534)
* ci: release

* format

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <m@mk.gg>
2026-06-22 20:23:36 +01:00
emdashbot[bot] 8b57af671c ci: release (#1516)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-17 20:42:46 +01:00
emdashbot[bot] 7f143184d9 ci: release (#1449)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-16 17:57:16 +01:00
emdashbot[bot] 0df001ea9d ci: release (#1418)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-12 20:43:46 +01:00
emdashbot[bot] 849628ff26 ci: release (#1360)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-11 20:46:32 +01:00
emdashbot[bot] 4fb27752e5 ci: release (#1354)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-05 12:14:08 +01:00
emdashbot[bot] a6e8a9185f ci: release (#1337)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-04 20:43:37 +01:00
emdashbot[bot] 73b5cf486c ci: release (#1283)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-03 23:41:53 +01:00
emdashbot[bot] d43a3808fb ci: release (#1280)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-01 23:06:13 +01:00
emdashbot[bot] 204b2f1931 ci: release (#1209)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-01 20:46:38 +01:00
emdashbot[bot] 139a4d5c96 ci: release (#1123)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-28 12:01:24 +01:00
Mohamed Hassan 11b300100e feat: bylines i18n support (#1146)
* feat: bylines i18n support

* chore: changeset

* chore: PR comments
2026-05-23 06:54:57 +01:00
Matt Kane 20c87fe924 chore: gate lint warnings in CI, clear the existing pile (#1147)
* fix(workerd): clear all lint warnings and tsgo errors

- Replace untyped `as T` casts in bridge dispatch with predicate-backed `require*`/`optional*` helpers
- Introduce `asContentDb()` for dynamic ec_* tables (single justified narrowing)
- Drop unnecessary `as keyof Database` casts for tables already in the static schema
- Validate marshaled RequestInit at the http/fetch boundary
- Typed HttpError class in backing-service for status-bearing errors
- getPluginStorageConfig now returns the real PluginStorageConfig shape
- WorkerdSandboxedPlugin implements SandboxedPluginInstance (the previous SandboxedPlugin symbol did not exist)
- Add typecheck script so the package participates in pnpm typecheck

No runtime behaviour changes.

* chore: bump oxlint and update disable-comment format

Upgrade oxlint (1.49 -> 1.66) and oxlint-tsgolint (0.15 -> 0.23). The
newer oxlint renamed the unused unicorn/prevent-abbreviations rule and
switched the canonical typescript-eslint plugin name to typescript,
which changes how inline disable comments are written.

Mechanical rename: `typescript-eslint(rule-name)` -> `typescript/rule-name`
in all eslint-disable comments. Without this, ~120 disable comments
stopped suppressing the rules they were meant to.

Also drops unicorn/prevent-abbreviations from .oxlintrc.json (no longer
a valid rule).

* ci: gate lint warnings so they cannot regress

`pnpm lint` now passes `--deny-warnings` to oxlint, so any warning is
a non-zero exit. CI inherits this through the existing lint job.

The blocker was the existing pile of warnings, so this commit also
clears them:

- `packages/core/src/astro/middleware.ts`: collapse duplicated
  `virtualSandboxRunnerModule as Record<...>` casts behind one local
  binding inside a block-form disable, and convert the remaining
  parenthesis-form disables that newer oxlint stopped recognising.
- `packages/core/src/astro/middleware/auth.ts` and 14 API route files:
  drop unnecessary `emdash!` non-null assertions; the preceding
  `requireDb(emdash?.db)` guard already narrows.
- `packages/core/src/emdash-runtime.ts`: drop unnecessary
  `as ResolvedPlugin[]` and `emdash!` casts; annotate the two
  remaining trusted dynamic-import sites with a single disable line.
- `packages/plugin-cli/src/build/pipeline.ts`: replace the chain of
  `as Record<string, unknown>` casts with `isRecord` /
  `isStringArray` predicate narrowing.
- `packages/cloudflare/src/sandbox/bridge.ts`: drop the
  `this.env.DB as D1Database` cast (already that type).
- `packages/core/src/client/index.ts`,
  `packages/core/src/astro/integration/index.ts`,
  `packages/registry-client/src/credentials/index.ts`: remove three
  unused imports.

Newer oxlint flagged config-level issues too:

- `packages/workerd/tsconfig.json`: add explicit `rootDir`.
- `packages/contentful-to-portable-text/tsconfig.json`: drop the
  `rootDir` that excluded `test/**/*` from `include`.
- `packages/core/src/page/absolute-url.ts`: fix the disable comment
  rule name so `no-control-regex` is suppressed (the regex
  intentionally matches control chars).
- `lunaria.config.ts`: convert block-form disable to next-line form
  with the new rule path.

Finally, four newer rules are disabled at the repo level:
`no-underscore-dangle` (Portable Text uses `_type`/`_key` by spec),
`typescript/consistent-return`, `typescript/no-unnecessary-type-conversion`,
`typescript/no-unnecessary-type-parameters`, and
`typescript/no-useless-default-assignment` (the rule errors out under
`strict: false`, which the test plugins use deliberately). These can
be re-enabled in follow-up PRs once their hits are triaged.
2026-05-22 15:25:38 +00:00
ask-bonk[bot] 88f544db4b Bump kysely to 0.29.0, fix 3 CVEs & imports (#1139)
* Bump kysely to 0.29.0, fix 3 CVEs & imports

Co-authored-by: ascorbic <ascorbic@users.noreply.github.com>

* fix(cloudflare): adapt D1Introspector to kysely 0.29 type changes

kysely 0.29 made two changes that broke our D1Introspector:

1. The 'DatabaseMetadata' type and getMetadata() method were removed from
   the DatabaseIntrospector interface. Drop the unused override (nothing in
   the workspace called it).

2. 'TableMetadata' now requires an 'isForeign: boolean' field. D1/SQLite
   has no concept of foreign tables (FDW), so emit 'isForeign: false' for
   every table.

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: ascorbic <ascorbic@users.noreply.github.com>
2026-05-22 12:03:31 +01:00
emdashbot[bot] 102535f308 ci: release (#1103)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-20 15:40:59 +01:00
emdashbot[bot] 361f0e27b4 ci: release (#1096)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-19 18:08:47 +01:00
Matt Kane ed917d9d53 chore: upgrade to TypeScript 6, pin tsgo beta, fix dual-load config (#1074)
- catalog typescript ^5.9.3 -> ^6.0.3 (current stable)
- pin @typescript/native-preview to 7.0.0-dev.20260421.2 (beta) to stop
  silent compiler drift from the floating ^7.0.0-dev range
- runtime.ts: key stored config on a Symbol.for registry entry instead of
  a typed globalThis var, removing the TS2403 dual-load (dist+src) error
  and matching the existing isolate-singleton pattern
- auth/create-emdash: add explicit types:[node]; the catalog bump's
  lockfile re-resolution stopped implicit @types/node auto-inclusion
2026-05-17 08:17:18 +00:00
Matt Kane 5681eb2e43 fix(deps): catalog-pin zod so trusted plugins typecheck (#1019)
Astro bundles its own Zod and re-exports it as 'astro/zod'. Trusted
plugins like @emdash-cms/plugin-forms import their route schemas via
'astro/zod', then pass those schemas to definePlugin() in core. With
emdash's 'zod: ^4.3.5' resolving independently of Astro's caret,
pnpm kept two Zod 4 patches in the tree (e.g. 4.3.6 alongside 4.4.1).

Zod 4 embeds its semver in the type system, so two patches of Zod 4
are not assignable to each other. The forms plugin's route schemas
(ZodObject<..., $strip>) were rejected by PluginRoute<TInput>['input']
(ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>) with
'Type "3" is not assignable to type "4"' on the internal version
field. The native definePlugin overload silently failed, TS fell
through to the StandardPluginDefinition overload, and reported a
misleading 'id does not exist' error -- masking 8 cascading errors.

Catalog-pinning Zod forces a single workspace-wide instance and
restores normal overload resolution. No code changes needed in core
or plugins/forms.

Also adds a pnpm-workspace.yaml comment explaining the gotcha so the
next person doesn't bump emdash's pin past Astro's range.
2026-05-13 22:17:45 +01:00
emdashbot[bot] 29eeee7c2a ci: release (#999)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-12 17:05:44 +01:00
emdashbot[bot] 356c52e0e2 ci: release (#992)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-11 15:17:29 +00:00
emdashbot[bot] b86ce9f73b ci: release (#925)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-11 10:06:15 +01:00
j-liszt f8ee1ed5e7 fix(auth): support RS256 algorithm for passkeys (#893)
* fix: support RS256 algorithm for Passkey authentication

* fix: address review feedback - forward-only migration and type safety

* style: format

* fix: address review feedback - forward-only migration, type safety, and error naming

* style: format

* fix: address review feedback - idempotent migration, type safety, and test fixes

* style: format

* fix: comprehensive review fixes - cross-dialect migration, integration test repair, and type safety

* fix: address reviewer feedback - improved migration robustness, regression tests for RS256, and polished error handling

* style: format

* fix: address maintainer feedback for RS256 passkey support

- Update CredentialTable type in core to include algorithm column
- Add robust RSA-2048 automated test for registration flow using BigInt representations
- Remove dead fallback code in Kysely adapter
- Clarify schema backwards compatibility in changeset

* style: format

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-05-07 06:55:29 +01:00
emdashbot[bot] 71ba0fbe25 ci: release (#892)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-06 11:44:22 +01:00
SeungMin Lee c8a3a2cce6 fix(core): permanent delete is missing trash guard and uses unrelated permission (#912)
* fix(core): gate permanent-delete route on content:delete_permanent

* fix(core): require deleted_at on permanent delete SQL

* chore: add changeset
2026-05-05 11:05:01 +01:00
emdashbot[bot] be5f05b08d ci: release (#806)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-01 16:58:59 +01:00
Matt Kane cee403d5c0 feat(core): add centralized secrets module and emdash secrets CLI (#811)
* feat(core): add centralized secrets module and emdash secrets CLI

PR 1 of secrets infrastructure work. Adds packages/core/src/config/secrets.ts
as the single source of truth for site-level cryptographic secrets, replacing
scattered import.meta.env reads at five route handlers.

- Preview HMAC secret and commenter-IP hash salt are now generated and
  persisted in the options table on first need. EMDASH_PREVIEW_SECRET
  and EMDASH_IP_SALT env vars are optional overrides.
- Replaces the empty-string fallback that silently disabled preview-token
  verification, and the hardcoded 'emdash-ip-salt' constant that was
  correlatable across installs.
- New 'emdash secrets generate' and 'emdash secrets fingerprint' CLI
  commands. Generates versioned 'emdash_enc_v1_*' keys with canonical
  base64url enforcement (kid derived from decoded bytes).
- 'emdash auth secret' kept as deprecated alias.
- create-emdash scaffolds EMDASH_ENCRYPTION_KEY into .dev.vars or .env
  on project creation, idempotently.
- Template gitignores updated for .dev.vars and .env*.
- Lays groundwork for plugin-secret encryption-at-rest in a follow-up.

* docs: rewrite encryption-key copy without contributor jargon

The user-facing docs talked about 'PR 1', 'follow-up', and 'forthcoming
release' — meaningless to readers who aren't tracking the project's
internal sequencing. Reworded to plain user-facing language: the env
var is validated today, not yet used to encrypt anything, will start
being used automatically when plugin secret encryption rolls out.

* fix(core): address PR #811 review findings

- Decouple EMDASH_ENCRYPTION_KEY parse from resolveSecrets so a malformed
  value can no longer 500 preview/comment hot paths for anonymous
  visitors. Startup validation in EmDashRuntime.create surfaces
  misconfiguration in startup logs instead.
- Enforce canonical base64url in fingerprintKey, matching
  parseEncryptionKeys, so the CLI cannot print kids the runtime would
  later refuse to load.
- Replace bespoke SHA-256 + hex encoding in fingerprintKeyBytes with
  @oslojs/crypto and @oslojs/encoding. Add the family to the workspace
  catalog and switch packages/auth + packages/core to catalog refs.
- Fix kid doc comment ("raw key string" was wrong, kid is derived from
  decoded bytes).
- Rephrase "per-deployment" wording in changeset, snapshot.ts, and
  themes/preview.ts to "per-database" — auto-generated values converge
  across processes that share the DB.
- Drop "validates and stores" in deployment docs (we validate; we don't
  store the plaintext key).
2026-04-29 06:45:07 +00:00
Cesar S Falcão e2d5d160ac fix(auth,core): accept multiple origins for passkey verification (#800)
* fix(auth,core): accept multiple origins for passkey verification

Closes #799

PasskeyConfig.origin (single string) becomes origins (string[]); register
and authenticate verify against the list via .includes(). getPasskeyConfig
takes an optional allowedOrigins 4th argument; verify routes pass the
parsed contents of EMDASH_ALLOWED_ORIGINS.

This unblocks deployments where one EmDash instance is reachable under
several hostnames sharing a registrable parent (apex + preview/staging),
which WebAuthn supports via shared rpId but EmDash previously rejected
with a strict origin-equality check.

* fix(auth,core): validate multi-origin passkey config (V2 review)

Addresses review feedback on PR #800:

- Add EmDashConfig.allowedOrigins config field as a parallel to siteUrl
  (maintainer ascorbic: "Can we do the same as siteUrl and allow passing
  the value in config too").
- Validate the merged effective set (config + EMDASH_ALLOWED_ORIGINS) at
  the runtime chokepoint in 5 verify routes. Validation throws loud,
  source-attributed errors covering: Rule A (allowedOrigins requires
  siteUrl), Rule B (each origin must be the same hostname as siteUrl or a
  subdomain), and shape rules (parseable URL, http/https only, no
  trailing-dot hostname, no empty labels). Reject IP-literal siteUrl and
  trailing-dot siteUrl when allowedOrigins is non-empty (multi-origin
  rpId requires a real domain).
- Validate config.allowedOrigins shape at integration init; defer
  siteUrl-dependent rules to runtime when config.siteUrl is absent
  (EMDASH_SITE_URL may supply it post-build per existing siteUrl pattern
  in integration/index.ts).
- Throw loud on invalid EMDASH_ALLOWED_ORIGINS entries instead of silent
  skip; an allowlist that drops typos masks real config errors.
- Rename internal _resetEnvSiteUrlCache to _resetEnvCache (it now resets
  both site-url and allowed-origins caches).
- Fix the docstring on getEnvAllowedOrigins that incorrectly claimed
  process.env was unavailable on Workers (it is, with nodejs_compat).
- Add focused register.test.ts off-list-origin test to lock in
  origin-check parity with authenticate.ts.

* format

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
Co-authored-by: Matt Kane <m@mk.gg>
2026-04-29 06:30:48 +00:00
emdashbot[bot] 5c0195ac05 ci: release (#797)
* ci: release

* chore: restore original PR/author attribution in CHANGELOGs

* style: format

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <m@mk.gg>
Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-04-27 21:21:37 +01:00
Matt Kane ba12ca5ee3 revert: undo accidental major and prevent recurrence (#796)
* revert: undo accidental 1.0.0 release; prevent recurrence

Reverts 46f3acb (ci: release #759), which bumped all 8 publishable
packages to 1.0.0. Restores 0.7.x versions and pending changesets so
the next release lands at 0.8.0.

Root cause: peer-dep cycle between `emdash` and `@emdash-cms/auth-atproto`,
both using `workspace:*`. Changesets resolves `workspace:*` to the exact
current version for semver checks, so a minor bump on either side falls
outside the range and escalates the cycle's other side to major. Other
plugins use `workspace:>=X.Y.Z` and don't trip this — switching both
ends of the cycle to the same form fixes the escalation.

The existing workflow guard greps `pnpm changeset status` for "bumped
at major", which only runs at PR-creation time. Once the version PR is
merged, no changesets are pending and the grep returns nothing — so
the publish step proceeded with already-bumped 1.0.0 versions.

Replaces it with a package.json scan that fails on any non-private 1.x
version. Wired into both `release.yml` (publish-time) and `ci.yml`
(every PR, including the auto-generated Version Packages PR).

Also adds .claude/* to .gitignore (mirroring the .opencode pattern)
so local agent state doesn't accidentally land in commits.

* style: format

* chore: update lockfile for workspace range changes

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-04-27 21:00:59 +01:00
emdashbot[bot] 46f3acb7fa ci: release (#759)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-27 19:46:13 +01:00
simnaut 31333dc593 feat: pluggable auth providers — add AT Protocol, refactor GitHub/Google (#398)
* feat: pluggable auth providers — add AT Protocol, refactor GitHub/Google

Introduces a pluggable auth provider system and uses it to add AT Protocol
authentication as the first plugin-based provider. GitHub and Google OAuth
are refactored from hardcoded buttons into the same provider interface.

- AuthProviderDescriptor interface with admin UI, routes, and public routes
- virtual:emdash/auth-providers Vite module for distributing provider components
- Shared findOrCreateOAuthUser() in @emdash-cms/auth for consistent signup gating
- AT Protocol auth via @atcute/oauth-node-client with PKCE (public client)
- allowedDIDs and allowedHandles config with independent handle verification
  via DNS-over-HTTPS + HTTP well-known (never trusts PDS handle claims)
- Default role for new signups changed to Subscriber
- First user becomes Admin during setup regardless of provider

* fix: address PR review — TOCTOU race, ensureTable memoization

- Replace countUsers() with setup_complete option flag check in both
  GitHub/Google and ATProto OAuth callbacks to prevent concurrent
  callbacks from both claiming first-user admin role
- Memoize ensureTable() in db-store.ts with a module-level boolean
  so CREATE TABLE IF NOT EXISTS only runs once per process

* style: format

* fix: address PR review — split auth-atproto package, add provider storage, update terminology

Addresses all 10 review comments on PR #398:

- Split auth provider into @emdash-cms/auth-atproto (npm-installable),
  keep syndication plugin in @emdash-cms/plugin-atproto (marketplace)
- Add `storage` field to AuthProviderDescriptor, reuse plugin storage
  infrastructure instead of manual SQL table creation
- Rename "AT Protocol" → "Atmosphere", remove "PDS" from user-facing strings
- Forbid self-signup when no allowlists configured (except first admin)
- Fix core callback.ts import to use #db alias
- Fix env.d.ts to reference emdash/locals package

* fix: CI failures — typecheck, lint, bundle, and i18n catalog

- Fix auth-atproto typecheck by aligning tsconfig with core's settings
  (noUncheckedIndexedAccess, lib targets) and adding explicit return type
  to storage.ts to avoid cross-package type portability issue
- Add @types/react to core devDependencies for auth/types.ts React refs
- Fix plugin bundle CLI: clean stale temp dirs before bundling, and
  expand TS_EXT_RE to strip .mjs/.js/.cjs extensions from dist entries
- Fix floating promise lint error in InlinePortableTextEditor
- Regenerate Lingui catalog to include interpolated "Sign in with {0}"

* fix: update tests and plugin config for pluggable auth changes

- Fix atproto plugin: add build step, tsdown dep, and point exports to
  dist files so plugin validation passes
- Update LoginPage browser test to mock fetchAuthMode instead of the
  removed fetchManifest
- Update SetupWizard browser test: step label changed from "Passkey"
  to "Sign In"
- Update E2E tests: passkey step text changed from "Set up your passkey"
  to "Choose how to sign in"

* fix(i18n): wrap missing "Back to login" string with Lingui t tag

* fix: address PR review — remove singleton, use getPublicOrigin

Remove module-scope singleton from OAuth client (unsafe on Workers
where module vars persist between requests). Construct per-request.

Replace url.origin with getPublicOrigin() in all atproto routes so
the correct origin is used behind reverse proxies. Export
getPublicOrigin from route-utils. Narrow the EmDashConfig import in
public-url.ts to an inline interface to avoid pulling the full core
type tree into auth-atproto's typecheck.

* fix(test): add missing virtual:emdash/config mock in mcp-discovery-post test

The test was missing a mock for the virtual:emdash/config module
imported by auth middleware, causing a module resolution error.

* fix(auth-atproto): suppress no-unsafe-type-assertion lint warnings

Add eslint-disable comments for type assertions required by the
@atcute SDK's type signatures and Astro's opaque locals types.

* style: format

* fix: address PR review — use Kumo components, rename label to Atmosphere

- Replace raw HTML form elements with Kumo Input, Button, and LinkButton
  in atproto admin components
- Update GitHub and Google LoginButtons to use Kumo LinkButton
- Rename auth provider label from "AT Protocol" to "Atmosphere"
- Improve oauth-client.ts loopback comment to cite RFC 8252 §8.3
- Remove broken client-side localhost→127.0.0.1 redirect that reset
  the setup wizard; server-side normalization handles this correctly

* fix(auth-atproto): use Button not LinkButton for LoginButton

Per ascorbic review: LinkButton is for actual links; LoginButton
expands the inline sign-in form on click, so it's a Button.

* fix(auth): restore findOrCreateOAuthUser export after upstream merge

Auto-merge with upstream/main reverted our pluggable-auth refactor —
findOrCreateOAuthUser and the CanSelfSignup type were silently removed
from packages/auth/src/index.ts, and consumer.ts was rolled back to the
private findOrCreateUser shape. auth-atproto's callback route depends on
these exports, so typecheck was failing.

Restored both files from branch tip 4faa43b. The User-Agent fix from
upstream commit 1a93d51 is preserved (it was already on the branch).

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-04-27 06:57:58 +01:00