Skip to content

Reference source · 0.1.0-dev.11

fixtures.ts

src/reference/fixtures.ts · Download original file

import { makeAuthority, makeIdentity, signCredential, signStatus, TrustStore } from '../identity.ts';
import type { DecisionProvider, Representative, AuthorizationOptions } from '../authorization.ts';
import { SCOPES } from '../authorization.ts';
import { ReferenceHost } from '../host.ts';
import { Client } from '../sdk.ts';
import { seconds } from '../core.ts';

export const PATIENT = 'synthetic-patient-001';
export const OTHER_PATIENT = 'synthetic-patient-002';
export function lab(patient = PATIENT): Record<string, any> {
  return { resourceType: 'Observation', status: 'final', category: [{ coding: [{ system: 'http://terminology.hl7.org/CodeSystem/observation-category', code: 'laboratory' }] }],
    code: { coding: [{ system: 'http://loinc.org', code: '2345-7' }] }, subject: { reference: `Patient/${patient}` }, valueQuantity: { value: 92, unit: 'mg/dL' } };
}
export function fixture(path = ':memory:', options: AuthorizationOptions = {}) {
  let now = seconds(); const started = now;
  const hostingAuthority = makeAuthority('authority-hosts.example');
  const applicationAuthority = makeAuthority('authority-apps.example');
  const hostIdentity = makeIdentity('urn:oprp:demo:host');
  const appIdentity = makeIdentity('urn:oprp:demo:hospital');
  const parentIdentity = makeIdentity('urn:oprp:demo:parent');
  const trust = new TrustStore({
    [hostingAuthority.issuer]: { publicKey: hostingAuthority.publicKey, kinds: ['host'], subjectPrefixes: ['urn:oprp:demo:'], roles: {}, maximumLifetime: 86400, maximumStatusAge: 600 },
    [applicationAuthority.issuer]: { publicKey: applicationAuthority.publicKey, kinds: ['application', 'person'], subjectPrefixes: ['urn:oprp:demo:'], roles: { application: ['emergency-provider'] }, maximumLifetime: 86400, maximumStatusAge: 600 },
  });
  let statusSequence = 0;
  const updateStatus = () => { statusSequence++; for (const authority of [hostingAuthority, applicationAuthority]) trust.ingestStatus(signStatus(authority, statusSequence, now), now); };
  updateStatus();
  const hostCredential = signCredential(hostingAuthority, hostIdentity.public, 'host', now);
  const appCredential = signCredential(applicationAuthority, appIdentity.public, 'application', now, ['emergency-provider']);
  const parentCredential = signCredential(applicationAuthority, parentIdentity.public, 'person', now);
  const app = trust.validate(appCredential, now);
  const representatives: Representative[] = [{ actor: parentIdentity.public.subject, patient: PATIENT, scopes: [SCOPES.demographicsRead], manageScopes: [SCOPES.demographicsRead], active: true, expiresAt: now + 7200 }];
  const policy: DecisionProvider = (request, context) => ({ maximumDuration: 90 * 86400,
    scopes: Object.fromEntries(request.scopes.map(scope => [scope,
      request.patient !== PATIENT ? 'deny' : context.actor ? 'allow' : scope === SCOPES.demographicsRead && request.requested_duration_seconds <= 86400 ? 'allow' : 'approval_required'])) });
  const host = new ReferenceHost(path, hostIdentity, hostCredential, trust, policy, representatives, options);
  host.seed(PATIENT, { name: [{ text: 'Synthetic Example' }] });
  host.seed(OTHER_PATIENT, { name: [{ text: 'Other Synthetic Example' }] });
  const client = new Client({ identity: appIdentity, credential: appCredential, hostCredential, hostId: hostIdentity.public.subject, trust,
    transport: async envelope => host.handle(envelope, now), clock: () => now });
  return { host, client, app, appIdentity, hostIdentity, parentIdentity, parentCredential, hostCredential, appCredential,
    trust, policy, representatives, hostingAuthority, applicationAuthority, started, clock: () => now, advance: (amount: number) => { now += amount; updateStatus(); } };
}