Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ your own 32-byte base64url key.

Verified browser-facing defaults are:

- Lock Server: <http://localhost:3000>
- creator demo: <http://localhost:8080/examples/js-sdk/>
- reader demo: <http://localhost:8081/reader/>
- Lock Server: <http://127.0.0.1:3000>
- creator demo: <http://127.0.0.1:8080/examples/js-sdk/>
- reader demo: <http://127.0.0.1:8081/reader/>

For the opt-in payment-lock demonstration, including Paykit Server, Bitcoin regtest,
and Fulcrum, use the separate Compose definition:
Expand All @@ -65,8 +65,8 @@ docker compose -f compose.paykit-local-demo.yaml up --build

Its external build contexts use anonymously reachable public repositories pinned to
immutable commits; no sibling Paykit or Pubky checkout is required. The full demo adds
Paykit Server at <http://localhost:3001> and publishes the reader at
<http://localhost:8088/reader/>. Pubky Testnet is built from `pubky/pubky-core` source at
Paykit Server at <http://127.0.0.1:3001> and publishes the reader at
<http://127.0.0.1:8088/reader/>. Pubky Testnet is built from `pubky/pubky-core` source at
commit `75eb1324f86e8caa16c41f18a2cd6b8e1909ee7b`, not from a released Pubky image or
version. Payment remains a manual operator action.

Expand Down
59 changes: 46 additions & 13 deletions compose.paykit-local-demo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ services:
.local/pubky-homeserver \
.local/locks-server \
.local/paykit-server \
.local/paykit-config
.local/paykit-config \
.local/homegate-bridge
chmod 0600 .local/paykit-server/paykit.env
volumes:
- ./examples/js-sdk:/workspace/examples/js-sdk:ro
Expand Down Expand Up @@ -141,6 +142,8 @@ services:
depends_on:
bitcoin-bootstrap:
condition: service_completed_successfully
ports:
- "127.0.0.1:${LOCKS_ELECTRUM_PORT:-60001}:50001"

electrum-readiness:
image: node:22-bookworm-slim@sha256:813a7480f28fdadac1f7f5c824bcdad435b5bc1322a5968bbbdef8d058f9dff4
Expand All @@ -165,7 +168,6 @@ services:
- "127.0.0.1:${LOCKS_HTTP_RELAY_PORT:-15412}:15412"
- "127.0.0.1:${LOCKS_HOMESERVER_HTTP_PORT:-6286}:6286"
- "127.0.0.1:${LOCKS_HOMESERVER_PUBKY_PORT:-6287}:6287"
- "127.0.0.1:${LOCKS_HOMESERVER_ADMIN_PORT:-6288}:6288"
- "127.0.0.1:${LOCKS_SERVER_PORT:-3000}:3000"
- "127.0.0.1:${LOCKS_PAYKIT_PORT:-3001}:3001"
- "127.0.0.1:${LOCKS_CREATOR_DEMO_PORT:-8080}:8080"
Expand All @@ -177,6 +179,38 @@ services:
postgres:
condition: service_healthy

homegate-bridge:
image: node:22-bookworm-slim@sha256:813a7480f28fdadac1f7f5c824bcdad435b5bc1322a5968bbbdef8d058f9dff4
user: "1000:1000"
working_dir: /workspace
command:
- /bin/sh
- -euc
- |
set -a
. /run/compose-local/homegate-bridge/homegate.env
set +a
exec node examples/js-sdk/scripts/homegate-bridge.mjs
environment:
HOMEGATE_BRIDGE_CONFIG: /run/compose-local/demo-config/config.json
HOMEGATE_BRIDGE_HOMESERVER_ADMIN_URL: http://pubky-testnet:6288
ports:
- "127.0.0.1:${LOCKS_HOMEGATE_PORT:-6288}:8082"
volumes:
- ./examples/js-sdk:/workspace/examples/js-sdk:ro
- ./.local/demo-config:/run/compose-local/demo-config:ro
- ./.local/homegate-bridge:/run/compose-local/homegate-bridge:ro
depends_on:
pubky-testnet:
condition: service_started
demo-config:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8082/health').then((response) => { if (!response.ok) process.exit(1); }).catch(() => process.exit(1))"]
interval: 2s
timeout: 2s
retries: 30

