Reference source · 0.1.0-dev.11
quickstart.md
docs/quickstart.md · Download original file
# OPRP prototype quickstart
The prototype demonstrates patient-address discovery, authenticated encrypted messages in both directions, Host-issued JWTs, conditional approval, bounded refresh recovery, representative access, duplicate-safe clinical writes, scoped snapshot/change polling, constrained credential/status checks, requester rotation, independently recoverable encrypted archives, coordinated live Host migration, encrypted callback subscriptions with durable delivery, and six additional versioned clinical resources with deletion/history. It uses synthetic records and development authorities. It is an executable design experiment, not a production Host or a released interoperable standard.
## Prerequisites and installation
Use Node 24 with native ML-KEM and ML-DSA support. Verification on October 1, 2026 used Node 24.19.0 and its OpenSSL 3.5.7. Node 22 installed on the development machine lacks the required encapsulation API. TypeScript runs directly through Node's type stripping; locally compiled JavaScript/declaration SDK packages are also provided; they remain experimental.
From the repository root:
```sh
cd protocol
node --version
npm ci
npm run typecheck
npm test
```
The HTTPS demonstration additionally needs an `openssl` executable capable of generating a development certificate with a subject alternative name. It binds an ephemeral port exclusively on `127.0.0.1`, validates its generated certificate through an explicitly supplied development CA, and deletes its temporary certificate and key on shutdown.
```sh
npm run demo
```
Expected output consists of PASS lines for signed WebFinger discovery, automatic token issuance, conditional approval and writes, paged change catch-up, lost-refresh-response recovery, and revocation. The demo deliberately omits private keys, tokens, and clinical contents from its logs. A sandbox that prohibits listening on loopback must permit this local demonstration before it can run; the unit tests do not require a listening socket.
For full backup and offline recovery:
```sh
npm run recovery
```
This writes synthetic encrypted files, shuts down and deletes the source database, advances past credential expiry, verifies offline under independently pinned public roots, restores into another Host, obtains destination authorization, and retries earlier writes without duplicates. Temporary files are removed. See [portability](portability.md) for its supported profile and limits. This demo uses in-process encrypted exchanges and needs no listening socket.
For coordinated live migration over two verified HTTPS endpoints:
```sh
npm run migration
```
The demo stages a baseline, catches up a committed write whose response was lost, fences the source, recovers a lost activation response, switches signed WebFinger generation, obtains destination authorization and continues the durable queue without duplicate data. It binds only ephemeral loopback ports and removes temporary state. See [Host migration](host-migration.md) and [conformance/recovery](migration-conformance.md).
For subscriptions over two verified HTTPS endpoints:
```sh
npm run subscriptions
```
The demo verifies a signed encrypted callback challenge, intentionally loses a processed delivery acknowledgment, restarts the receiver, retries without duplicate pull work, retrieves authorized changes, recovers a retention gap and blocks a queued hint after revocation. Its private-network exception is an operator-selected exact loopback endpoint and development CA. See [subscriptions](subscriptions.md) and [conformance/recovery](subscription-conformance.md).
For independent Python interoperability, use Python 3.12 and the pinned native dependencies:
```sh
python3.12 -m venv .venv
.venv/bin/python -m pip install -r python/requirements.txt
npm run interop
```
`OPRP_PYTHON` can name an alternative Python executable with the same dependencies. The script exchanges generated keys and synthetic messages through subprocess pipes. Its Python implementation uses PQClean through `pqcrypto`, independently of Node's OpenSSL primitives and the TypeScript codec. It verifies supplied authority policies and signed status, both message directions, scoped snapshot/change polling, repeated refresh recovery, and modified-ciphertext rejection. It is an interoperability harness, not a complete Python SDK.
For locally installable TypeScript, Python and .NET SDKs:
```sh
.venv/bin/python -m pip install -r python/build-requirements.txt
npm run package:sdks
npm run sdk:conformance
```
This needs .NET 10 and the pinned Python runtime dependencies already installed. It builds local tarball/wheel/NuGet artifacts and installs fresh consumers before running encrypted SDK scenarios. The .NET prototype explicitly invokes a local PQClean primitive provider because native PQ support is unavailable on the tested macOS runtime. No packages are published. See [SDK setup and verification](sdks.md).
```sh
npm run check:docs
```
This validates repository documentation links, schema/API JSON syntax and local schema references. It does not build or publish www.convey.care or prove complete JSON Schema conformance.
## TypeScript example
The smallest executable example uses the development fixture and an in-process transport. Import paths below assume a file saved under `protocol/scripts/` and execution from `protocol/` with Node 24.
```ts
import { fixture, PATIENT } from '../src/reference/fixtures.ts';
import { SCOPES } from '../src/authorization.ts';
const f = fixture();
try {
const decision = await f.client.requestAccess({
patient: PATIENT,
scopes: [SCOPES.demographicsRead],
requested_duration_seconds: 86400,
refresh_requested: true,
});
if (decision.status !== 'granted') throw new Error(decision.status);
const result = await f.client.readDemographics(PATIENT);
if (result.resource.id !== PATIENT) throw new Error('Wrong patient');
} finally {
f.host.close();
}
```
For an approval-required request, persist the request ID and inspect `pending.approval_required`. Poll `client.approvalStatus(requestId)` after the Host's chosen patient or representative process acts. There is no public approve endpoint. The demonstration calls `host.authorization.approve` as a trusted local integration after simulating an authenticated patient decision. That call is not authentication and must never be exposed directly to an untrusted requester.
Configure `TrustStore` with explicit issuer kind/namespace/role/lifetime/status limits and ingest signed fresh status. Use a persistent trust database to retain revocation/sequence state across restart. The development fixture manages synthetic status for its test clock; real operators must supply status acquisition and renewal workers. See [credential lifecycle](credential-lifecycle.md). Close caller-owned trust stores separately from Hosts.
For network transport, construct a `DirectoryTrust` from independently chosen, domain-constrained authority roots and use `discover(address, directoryTrust, now)`. Construct a `Client` with the returned Host identity and credential and `httpsTransport(located.endpoint)`. The complete synthetic flow, including its explicit local development-origin override, is in [the HTTPS demo](../scripts/demo.ts). `discover` also returns the original `delegation`; use `webfinger(address, located.delegation)` to retain those signed bytes for SDK/queue route validation. The [migration demo](../scripts/migration.ts) shows this network flow.
## SDK methods and retry rules
| Method | Behavior |
| --- | --- |
| `requestAccess(request)` | Requests explicit permissions and duration; stores a granted result. |
| `approvalStatus(requestId)` | Checks a Host decision and stores tokens when granted. |
| `cancelAuthorization(requestId)` | Cancels pending approval without revoking an already granted authorization. |
| `followDiscovery(document, address, directoryTrust, transport, patient, minimumGeneration)` | Verifies the binding/patient/generation, switches Host and clears old context secrets before awaiting persistence. |
| `rotateRequester(proof)` | Explicit dual-key requester rotation using old/new credentials and signatures; call on the new-key client. |
| `replaceToken(grantId)` | Reissues under existing current authority after rotation or JWT expiry; never extends permission. |
| `exportRecord(patient)` | Exports the supported full record under the separate `oprp/record.export` scope. |
| `readDemographics(patient)` | Retrieves the authorized Patient and its reference-Host version. |
| `listLabs(patient)` | Retrieves only that patient's laboratory observations. |
| `updateDemographics(patient, name, baseVersion, operationId)` | Updates the narrow demonstration name field with version checking. |
| `createLab(patient, resource, operationId)` | Inserts a laboratory Observation with an atomic operation receipt. |
| `capabilities()` | Reports supported generic types/interactions and subscription capability through an authenticated encrypted exchange. |
| `createResource`, `readResource`, `searchResources`, `updateResource`, `deleteResource`, `resourceHistory` | Scoped generic operations for the six new clinical profiles; mutation IDs are explicit, updates/deletes version-checked. |
| `subscribe(patient, callback, topics, expiresAt, subscriptionId)` | Registers an idempotent, grant-bound pending callback; persist the receiver expectation first. |
| `subscriptionStatus(patient, subscriptionId)` | Reads subscription state under its original current grant. |
| `unsubscribe(patient, subscriptionId)` | Cancels subscription and pending delivery work. |
| `syncSnapshot(patient)` | Retrieves a scoped baseline page and stable feed cursor; inspect `has_more` and continue `page_cursor`. |
| `changes(patient, cursor, limit)` | Retrieves ordered visible changes; repeated pages retain stable event IDs. |
| `exportState()` / `restoreState(state)` | Preserves grant and pending refresh state for an application-owned protected store. |
Persist the original logical mutation and operation ID before sending. On retry, reuse both and let the SDK create a fresh envelope. Reusing the same signed envelope is rejected as replay. A new operation ID can create a duplicate, so do not use the default generated ID for a retry whose first outcome is unknown. Preserve the resource's compact JSON representation and field order in this prototype.
The SDK refreshes an expired JWT within its approved period and serializes concurrent refresh calls inside one client instance. Its persistence hook can durably preserve a logical refresh request before transmission so a lost response can be recovered after restart. Its durable queue preserves ordered mutations and stops on conflicts or revoked access. Cross-process coordination, conflict resolution, secure token storage and production secure storage and cross-process mirror coordination remain application/SDK work. [Durable mirrors](pagination-mirrors.md) now implement baseline staging and atomic feed application in all three SDKs. Use `queue.followMigration` to update a selected patient route only after verified discovery and awaited SDK persistence. Obtain fresh destination authorization and a new snapshot before replaying pending operations. Source tokens/cursors are never moved; other patients retain their own route pins. These calls require an idle queue worker. See [Host migration](host-migration.md).
See [expanded FHIR coverage](fhir-coverage.md), [SDKs](sdks.md), [refresh recovery](refresh-recovery.md), [synchronization](synchronization.md), [reference Host and queue integration](reference-host.md), and [implementation status](implementation-status.md).
## Visibility profile update
The Host advertises `visibility_profile: "oprp-visibility-1"`. [Visibility and cache invalidation](visibility.md) defines trusted grant policy, exact security labels, `SUBSETTED` field projections, write/export protection and required baseline/change `visibility_epoch`. Changed visibility invalidates prior cursors and clears SDK mirrors before a new baseline; disconnected clients cannot learn unknown permission changes. [Negative conformance](negative-conformance.md) records authenticated rejection tests. Host policy and approval delivery remain local integration choices.
## External clinical validation update
The [external clinical validation guide](external-clinical-validation.md) supplies six versioned R4 profiles and selected US Core 9.0.0 targets. The [durable validation guide](durable-clinical-validation.md) adds full offline dependency locking, finite local terminology and restartable intake/migration jobs. Setup requires Java and a verified dependency-cache copy. Structural-only mode advertises disabled terminology; local mode rejects unavailable systems and does not include broad licensed clinical vocabularies. Host authorization and conditional patient approval remain separate.