Skip to content

release: to prod#1415

Merged
joelorzet merged 14 commits into
prodfrom
staging
May 29, 2026
Merged

release: to prod#1415
joelorzet merged 14 commits into
prodfrom
staging

Conversation

@joelorzet

Copy link
Copy Markdown

No description provided.

joelorzet added 9 commits May 28, 2026 19:05
REST clients had no way to introspect plugin action schemas without
going through MCP. The MCP list_action_schemas tool exists, but a
parallel REST entry point did not — every REST integrator was forced
into MCP for schema discovery, and that gap is the upstream cause of a
class of silent-config bugs (workflow PATCHes accepted with unknown
actionTypes or invalid configs because the caller could not validate
locally).

Adds:

- GET /api/action-schemas — bearer kh_ auth, returns the same payload
  shape as list_action_schemas. Supports ?category=, ?includeChains=,
  and ?type=<actionType> to narrow the actions map to a single entry.
- GET /api/action-schemas/{actionType} — bearer kh_ auth, returns just
  the matching action schema; 404 on unknown actionType.

Extracts the response builder out of /api/mcp/schemas/route.ts into
lib/action-schemas/builder.ts so the MCP-internal route and the new
public REST route share a single source of truth and cannot drift.
/api/mcp/schemas behaviour, response keys, and cache headers are
unchanged.
Covers the auth gate (missing header, wrong scheme, non-kh_ prefix),
the full-collection response shape (actions, triggers, chains,
platform, templateSyntax, builtinVariables, tips), the ?type=,
?category=, ?includeChains= filters, and the single-action lookup
including the 404 path and URL-decoding of the path segment.

Mocks plugins/registry, lib/mcp/workflow-schema-constants, lib/db, and
lib/api-key-auth so the tests exercise the route logic and the shared
builder without hitting a database or the real plugin registry.
…rapper

The condition expression resolver walked output.data directly with no
wrapper-shape fallback, so trigger node paths like "args.value" failed
with "Available fields: success, data" while the same path resolved
cleanly in action-config templates via resolveFromOutputData. Routes the
field walk through resolveFromOutputDataChecked first so trigger paths
get the same three-shape lookup (top -> { data } -> { result }) the
template engine already provides; falls back to the original strict
walk for true misses so the informative "Available fields" error
remains intact.

Also fixes the related orphan-row mis-attribution where the trigger
log row was closed with "Step did not record completion" even when a
peer step recorded the actionable error (the real failure source the
user should see in the UI). pickOrphanCloseErrorMessage detects
sibling-error rows and uses a clearer cancelled-due-to-peer message;
the legacy message is preserved when no peer carries a real error so
the worker-killed-mid-step signal is not lost.
The event worker can emit { type: 'uint256', value: 'undefined' } for
missing log fields (most commonly logIndex on pending blocks). The
prior deserializePrimitive caught the BigInt parse failure and
returned the original string, so the literal word "undefined"
propagated into the trigger output and downstream conditions either
silently mis-matched or threw an opaque BigInt error.

Now returns null for the literal strings "undefined" / "null" / "" /
actual undefined and for any value BigInt() rejects (e.g. "NaN").
Applies across all type branches because a missing field is missing
regardless of its declared ABI type. Signature widened to unknown to
match the runtime reality of values arriving from JSON over the wire.

Adds a unit-test file covering deserializePrimitive,
deserializeArg (primitive, dynamic + fixed arrays, tuples, propagation
through arrays), and deserializeEventTriggerData (happy path,
blockNumber / logIndex / transactionIndex deserialization, the
logIndex='undefined' regression, missing-args resilience). 27 cases.
…tion-resolver-event-deserializer

# Conflicts:
#	tests/unit/condition-executor.test.ts
…er-event-deserializer

fix(workflow): condition resolver + orphan-row error + event deserializer hardening
…on-schemas-rest

# Conflicts:
#	app/api/mcp/schemas/route.ts
…rest

feat(api): public REST endpoint for action schemas
Rejects sign-ups from disposable / temporary email providers on both the
email+password path and OAuth (Google / GitHub) callbacks. Both paths
flow through better-auth's databaseHooks.user.create, so a single
before-hook in lib/auth.ts catches them.

The blocklist combines a curated headline set (Mailinator, YOPmail,
Guerrilla Mail, 10MinuteMail, Maildrop, EmailOnDeck, DisposableMail,
Temp-Mail, Mailnesia, GetNada, Throwawaymail, Trashmail, Dispostable,
Fakemail, plus aliasing services SimpleLogin, addy.io, Firefox Relay,
DuckDuckGo, Burner Mail, IronVest) with the maintained
disposable-email-domains.json fallback (5,488 domains, vendored from the
disposable-email-domains/disposable-email-domains repo).

isDisposableEmailDomain handles case folding, +alias local-parts, and
multi-@ inputs via lastIndexOf. Exact-domain match only -- substring
collisions like 'notmailinator.com' are intentionally checked against
the full vendored list to avoid false positives or negatives.
@joelorzet joelorzet requested review from a team, OleksandrUA, eskp and suisuss and removed request for a team May 29, 2026 19:48
joelorzet added 2 commits May 29, 2026 17:08
The back/cancel control on the step-up MFA dialog navigated to
/sign-in, which is not a route in this app (auth is a modal, not a
page), so cancelling produced a 404. Point it at / like the other
no-session navigations.

Also add temporary [mfa-debug] diagnostics on the OAuth verify-mfa
path and in the dual-factor TOTP check to investigate authenticator
codes being rejected after OAuth sign-in on a TOTP-enrolled account.
…-totp-debug

fix(auth): redirect MFA verify cancel to home instead of 404
…-signups

hotfix(auth): block disposable email domains on signup
Before, the server's databaseHooks.user.create.before hook returned
false to abort, which better-auth converted into a generic "Failed to
create user" string. The signup dialog had no special case for it, so
the user saw an opaque error with no hint of what to fix.

Now the hook throws an APIError("BAD_REQUEST") carrying the shared
DISPOSABLE_EMAIL_REJECTION_MESSAGE constant. The signup dialog imports
the same constant and matches on it directly, so the surfaced text
cannot drift between server and client.

The constant lives in its own file (lib/auth-disposable-emails-message.ts)
so the client bundle does not pull in the 5,488-domain JSON or the
Set construction from lib/auth-disposable-emails.ts.

Follow-up to the ref/block-disposable-email-signups landing.
…sage

refactor(auth): surface disposable-email rejection message to user
@joelorzet joelorzet merged commit df4d257 into prod May 29, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant