Two integration modes.
Use @polaris/fhir-de directly against your own Aidbox installation, or build on the full Polaris platform. Both modes use the same resource builders and extension constants.
Mode A
Standalone Aidbox
Use createFhirDeClient directly against your own Aidbox FHIR server. You bring your own transport, your own Aidbox credentials, and your own deployment. The SDK handles profile-typed CRUD — you handle the infrastructure.
- Direct FHIR CRUD against your Aidbox FHIR endpoint
- You implement the FhirTransport SPI (e.g. fetch-based)
- No Polaris platform dependency required
- Same resource builders and extension constants as platform mode
Mode B
Polaris Platform
Build on the Polaris platform, which handles Aidbox lifecycle, multi-tenant identity, adapter orchestration, and MCP agent access. The adapter-sdk (internal, separate package) wraps the platform-level concerns — your application code stays at the FHIR resource level.
- PVS adapter sync (x.isynet, Charly) managed by the platform
- Multi-org Aidbox with identity and access control at the platform layer
- MCP agent access with anonymization and audit by construction
- Platform docs at polaris-platform.de
Standalone Aidbox — createFhirDeClient
Profile-typed CRUD against any FHIR server.
The createFhirDeClient factory creates a client that wraps FHIR operations with profile-typed methods. The client API is stable since v0.1.0. You supply the transport — no default HTTP client is included.
import {
buildPatient,
createFhirDeClient,
FhirDeHttpError,
KBV_PR_FOR_PatientProfile,
} from '@polaris/fhir-de'
import type { FhirTransport } from '@polaris/fhir-de'
// Implement the FhirTransport SPI with your HTTP client
const baseUrl = 'https://aidbox.example.com/fhir'
const transport: FhirTransport = {
async request(method, path, init) {
const normalizedPath = path.startsWith('/') ? path : `/${path}`
const url = new URL(`${baseUrl.replace(/\\/$/, '')}${normalizedPath}`)
if (init?.query) {
for (const [key, value] of Object.entries(init.query)) {
const values = Array.isArray(value) ? value : [value]
for (const item of values) url.searchParams.append(key, item)
}
}
const res = await fetch(url, {
method,
headers: {
'Content-Type': 'application/fhir+json',
Accept: 'application/fhir+json',
'Authorization': `Bearer ${process.env.AIDBOX_TOKEN}`,
...init?.headers,
},
body: init?.body == null ? undefined : JSON.stringify(init.body),
})
const body = res.status === 204 ? null : await res.json().catch(() => null)
if (!res.ok) throw new FhirDeHttpError(res.status, body)
return body
},
}
// Create a client
const client = createFhirDeClient({
baseUrl,
transport,
})
// Get a profile-scoped resource client
const patients = client.forProfile(KBV_PR_FOR_PatientProfile, 'Patient')
// Typed CRUD operations
const patient = await patients.read('pat-001') // returns null on 404
const results = await patients.search({ family: 'Müller' })
const draft = buildPatient({
id: 'pat-002',
firstName: 'Anna',
lastName: 'Müller',
birthDate: '1985-04-12',
})
const created = await patients.createResource(draft)
await patients.update('pat-002', { ...draft, id: 'pat-002' })
await patients.delete('pat-001') // treats 404 as success read(id)
Returns the profile-wrapped resource, or null on 404. A missing resource is a valid absence — not an error.
search(params)
Returns an array of profile-wrapped resources from the FHIR Bundle. An empty bundle returns [], not an error. A server 404 is a FhirDeHttpError.
delete(id)
Idempotent: a 404 on delete is treated as success (resource was already absent). Non-404 errors throw FhirDeHttpError.
Transport SPI
Bring your own HTTP client.
The FhirTransport interface is the extension point for HTTP behavior. This design decision (arch-council F#2) keeps the SDK independent of any specific HTTP library. A fetch-based reference implementation is available in src/client/examples/fetch-transport.ts in the source package.
import type { FhirTransport } from '@polaris/fhir-de'
// The FhirTransport SPI interface
interface FhirTransport {
request(
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
path: string, // FHIR path, e.g. '/Patient/123'
init?: {
headers?: Record<string, string>
body?: unknown
query?: Record<string, string | string[]>
}
): Promise<unknown>
} Routing policy
baseUrl must point directly to a FHIR server endpoint (e.g. https://aidbox.example.com/fhir). The client appends FHIR resource paths to this URL. Do not use a non-FHIR API proxy as the base URL.
PII-Modus — piiMode
Anonymisierte Antworten mit piiMode: 'anonymized'.
createFhirDeClient akzeptiert ein optionales piiMode-Feld. Der Standardwert ist 'real'. Mit piiMode: 'anonymized' wird der Transport intern in einen AnonymizingTransport eingehüllt, der alle FHIR-Antworten (GET und Write-Echoes) vor der Rückgabe bereinigt. Das Verhalten ist fail-loud: fehlt die Umgebungsvariable POLARIS_ANON_SALT, wirft der Konstruktor synchron.
import { createFhirDeClient } from '@polaris/fhir-de'
// POLARIS_ANON_SALT must be set in the environment before calling this.
// The factory throws synchronously if the variable is missing.
const client = createFhirDeClient({
baseUrl: 'https://aidbox.example.com/fhir',
transport,
piiMode: 'anonymized',
})
// All responses from client.forProfile(...).read/search are now anonymized.
// No further configuration required. Was anonymisiert wird
- Strukturelle PII-Felder: Patient.name, .identifier, .address, .telecom, .photo, Practitioner.name usw. werden vollständig entfernt (PII_FIELDS aus @polaris/adapter-common)
- Freitext-Scrubbing: DocumentReference.description und AllergyIntolerance.note[].text — betitelte Namen (Dr./Hr./Fr.), Datumsangaben (TT.MM.JJJJ), Telefonnummern (+49/0…) und KV-Nummern (A123456789) werden durch Tokens ersetzt
- ID-Hashing: SHA-256(POLARIS_ANON_SALT + ':' + id) → anon-<12hex> (deterministisch)
- Referenz-Rewriting: Patient/p-123 → Patient/anon-<hash> (auch absolute URLs)
- Display-Felder: subject.display, participant[].individual.display → [NAME]
- Write-Echoes: POST/PUT-Antworten werden ebenfalls anonymisiert
Konfiguration und Anforderungen
- POLARIS_ANON_SALT muss als Umgebungsvariable gesetzt sein — ein geheimes Salt-String, das die ID-Hashes deterministisch macht
- Fehlt das Salt, wirft createFhirDeClient synchron bei der Initialisierung — kein stiller Datenleck
- Das Salt kann alternativ direkt an new AnonymizingTransport(transport, salt) übergeben werden (z. B. in Tests)
- Die exportierten Konstanten FREE_TEXT_FIELDS und PII_FIELDS definieren den genauen Scrubbing-Scope
- Freitext-Scrubbing erfasst nur betitelte Namen (Dr./Hr./Fr.) — Bare-Bigrams werden bewusst nicht gematcht, um klinische Termini (z. B. "Diabetes Mellitus") nicht zu scrubben
Polaris platform
Platform integration — what the platform provides.
When building on the Polaris platform, the adapter-sdk (an internal package, separate from @polaris/fhir-de) manages the platform-layer concerns. Application code still uses the same resource builders and extension constants from @polaris/fhir-de.
What the platform handles
- Aidbox lifecycle and configuration
- Multi-tenant identity and access control (Practitioner JWT)
- PVS adapter sync scheduling and reconciliation
- MCP agent surface with anonymization and audit trail
What your application provides
- Business logic and UI
- FHIR resource construction using @polaris/fhir-de builders
- Domain-specific workflows on top of the FHIR contract
- Extension constants imported — never hardcoded