Skip to content

refactor(ui): the pages' browser code is Rust on Topcoat's runtime, not script files - #387

Draft
PiquelChips wants to merge 14 commits into
mainfrom
refactor/rust-frontend-scripts
Draft

PiquelChips wants to merge 14 commits into
mainfrom
refactor/rust-frontend-scripts

Conversation

@PiquelChips

@PiquelChips PiquelChips commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Every new browser feature added another plain JavaScript file (passkey.js, dashboard.js, now picture.js), wired to the Rust pages through data-* attributes the compiler couldn't check. We have a Rust frontend framework; the pages should use it.

Now they do. What the pages do in the browser is Rust in crates/ui, on Topcoat's runtime: signals hold the state, @submit/@click handlers and :hidden/:disabled bindings do the rest. The three scripts are gone.

  • Passkey forms, confirm-before-post, submit-once, fragment links, copy buttons, dismissible hints and the secret page's address: Passkey, Once, Dismissal in form.rs and layout/parts.rs.
  • Dashboard confirmation dialog: a Gate in the admin frame, with one delegated click handler.
  • Picture cropper: settings/cropper.rs.
  • What Topcoat's expressions can't name (WebAuthn and the ceremony fetches, clipboard, local storage, history, popovers, pointer capture) is one small raw! method per API on Browser in crates/ui/src/browser.rs.
  • AGENTS.md now says so: no more script files.

Security policy stays strict. Topcoat's runtime normally needs 'unsafe-eval' (tokio-rs/topcoat#484). We depend on a fork, PiquelChips/topcoat@csp-safe-expressions, where pages carry their expressions as data naming functions in one hashed expressions script. script-src lists that script and the runtime, nothing else, on auth and the dashboard. The fork also has @mount (from tokio-rs/topcoat#550) and fixes for two expression bugs this work hit. Nothing was filed upstream yet.

Also: Topcoat main's breaking changes (components take cx: &Cx), and #[key] on the view! loops whose rows keep state.

The JSON ceremony routes are unchanged, and the pages code passkey options and credentials themselves, as passkey.js did, so browsers without WebAuthn's JSON helpers keep passkeys. Forms still work without scripts where they did.

Proof: just validate's checks (Clippy, rustdoc, doc tests, tsc, ESLint, knip, Prettier, cargo deny), all 455 Rust tests with the database ones, and the Playwright suite on a preview: every spec that runs there passed, two failing only when auth's rate limit on repeated sign-ups kicked in, then passing on rerun (4 skipped: invitation, Mailpit and the confidential client's secret aren't on previews).

