Go-plus-React example
The React bindings against the real Go server, with
server-side rendering. The Go host is the shared HTTPS loopback host
(examples/internal/loopback: core credentials with
verification, reset and email-change mail, the magic-link plugin, the OAuth
plugin bound to a built-in mock OIDC provider, and a development mail
preview). It starts a Node render server (server.mjs) and proxies the three
pages (/, /account, /callback/mock) to it with the browser's cookies;
the renderer creates one createServerClient per request, forwards only the
session cookie to the API on the public origin, renders the page with
@sigil/react and embeds the snapshot; the browser bundle hydrates the same
components and continues through the hooks. It exists to run the bindings'
journeys in Chromium, Firefox and WebKit (AUTH-030) and is not a deployment
pattern: it binds only to loopback, mints a throwaway certificate per run that
the renderer trusts through NODE_EXTRA_CA_CERTS, approves one fixed mock
identity, exposes proofs in its mail preview and raises abuse budgets.
Run from a clean checkout
Requirements: the Go version in go.mod, Node/npm versions in package.json
(Node also runs the renderer), Docker for the disposable PostgreSQL server,
and an available loopback port.
make pg-up # skip if sigil-ci is already running
npm ci --ignore-scripts --no-audit --no-fund
npm run build --workspaces # @sigil/client, @sigil/react, then this example's dist/
make react-example
export SIGIL_DATABASE_URL='postgres://auth_ci:auth_ci@127.0.0.1:55432/auth_ci?sslmode=disable'
./bin/react-example --migrate
Open https://localhost:8445/ (exactly this host; the certificate names
localhost) and accept the throwaway certificate once. The page arrives
already rendered for your session: signed out at first; after signing in,
reloading shows the signed-in page before any script runs, and the account
page renders your sessions and settings the same way. Register, select
Check mail, open the verification link, confirm, then sign in with the
password, a magic link or the mock provider. Account lists sessions,
changes the password (all sessions are revoked), requests an email change
(confirm from the link the new address receives; all sessions are revoked)
and manages linked identities. Every list disappears the moment the session
ends.
Flags: --addr (numeric loopback only), --host, --database, --schema,
--key-file (parent directory must exist), --dist-dir (the built
browser.js and ssr.js), --renderer (the render server script), --node
and --migrate. The first start writes a random mode-0600 key to ignored
bin/react.key; keep it with the database.
What is where
src/app.tsx: every page, shared by server and browser. Forms go through
useAction; the session panel reads useSession; landing pages capture
the emailed proof or the provider callback only in the browser, after
hydration, and wait for an explicit confirmation. The status line, ids and
labels match examples/client, so the client's journeys run unchanged.
src/ssr.tsx: renderPage({ client, snapshot, path }) returns the
document with the rendered tree and the HTML-safe snapshot.
src/browser.tsx: reads the snapshot, creates the page's client, exposes
it as window.sigil for the tests, and hydrates.
server.mjs: the render server. One createServerClient per request from
SIGIL_API_URL and the request's Cookie header, session.load(),
renderPage, no-store and Vary: Cookie; 404 for other paths, 500
without details on failure. It prints listening http://127.0.0.1:<port>
and the Go host proxies to that address.
build.mjs: esbuild produces dist/browser.js (React, the client and the
bindings bundled, production mode) and dist/ssr.js (packages external,
so the renderer uses the installed react-dom/server).
main.go: flags, the renderer process (certificate file, readiness,
shutdown), the page proxy and the static assets. Only the three pages are
proxied, only as GET; dist/ssr.js is never served.
Automated journeys
npx playwright install chromium firefox webkit # Linux: --with-deps
make check-react-browser # or: npm run test:react
SIGIL_BROWSERS=chromium make check-react-browser # one browser
The command builds the workspaces and the host, launches the browsers
against PostgreSQL on port 8446 with ignoreHTTPSErrors, creates a fresh
sigil_react_test_<32 hex> schema and drops only that schema at teardown via
examples/browser/testdb. Nine tests per browser: the client's five
journeys from examples/client/tests/journeys.mjs
(password with cookie flags, cross-tab sign-out, a held stale 200 and
reset-driven revocation; magic link with explicit confirmation and cross-tab
refetch; provider link, sign-in, denial and unlink; typed aborted, network,
protocol and 401 outcomes; host and origin rejection) and four of this
example's own: forty interleaved server renders for two users, nobody and a
forged cookie, then hydration of the account page without a session request
or a console error; account settings with no user data left after sign-out;
focus revalidation dropping a session another browser revoked; and 404/405
for the server module, unknown paths and non-GET pages. The PostgreSQL CI job
runs the suite after the client example. Go tests cover the renderer address
parser, the proxy and asset rules, the dead-renderer 502 and the certificate
file's mode; the shared host's tests cover the loopback and host boundaries
and the mock provider's exchange enforcement.