locks-server:
build:
context: .
Expand Down Expand Up @@ -247,11 +281,11 @@ services:
paykit-server:
image: pubky-locks-paykit-server:local
build:
context: "https://github.com/pubky/paykit-server.git#f38c7915e6b9b104e040773e78438f8aa984c46c"
context: "https://github.com/pubky/paykit-server.git#5ed3e8e849a16045c26c37a75068625dda333785"
dockerfile: Dockerfile.local
additional_contexts:
paykit-lib: "https://github.com/pubky/paykit-rs.git#52a852995bfc457b78d32f5a45f6741766a89bba:paykit-lib"
paykit-sdk: "https://github.com/pubky/paykit-rs.git#52a852995bfc457b78d32f5a45f6741766a89bba:paykit-sdk"
paykit-lib: "https://github.com/pubky/paykit-rs.git#6b241878a9bba5cecea919c0298c3f90624be6ff:paykit-lib"
paykit-sdk: "https://github.com/pubky/paykit-rs.git#6b241878a9bba5cecea919c0298c3f90624be6ff:paykit-sdk"
locks: "https://github.com/pubky/locks.git#df5ea1b6d8dcdec3a9b5a915c3f57bca69d75c8a"

depends_on:
Expand Down Expand Up @@ -320,19 +354,16 @@ services:
PAYKIT_COMPANION_AUTH_BIN: /usr/local/bin/paykit-companion-auth
PUBKY_LOCK_DEBUG: ${PUBKY_LOCK_DEBUG:-0}
volumes:
- ./locks-sdk/bindings/js/pkg:/workspace/locks-sdk/bindings/js/pkg:ro
- ./.local/demo-config:/workspace/.local/demo-config:ro
- ./.local/js-sdk-demo:/workspace/.local/js-sdk-demo
- ./.local/content-creator:/workspace/.local/content-creator
- ./.local/creator-public:/workspace/.local/creator-public
command:
- sh
- -lc
- |
set -eu
npm --prefix examples/js-sdk run create-user -- --role content-creator
npm --prefix examples/js-sdk run publish-creator-profile
npm --prefix examples/js-sdk run start-server -- --allow-unhealthy
rm -f /workspace/.local/creator-public/profile.json
npm --prefix examples/js-sdk run start-server -- --external-wallet
Comment thread
ben-kaufman marked this conversation as resolved.

reader-demo:
restart: unless-stopped
Expand Down Expand Up @@ -363,9 +394,9 @@ services:
PAYKIT_READER_RECEIVER_PATH: bitkit/wallet
PAYKIT_READER_SERVER_PATH: bitkit/server
PAYKIT_READER_WORKER_ENABLED: "1"
PAYKIT_EXTERNAL_READER_PUBKY: ${PAYKIT_EXTERNAL_READER_PUBKY:-}
PUBKY_LOCK_DEBUG: ${PUBKY_LOCK_DEBUG:-0}
volumes:
- ./locks-sdk/bindings/js/pkg:/workspace/locks-sdk/bindings/js/pkg:ro
- ./.local/demo-config:/workspace/.local/demo-config:ro
- ./.local/creator-public:/workspace/.local/creator-public:ro
- ./.local/content-viewer:/workspace/.local/content-viewer
Expand All @@ -374,8 +405,10 @@ services:
- sh
- -euc
- |
npm --prefix examples/js-sdk run create-user -- --role content-viewer
exec node examples/js-sdk/scripts/start-reader-demo-server.mjs --allow-unhealthy
if [ -z "$PAYKIT_EXTERNAL_READER_PUBKY" ]; then
npm --prefix examples/js-sdk run create-user -- --role content-viewer
fi
exec node examples/js-sdk/scripts/start-reader-demo-server.mjs
healthcheck:
test:
- CMD
Expand Down
13 changes: 12 additions & 1 deletion docker/js-demo.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# syntax=docker/dockerfile:1.7@sha256:a57df69d0ea827fb7266491f2813635de6f17269be881f696fbfdf2d83dda33e
FROM paykit-runtime AS paykit-runtime