Not covered: the browser test that forced a lapsed passkey confirmation is gone (pages now decide confirm mode on the server, and e2e can't lapse a session); the Rust tests cover the confirm-mode render, and the browser side is the same ceremony code sign-in uses.

Reviewed with review-loop: 4 rounds with 2× GPT 6.1 Sol and Claude Opus 5.5 (Sol from round 2: round 1's Sol reviewers hit a usage limit). Verdict: approved

Note

Written by Claude Opus 5.5 in Claude Code and reviewed by GPT 6.1 Sol and Claude Opus 5.5 (via T3 Code)

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 114 files, which is 14 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fe58bf5e-0971-41f7-84e9-c060083db8c4
Commits

Reviewing files that changed from the base of the PR and between e0d7ea0 and c35b936.

Files ignored due to path filters: 1

  • Cargo.lock is excluded by !**/*.lock
Files selected for processing: 114

  • .github/workflows/ci.yml
  • .prettierignore
  • AGENTS.md
  • Cargo.toml
  • apps/auth-service/assets/dashboard.js
  • apps/auth-service/assets/passkey.js
  • apps/auth-service/assets/picture.js
  • apps/auth-service/assets/tsconfig.json
  • apps/auth-service/src/assets.rs
  • apps/auth-service/src/lib.rs
  • apps/auth-service/src/routes.rs
  • apps/auth-service/src/tests.rs
  • apps/auth-service/src/web/account.rs
  • apps/auth-service/src/web/admin/administrators.rs
  • apps/auth-service/src/web/admin/alerts.rs
  • apps/auth-service/src/web/admin/announcements.rs
  • apps/auth-service/src/web/admin/audit.rs
  • apps/auth-service/src/web/admin/clients.rs
  • apps/auth-service/src/web/admin/deliveries.rs
  • apps/auth-service/src/web/admin/handles.rs
  • apps/auth-service/src/web/admin/invitations.rs
  • apps/auth-service/src/web/admin/keys.rs
  • apps/auth-service/src/web/admin/lists.rs
  • apps/auth-service/src/web/admin/mod.rs
  • apps/auth-service/src/web/admin/origins.rs
  • apps/auth-service/src/web/admin/overview.rs
  • apps/auth-service/src/web/admin/settings.rs
  • apps/auth-service/src/web/admin/tests.rs
  • apps/auth-service/src/web/admin/users.rs
  • apps/auth-service/src/web/auth/handoff.rs
  • apps/auth-service/src/web/auth/login/mod.rs
  • apps/auth-service/src/web/auth/login/tests.rs
  • apps/auth-service/src/web/auth/oidc.rs
  • apps/auth-service/src/web/auth/recovery/mod.rs
  • apps/auth-service/src/web/auth/recovery/tests.rs
  • apps/auth-service/src/web/developers/app.rs
  • apps/auth-service/src/web/developers/mod.rs
  • apps/auth-service/src/web/developers/tests.rs
  • apps/auth-service/src/web/mod.rs
  • apps/auth-service/src/web/settings/connected.rs
  • apps/auth-service/src/web/settings/data.rs
  • apps/auth-service/src/web/settings/emails.rs
  • apps/auth-service/src/web/settings/history.rs
  • apps/auth-service/src/web/settings/notifications.rs
  • apps/auth-service/src/web/settings/overview.rs
  • apps/auth-service/src/web/settings/profile.rs
  • apps/auth-service/src/web/settings/sessions.rs
  • apps/auth-service/src/web/settings/sign_in.rs
  • apps/auth-service/src/web/settings/tests.rs
  • apps/auth-service/src/web/tests.rs
  • apps/web/src/pages.rs
  • apps/web/src/site/mod.rs
  • crates/ui/Cargo.toml
  • crates/ui/assets/style/base.css
  • crates/ui/assets/style/cards.css
  • crates/ui/assets/style/components.css
  • crates/ui/src/admin/alerts.rs
  • crates/ui/src/admin/announcements.rs
  • crates/ui/src/admin/audit.rs
  • crates/ui/src/admin/clients.rs
  • crates/ui/src/admin/deliveries.rs
  • crates/ui/src/admin/events.rs
  • crates/ui/src/admin/handles.rs
  • crates/ui/src/admin/keys.rs
  • crates/ui/src/admin/lists.rs
  • crates/ui/src/admin/mod.rs
  • crates/ui/src/admin/overview.rs
  • crates/ui/src/admin/recoveries.rs
  • crates/ui/src/admin/users.rs
  • crates/ui/src/asset.rs
  • crates/ui/src/browser.rs
  • crates/ui/src/clients.rs
  • crates/ui/src/developers.rs
  • crates/ui/src/form.rs
  • crates/ui/src/icons.rs
  • crates/ui/src/layout/frames.rs
  • crates/ui/src/layout/html.rs
  • crates/ui/src/layout/mod.rs
  • crates/ui/src/layout/parts.rs
  • crates/ui/src/layout/sections.rs
  • crates/ui/src/layout/signed_in.rs
  • crates/ui/src/lib.rs
  • crates/ui/src/login/mod.rs
  • crates/ui/src/oidc.rs
  • crates/ui/src/recovery/mod.rs
  • crates/ui/src/settings/connected.rs
  • crates/ui/src/settings/cropper.rs
  • crates/ui/src/settings/data.rs
  • crates/ui/src/settings/emails.rs
  • crates/ui/src/settings/mod.rs
  • crates/ui/src/settings/notifications.rs
  • crates/ui/src/settings/overview.rs
  • crates/ui/src/settings/profile.rs
  • crates/ui/src/settings/sessions.rs
  • crates/ui/src/settings/sign_in.rs
  • crates/ui/src/settings/timeline.rs
  • deny.toml
  • docs/dev/architecture/overview.md
  • docs/dev/architecture/request-lifecycle.md
  • docs/dev/architecture/surfaces.md
  • docs/dev/extending/page.md
  • docs/dev/getting-started.md
  • docs/dev/rust-conventions.md
  • docs/dev/security/account-recovery.md
  • docs/dev/testing.md
  • infra/auth.Dockerfile
  • knip.json
  • package.json
  • tests/browser/admin.spec.ts
  • tests/browser/helpers.ts
  • tests/browser/profile.spec.ts
  • tests/browser/recovery.spec.ts
  • tests/browser/settings.spec.ts
  • tests/browser/sign-in.spec.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@PiquelChips
PiquelChips force-pushed the refactor/rust-frontend-scripts branch from 773d7ba to c9ef31d Compare November 6, 2026 12:53
…oard dialog waits for a valid form

From review: auth's pages code their passkey options and credentials
themselves again, as passkey.js did, so browsers without the JSON helpers keep
passkeys; the dashboard opens its dialog only for a form that validates, and
goes on when a ceremony does not start again; the cropper drags with the
primary pointer only; and the dashboard's page wrapper lays out as if absent.
…nge, and the cropper keeps the square it shows

From review: a ceremony that finishes after the dialog closed, or reopened for
another change, no longer goes on; the dialog's button waits for its pre-started
ceremony; and moving or zooming keeps the square's centre where it stays inside
the image, as picture.js did.
From review: closing the picture dialog resized the stage to nothing, and
placing the image then kept a centre of 0 / 0, so reopening it lost the
square chosen. picture.js's render() skipped that case too.
# Conflicts:
#	README.md
#	apps/auth-service/assets/dashboard.js
#	apps/auth-service/assets/passkey.js
#	apps/auth-service/src/lib.rs
#	apps/auth-service/src/web/account.rs
#	apps/auth-service/src/web/admin/audit.rs
#	apps/auth-service/src/web/admin/mod.rs
#	apps/auth-service/src/web/admin/tests.rs
#	apps/auth-service/src/web/auth/login/mod.rs
#	apps/auth-service/src/web/auth/login/tests.rs
#	apps/auth-service/src/web/auth/recovery/tests.rs
#	apps/auth-service/src/web/settings/tests.rs
#	crates/ui/src/admin/mod.rs
#	crates/ui/src/form.rs
#	crates/ui/src/layout/mod.rs
#	crates/ui/src/layout/signed_in.rs
#	crates/ui/src/recovery/mod.rs
#	docs/architecture/monorepo.md
#	docs/dev/rust-conventions.md
#	knip.json
#	tests/browser/README.md
#	tests/browser/recovery.spec.ts
#	tests/browser/settings.spec.ts
…d-scripts

# Conflicts:
#	AGENTS.md
#	Cargo.lock
#	README.md
#	apps/auth-service/assets/passkey.js
#	apps/auth-service/src/account/mod.rs
#	apps/auth-service/src/admin/tests/accounts.rs
#	apps/auth-service/src/admin/types/mod.rs
#	apps/auth-service/src/assets.rs
#	apps/auth-service/src/audit/mod.rs
#	apps/auth-service/src/audit/routes.rs
#	apps/auth-service/src/cli/console.rs
#	apps/auth-service/src/cli/mod.rs
#	apps/auth-service/src/clients/mod.rs
#	apps/auth-service/src/clients/owned.rs
#	apps/auth-service/src/clients/tests/origins.rs
#	apps/auth-service/src/config/keys.rs
#	apps/auth-service/src/config/mod.rs
#	apps/auth-service/src/config/tests.rs
#	apps/auth-service/src/deletion/export/mod.rs
#	apps/auth-service/src/deletion/export/tests.rs
#	apps/auth-service/src/deletion/tests.rs
#	apps/auth-service/src/deliveries/email/mod.rs
#	apps/auth-service/src/deliveries/email/tests.rs
#	apps/auth-service/src/deliveries/outbound.rs
#	apps/auth-service/src/emails/mod.rs
#	apps/auth-service/src/emails/tests.rs
#	apps/auth-service/src/federation/identities.rs
#	apps/auth-service/src/federation/mod.rs
#	apps/auth-service/src/federation/providers/github.rs
#	apps/auth-service/src/federation/providers/google.rs
#	apps/auth-service/src/federation/providers/mod.rs
#	apps/auth-service/src/federation/tests/protocols.rs
#	apps/auth-service/src/grants/mod.rs
#	apps/auth-service/src/history/mod.rs
#	apps/auth-service/src/history/tests.rs
#	apps/auth-service/src/keys/mod.rs
#	apps/auth-service/src/keys/tests.rs
#	apps/auth-service/src/notifications/mod.rs
#	apps/auth-service/src/notifications/preferences.rs
#	apps/auth-service/src/notifications/tests.rs
#	apps/auth-service/src/oidc/authorize/consent.rs
#	apps/auth-service/src/oidc/authorize/mod.rs
#	apps/auth-service/src/oidc/authorize/parameters.rs
#	apps/auth-service/src/oidc/authorize/pushed.rs
#	apps/auth-service/src/oidc/error.rs
#	apps/auth-service/src/oidc/inline.rs
#	apps/auth-service/src/oidc/logout.rs
#	apps/auth-service/src/oidc/mod.rs
#	apps/auth-service/src/oidc/tests/mod.rs
#	apps/auth-service/src/oidc/token.rs
#	apps/auth-service/src/passkey/acceptance.rs
#	apps/auth-service/src/passkey/ceremonies.rs
#	apps/auth-service/src/passkey/mod.rs
#	apps/auth-service/src/passkey/related.rs
#	apps/auth-service/src/passkey/tests/mod.rs
#	apps/auth-service/src/passkey/types.rs
#	apps/auth-service/src/pictures/mod.rs
#	apps/auth-service/src/pictures/tests.rs
#	apps/auth-service/src/recovery/mod.rs
#	apps/auth-service/src/recovery/tests/mod.rs
#	apps/auth-service/src/security/http.rs
#	apps/auth-service/src/sessions/mod.rs
#	apps/auth-service/src/sessions/tests.rs
#	apps/auth-service/src/tests.rs
#	apps/auth-service/src/web/account.rs
#	apps/auth-service/src/web/admin/administrators.rs
#	apps/auth-service/src/web/admin/alerts.rs
#	apps/auth-service/src/web/admin/announcements.rs
#	apps/auth-service/src/web/admin/audit.rs
#	apps/auth-service/src/web/admin/clients.rs
#	apps/auth-service/src/web/admin/deliveries.rs
#	apps/auth-service/src/web/admin/handles.rs
#	apps/auth-service/src/web/admin/invitations.rs
#	apps/auth-service/src/web/admin/keys.rs
#	apps/auth-service/src/web/admin/lists.rs
#	apps/auth-service/src/web/admin/mod.rs
#	apps/auth-service/src/web/admin/origins.rs
#	apps/auth-service/src/web/admin/overview.rs
#	apps/auth-service/src/web/admin/settings.rs
#	apps/auth-service/src/web/admin/tests.rs
#	apps/auth-service/src/web/admin/users.rs
#	apps/auth-service/src/web/auth/handoff.rs
#	apps/auth-service/src/web/auth/login/mod.rs
#	apps/auth-service/src/web/auth/oidc.rs
#	apps/auth-service/src/web/auth/recovery/mod.rs
#	apps/auth-service/src/web/auth/recovery/tests.rs
#	apps/auth-service/src/web/developers/app.rs
#	apps/auth-service/src/web/developers/mod.rs
#	apps/auth-service/src/web/developers/tests.rs
#	apps/auth-service/src/web/mod.rs
#	apps/auth-service/src/web/settings/connected.rs
#	apps/auth-service/src/web/settings/data.rs
#	apps/auth-service/src/web/settings/emails.rs
#	apps/auth-service/src/web/settings/history.rs
#	apps/auth-service/src/web/settings/notifications.rs
#	apps/auth-service/src/web/settings/overview.rs
#	apps/auth-service/src/web/settings/profile.rs
#	apps/auth-service/src/web/settings/sessions.rs
#	apps/auth-service/src/web/settings/sign_in.rs
#	apps/auth-service/src/web/settings/tests.rs
#	apps/auth-service/src/web/tests.rs
#	apps/web/assets/policies/privacy.html
#	apps/web/assets/policies/terms.html
#	apps/web/src/main.rs
#	apps/web/src/pages.rs
#	apps/web/src/site/mod.rs
#	crates/auth-sdk/examples/notes.rs
#	crates/auth-sdk/src/axum/bearer.rs
#	crates/auth-sdk/src/axum/login/mod.rs
#	crates/auth-sdk/src/client.rs
#	crates/auth-sdk/src/http.rs
#	crates/auth-sdk/src/keys.rs
#	crates/auth-sdk/src/lib.rs
#	crates/auth-sdk/src/resource.rs
#	crates/auth-sdk/src/tests.rs
#	crates/auth-sdk/src/token.rs
#	crates/auth-sdk/tests/ui/coerced_scope.stderr
#	crates/auth-sdk/tests/ui/forged_id_token.stderr
#	crates/auth-sdk/tests/ui/forged_scope.stderr
#	crates/common/src/clients/mod.rs
#	crates/common/src/clients/tests.rs
#	crates/common/src/handle/tests.rs
#	crates/common/src/protocol/claims.rs
#	crates/common/src/protocol/metadata.rs
#	crates/common/tests/sdk_vectors.rs
#	crates/crypto/src/signing/mod.rs
#	crates/database/.sqlx/query-45e983401ce66752126d428c6cbeabdfb933c2459aa9b80a5b382a4712716621.json
#	crates/database/.sqlx/query-a2aa3a6a671a884166e9fd0db54829b12b85ce47ffe7332b002bf7c3ca7e8ba4.json
#	crates/database/src/connection/tests.rs
#	crates/database/src/repositories/alerts.rs
#	crates/database/src/repositories/deliveries/backchannel.rs
#	crates/database/src/repositories/deliveries/email.rs
#	crates/database/src/repositories/deliveries/mod.rs
#	crates/database/src/repositories/events/mod.rs
#	crates/database/src/repositories/handles/tests.rs
#	crates/database/src/repositories/notifications/mod.rs
#	crates/database/src/repositories/oidc/clients.rs
#	crates/database/src/repositories/passkeys/mod.rs
#	crates/database/src/repositories/sessions.rs
#	crates/database/src/repositories/tokens/mod.rs
#	crates/telemetry/src/lib.rs
#	crates/ui/src/admin/announcements.rs
#	crates/ui/src/admin/audit.rs
#	crates/ui/src/admin/clients.rs
#	crates/ui/src/admin/events.rs
#	crates/ui/src/admin/mod.rs
#	crates/ui/src/clients.rs
#	crates/ui/src/developers.rs
#	crates/ui/src/form.rs
#	crates/ui/src/layout/frames.rs
#	crates/ui/src/layout/html.rs
#	crates/ui/src/layout/signed_in.rs
#	crates/ui/src/lib.rs
#	crates/ui/src/login/mod.rs
#	crates/ui/src/oidc.rs
#	crates/ui/src/recovery/mod.rs
#	crates/ui/src/settings/connected.rs
#	crates/ui/src/settings/emails.rs
#	crates/ui/src/settings/notifications.rs
#	crates/ui/src/settings/overview.rs
#	crates/ui/src/settings/sessions.rs
#	crates/ui/src/settings/sign_in.rs
#	crates/ui/src/settings/timeline.rs
#	deny.toml
#	docs/README.md
#	docs/dev/architecture/overview.md
#	docs/dev/architecture/surfaces.md
#	docs/dev/getting-started.md
#	docs/dev/operations/administration.md
#	docs/dev/operations/cli-commands.md
#	docs/dev/operations/clients.md
#	docs/dev/operations/deploying.md
#	docs/dev/operations/secrets.md
#	docs/dev/operations/telemetry.md
#	docs/dev/rust-conventions.md
#	docs/dev/security/audit-history.md
#	docs/dev/security/audit-key.pub
#	docs/dev/security/boundaries.md
#	docs/dev/security/threat-model.md
#	docs/user/account/connected-apps.md
#	docs/user/account/email-addresses.md
#	docs/user/account/security-history.md
#	docs/user/agents/overview.md
#	docs/user/agents/skills/sourceorigin-debug-sign-in/SKILL.md
#	docs/user/agents/skills/sourceorigin-deploy/SKILL.md
#	docs/user/agents/skills/sourceorigin-dev-setup/SKILL.md
#	docs/user/agents/skills/sourceorigin-sign-in/SKILL.md
#	docs/user/agents/sourceorigin-debug-sign-in.md
#	docs/user/agents/sourceorigin-deploy.md
#	docs/user/agents/sourceorigin-dev-setup.md
#	docs/user/apps/deploying-with-piqueld.md
#	docs/user/apps/how-sign-in-works.md
#	docs/user/apps/protect-an-api.md
#	docs/user/apps/register-an-app.md
#	docs/user/apps/sign-in-rust.md
#	docs/user/apps/sign-in-typescript.md
#	infra/auth.Dockerfile
#	infra/piqueld.toml
#	infra/telemetry.toml
#	package.json
#	packages/auth/src/protocol.ts
#	tests/browser/admin.spec.ts
#	tests/browser/browser-client.spec.ts
#	tests/browser/web.spec.ts
#	tests/sdk-vectors/sessions/ended.json
#	tests/sdk-vectors/sessions/other-client.json
#	tests/sdk-vectors/sessions/other-cookie.json
#	tests/sdk-vectors/sessions/other-key.json
#	tests/sdk-vectors/sessions/pending-login-key.json
#	tests/sdk-vectors/sessions/tampered.json
#	tests/sdk-vectors/sessions/valid.json
#	tests/sdk-vectors/sessions/without-refresh-token.json
Main's alert and email-preference lists render forms, whose state needs each
iteration's own identity under Topcoat, and its password-manager test read the
data attributes the passkey script used, which the signal now captures.
@PiquelChips PiquelChips self-assigned this Nov 11, 2026
@PiquelChips
PiquelChips marked this pull request as draft November 11, 2026 21:22
@PiquelChips PiquelChips added apps/auth-service Origin Auth at auth.sourceorigin.dev, its settings and developer console, and the operator CLI refactor No behviour changes labels Nov 11, 2026
@PiquelChips PiquelChips added this to the v0.1 milestone Nov 11, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in origin-src.dev Nov 11, 2026
@PiquelChips PiquelChips moved this from Needs Triage to In Progress in origin-src.dev Nov 12, 2026
@PiquelChips PiquelChips modified the milestones: v0.1, v1.0 Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apps/auth-service Origin Auth at auth.sourceorigin.dev, its settings and developer console, and the operator CLI refactor No behviour changes

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant