~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
78 lines · 3.7 KB Raw History
# @pdsjs/start

The setup wizard behind start.pdsjs.dev. A visitor signs in with Cloudflare
and the wizard deploys pds.js into their own account: one Worker, one R2
bucket, a workers.dev hostname as the handle. The signing key, the server
password and the JWT secret are generated in the visitor's browser tab and
go from the tab to the visitor's own worker.

The wizard is a static site, served from the pdsjs.dev PDS through the site
lexicons like any other site. There is no wizard worker. The page calls its
dependencies directly:

- The OAuth token exchange goes to dash.cloudflare.com. It is a form POST,
  which browsers send without a preflight, and the response carries CORS for
  the origins registered on the OAuth client.
- PLC registration and the relay crawl request go to plc.directory and
  bsky.network, which serve open CORS.
- The worker artifact comes from the release site named in `config.json`
  (artifacts.pdsjs.dev, filled by `.knotless/workflows/release-worker.yml` on
  each version tag). Site files serve with open CORS.
- Cloudflare API calls are the one thing a browser cannot do:
  api.cloudflare.com answers no CORS preflight. They ride through the
  serving PDS's `/cf-api/` passthrough (`PDS_EXPERIMENTAL_CF_API_PROXY` in
  @pdsjs/cloudflare), same-origin because the same worker serves the site.

## Operator setup

1. Register an OAuth client in the Cloudflare dashboard under Manage
   account, then OAuth clients. Grant type: authorization code with PKCE, no
   client secret. Redirect URL: `https://<host>/callback`. Add the site's
   origin to Allowed CORS Origins; without it the token exchange fails in
   the browser. Scopes: account settings read, workers scripts write,
   workers R2 write; plus zone read and DNS write for the custom-domain
   picker. Without the zone scopes the picker offers workers.dev alone.
2. Set `PDS_EXPERIMENTAL_CF_API_PROXY = "true"` on the PDS worker that
   serves the site domain.
3. Build and publish:

```bash
npm run build:start
cd packages/start
PDS_URL=https://pds.pdsjs.dev PDS_IDENTIFIER=pdsjs.dev PDS_PASSWORD=... \
  OAUTH_CLIENT_ID=... OAUTH_SCOPES="account-settings.read workers-scripts.write workers-r2.write zone.read dns.write" \
  npm run publish-site
```

The record's `fallback` serves the page for `/callback` and `/update`, the
app's client-side routes. `config.json` is generated by the publish script;
the page falls back to sane defaults for everything but the client id.

A public OAuth client needs domain ownership verification for the redirect
URL's domain, via a DNS TXT record. Public visibility is permanent once set.

## What the visitor's account needs

- R2 enabled. Enabling it takes one dashboard step and a billing profile;
  the wizard links there when the bucket creation fails.
- A workers.dev subdomain. The wizard links to the dashboard when none is
  set.

## Domains

The configure screen offers the account's active zones beside workers.dev.
With a zone chosen, the server answers at `pds.<zone>` (a worker custom
domain; Cloudflare creates the record and the certificate) and the handle
is the zone apex, proven by a `_atproto` TXT record the wizard writes. The
domain's site, if any, stays untouched: handle resolution reads the TXT
record and never the apex. The workers.dev hostname stays enabled and
carries the bootstrap, since a fresh certificate can take minutes.

## Not yet in the wizard

- Domain registration through the Registrar API (beta; needs a billing
  profile and a registrant contact on the account).
- Updates for custom-domain servers; /update derives the worker name from
  a workers.dev hostname only.
- Scheduled backups. The deployed worker supports them; see the root
  `wrangler.toml` for the S3 settings.