FROM rust:1.91.1-slim-bookworm@sha256:8514999d4786ef12efe89239e86b3d0a021b94b9d35108c8efe6c79ca7dc1a65 AS locks-sdk-wasm
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential ca-certificates libssl-dev pkg-config \
&& rm -rf /var/lib/apt/lists/*
RUN rustup target add wasm32-unknown-unknown \
&& cargo install wasm-pack --version 0.13.1 --locked
WORKDIR /workspace
COPY . .
RUN cd locks-sdk/bindings/js && wasm-pack build --target web --out-dir pkg

FROM node:22-bookworm-slim@sha256:813a7480f28fdadac1f7f5c824bcdad435b5bc1322a5968bbbdef8d058f9dff4
WORKDIR /workspace
RUN apt-get update \
Expand All @@ -10,8 +20,9 @@ COPY --chown=node:node examples/js-sdk/package.json examples/js-sdk/package-lock
RUN npm --prefix examples/js-sdk ci --ignore-scripts \
&& npm cache clean --force
COPY --chown=node:node examples/js-sdk /workspace/examples/js-sdk
COPY --from=locks-sdk-wasm --chown=node:node /workspace/locks-sdk/bindings/js/pkg /workspace/locks-sdk/bindings/js/pkg
COPY --from=paykit-runtime /usr/local/bin/paykit-companion-auth /usr/local/bin/paykit-companion-auth
COPY --from=paykit-runtime /usr/local/bin/paykit-reader-demo /usr/local/bin/paykit-reader-demo
RUN mkdir -p /workspace/locks-sdk/bindings/js/pkg /workspace/.local \
RUN mkdir -p /workspace/.local \
&& chown -R node:node /workspace
USER node:node
6 changes: 3 additions & 3 deletions docker/locks-server-compose-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ frontend_session_ttl_seconds = 86400
frontend_session_code_ttl_seconds = 120

[creator_authority_acquisition.legacy_connect]
allowed_return_origins = ["http://localhost:8080"]
allowed_return_origins = ["http://127.0.0.1:8080", "http://localhost:8080"]

[secrets]
creator_authority_key_env = "PUBKY_LOCK_CREATOR_AUTH_ENCRYPTION_KEY"
Expand All @@ -101,8 +101,8 @@ network = "testnet"
public_ip = "127.0.0.1"
public_pubky_tls_port = 6287
public_icann_http_port = 3000
icann_domain = "localhost"
pkarr_relays = ["http://localhost:15411"]
icann_domain = "127.0.0.1"
pkarr_relays = ["http://127.0.0.1:15411"]
key_republisher_interval_seconds = 86400

[rate_limits.verification_submission]
Expand Down
19 changes: 12 additions & 7 deletions examples/js-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ examples/js-sdk/reader.html
examples/js-sdk/reader-app.js
examples/js-sdk/reader-flow.js
examples/js-sdk/scripts/init-config.mjs
examples/js-sdk/scripts/homegate-bridge.mjs
examples/js-sdk/scripts/create-user.mjs
examples/js-sdk/scripts/authenticate.mjs
examples/js-sdk/scripts/prepare-paykit-reader.mjs
Expand Down Expand Up @@ -61,7 +62,7 @@ Required tools/services:
DHT bootstrap localhost:6881
```

Build the local WASM SDK package first:
For direct npm development, build the local WASM SDK package first:

```bash
npm --prefix locks-sdk/bindings/js run build
Expand All @@ -83,6 +84,8 @@ The examples package uses `@synonymdev/pubky` for Node-side Pubky testnet auth/k

The supported end-to-end path is the complete local Compose stack documented below. It generates ignored owner-only credentials, starts both databases and both application servers, bootstraps Bitcoin regtest, waits for Fulcrum using `server.version`, and starts the creator and reader demos.

The Compose image builds the JS/WASM package itself. A fresh checkout does not need a host-generated `locks-sdk/bindings/js/pkg` directory.

For direct npm development without Compose, provide a running local Pubky testnet, PostgreSQL, Lock Server, and Paykit Server first. `init-config` reads the Lock Server public key from `~/.pubky-lock/config.toml` by default; it does not read the Lock Server signing secret.

### Basic Locks stack
Expand Down Expand Up @@ -190,7 +193,7 @@ checkout is required.

`compose.paykit-local-demo.yaml` is intentionally limited to local development and demonstration. When `.local` is absent, the one-shot `compose-bootstrap` service creates the ignored owner-only credentials and non-state configuration before dependent services start. Existing generated credentials are validated and reused. For a quiet configuration check without printing generated environment values, run `npm --prefix examples/js-sdk run validate:paykit-compose`; the wrapper inspects a captured `docker compose -f compose.paykit-local-demo.yaml config --no-env-resolution` model.

This starts separate Locks and Paykit PostgreSQL services, Bitcoin Core regtest, a 101-block wallet bootstrap, Fulcrum readiness through `server.version`, Pubky testnet, Locks, Paykit Server, and both browser demos. All published ports bind to host loopback. Paykit is browser-visible at `http://localhost:3001`; Locks reaches it at `http://127.0.0.1:3001` inside the shared Pubky network namespace. The unprivileged creator and reader images contain the reviewed native helpers at `/usr/local/bin`; they receive only their explicit role/runtime directories and generated WASM package, never the repository root or Lock Server identity volume.
This starts separate Locks and Paykit PostgreSQL services, Bitcoin Core regtest, a 101-block wallet bootstrap, Fulcrum readiness through `server.version`, Pubky testnet, a local Homegate-compatible signup bridge, Locks, Paykit Server, and both browser demos. All published ports bind to host loopback. Paykit is browser-visible at `http://localhost:3001`, the Homegate bridge at `http://localhost:6288`, and Fulcrum at `tcp://localhost:60001`. Locks reaches Paykit at `http://127.0.0.1:3001` inside the shared Pubky network namespace. The unprivileged creator and reader images contain the reviewed native helpers and a package built in the image; they receive only their explicit runtime directories, never the repository root or Lock Server identity volume.

Open:

Expand Down Expand Up @@ -265,7 +268,9 @@ POST /api/demo-auth/start
GET /api/demo-auth/status
```

It displays a `pubkyauth://...` string and command like:
It displays a `pubkyauth://...` string. In the Compose external-wallet flow, scan or paste that request into the wallet under test. The approved wallet identity becomes the canonical creator identity and is published for the reader and Paykit services; the demo never imports the wallet private key.

For direct npm development outside the Compose external-wallet mode, the recovery-file command remains available:

```bash
npm --prefix examples/js-sdk run authenticate -- \
Expand All @@ -279,7 +284,7 @@ npm --prefix examples/js-sdk run authenticate -- \
npm --prefix examples/js-sdk run authenticate -- --role content-creator
```

It signs up/registers the `content-creator` with the configured homeserver, approves the auth string, and the demo server persists its session to:
That command signs up/registers the local `content-creator`, approves the auth string, and the demo server persists its session to:

```text
./.local/js-sdk-demo/content-creator-session.json
Expand All @@ -297,7 +302,7 @@ The shell returns `{ state, code }` directly to the parent with `postMessage`. T
http://localhost:8080/auth/lock-server/callback
```

Approve the Lock Server auth string with the same role:
Approve the Lock Server auth string with the same identity. In Compose, scan or paste it into the same external wallet. For direct npm development, use:

```bash
npm --prefix examples/js-sdk run authenticate -- \
Expand Down Expand Up @@ -338,7 +343,7 @@ The Paykit iframe displays the auth URL and both approved local commands. First
npm --prefix examples/js-sdk run generate-paykit-account-tpub
```

This command uses the running Compose regtest node, requests public descriptors only, selects `m/84'/1'/0'`, and intentionally prints only the account-level `tpub` and index at this explicit setup boundary. It never prints or exports the account private key. Then run the companion-auth wrapper:
This command uses the running Compose regtest node, requests public descriptors only, selects `m/84'/1'/0'`, and intentionally prints only the account-level `tpub` and index at this explicit setup boundary. It never prints or exports the account private key. In the external-wallet flow, scan or paste the Paykit authorization request into the same wallet. For direct npm development with a generated creator recovery file, the companion-auth wrapper remains available:

```bash
docker compose -f compose.paykit-local-demo.yaml exec creator-demo npm --prefix examples/js-sdk run authenticate-paykit -- --role content-creator
Expand Down Expand Up @@ -389,7 +394,7 @@ The worker is the sole mutable owner of `./.local/paykit-reader/state.v1`. A dir

The native helper is `/usr/local/bin/paykit-reader-demo`; `PAYKIT_READER_DEMO_BIN` is a test-only executable override. Its state path and local Pubky endpoints come from the `PAYKIT_READER_*` Compose environment. Reader homeserver registration runs in a separate direct-spawned Node subprocess with bounded output, timeout, and TERM→KILL cancellation because the Pubky JS API does not expose request cancellation; cancellation waits for child settlement before ownership is released. The worker derives the Paykit peer from the public `content-creator` profile, then passes only the closed native helper environment. The state path must end in `.local/paykit-reader/state.v1`. The helper owns encrypted versioned state, owner-only file permissions, fresh-nonce rewrites, and invariant validation. The worker fences status publication and state checkpoints on current kernel-lock ownership, atomically writes its separate owner-only `worker.v1.json` projection, and clears in-memory readiness immediately if ownership is lost. The HTTP server validates the projection again and requires current in-memory ownership before returning a ready browser status. Terminal worker failure closes PID 1 after a coarse error so Compose restart policy applies.

The reader page persists local progress in browser `localStorage` under `pubky-locks-reader-demo.*` and has a visible **Reset reader state** button. Bundle IDs and access credentials are bearer-like local-dev secrets; the demo displays them for debugging only.
The reader page persists local progress in browser `localStorage` under `pubky-locks-reader-demo.*` and has a visible **Reset reader state** button. Retrieved guarded bytes are never persisted: text and JSON render as text, images use a temporary object URL, and other binary content exposes metadata and a temporary download link. Bundle IDs and access credentials are bearer-like local-dev secrets; the demo displays them for debugging only.

## Static drift check

Expand Down
2 changes: 1 addition & 1 deletion examples/js-sdk/app-iframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ el.startDemoAuth.addEventListener('click', async () => {
await refreshDemoAuthStatus();
return;
}
el.demoAuthCommand.textContent = `${result.authorizationUrl}\n\n${result.command}`;
el.demoAuthCommand.textContent = [result.authorizationUrl, result.command].filter(Boolean).join('\n\n');
} catch (error) {
showError(el.demoAuthStatus, error);
}
Expand Down
Loading