@openedc/sdk 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -0
- package/openedc-sdk.d.ts +1136 -0
- package/openedc-sdk.js +23181 -0
- package/package.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
<br>
|
|
2
|
+
<div align="center">
|
|
3
|
+
<img src="../public/icons/custom/openedc.svg" alt="OpenEDC Logo" width="48">
|
|
4
|
+
|
|
5
|
+
### SDK for the OpenEDC Health Platform
|
|
6
|
+
#### OpenEDC Health is a modular, standards-compliant platform for medical research
|
|
7
|
+
</div>
|
|
8
|
+
<br>
|
|
9
|
+
|
|
10
|
+
The official TypeScript SDK for the OpenEDC Health Platform — a modular, standards-compliant platform for medical research.
|
|
11
|
+
|
|
12
|
+
Fully typed end-to-end, it runs on any modern JavaScript runtime (Node, Deno, Bun) and gives you a clean, expressive API to work with all aspects of a clinical study:
|
|
13
|
+
|
|
14
|
+
- **Query** metadata, clinical data, administrative data, and more — with filtering, sorting, and cross-project support
|
|
15
|
+
- **Mutate** study data with a single `.commit()` call, including cascading saves across related records
|
|
16
|
+
- **Stream live updates** via reactive queries that automatically reflect changes in real time
|
|
17
|
+
- **Track changes** with a built-in audit trail for all relevant study data
|
|
18
|
+
- **Manage files** with resumable uploads and signed downloads, supporting files up to 5 GB
|
|
19
|
+
|
|
20
|
+
## Getting started
|
|
21
|
+
|
|
22
|
+
### Installation
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
# npm
|
|
26
|
+
npm install @openedc/sdk
|
|
27
|
+
|
|
28
|
+
# pnpm / yarn / bun
|
|
29
|
+
pnpm add @openedc/sdk
|
|
30
|
+
|
|
31
|
+
# Deno
|
|
32
|
+
deno add npm:@openedc/sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Initialization
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { login, logout } from "@openedc/sdk";
|
|
39
|
+
|
|
40
|
+
const user = await login({
|
|
41
|
+
serverUrl: "server-base-url",
|
|
42
|
+
apiKey: "your-api-key"
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await logout();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
### Data querying, creation, and modification
|
|
51
|
+
|
|
52
|
+
#### Explicit project scope
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { Project, Location, SubjectData } from "@openedc/sdk";
|
|
56
|
+
|
|
57
|
+
// Get project by name
|
|
58
|
+
const project = await Project
|
|
59
|
+
.where({ name: "Exemplary study" })
|
|
60
|
+
.first();
|
|
61
|
+
|
|
62
|
+
// Get the first location
|
|
63
|
+
const location = await Location
|
|
64
|
+
.where()
|
|
65
|
+
.project(project)
|
|
66
|
+
.first();
|
|
67
|
+
|
|
68
|
+
// Get all subjects from a location sorted by creation
|
|
69
|
+
const subjects = await SubjectData
|
|
70
|
+
.where({ location })
|
|
71
|
+
.project(project)
|
|
72
|
+
.sort("createdDate")
|
|
73
|
+
.asc().all();
|
|
74
|
+
|
|
75
|
+
// Create a new subject within a location
|
|
76
|
+
const subject = await new SubjectData("Patient-001", location.reference)
|
|
77
|
+
.commit({ project });
|
|
78
|
+
|
|
79
|
+
// Update an existing subject (no need to specify the project again)
|
|
80
|
+
subject.subjectKey = "Patient-002";
|
|
81
|
+
await subject.commit();
|
|
82
|
+
|
|
83
|
+
// Alternatively, use .set() for a single expression
|
|
84
|
+
await subject.set({ subjectKey: "Patient-003" }).commit();
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### Global project scope
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { Location, SubjectData } from "@openedc/sdk";
|
|
91
|
+
|
|
92
|
+
// Instead of specifying the project for each query or commit, it can also be scoped globally for
|
|
93
|
+
// all upcoming statements. This can be changed at any time but shouldn't be used when handling
|
|
94
|
+
// multiple projects at the same time. Will be assumed to be set for the rest of the examples.
|
|
95
|
+
scope(project);
|
|
96
|
+
|
|
97
|
+
const sameLocation = await Location
|
|
98
|
+
.where()
|
|
99
|
+
.first();
|
|
100
|
+
|
|
101
|
+
const sameSubjects = await SubjectData
|
|
102
|
+
.where({ location })
|
|
103
|
+
.sort("createdDate")
|
|
104
|
+
.asc().all();
|
|
105
|
+
|
|
106
|
+
// Create a new subject (note that Patient-003 would result in a unique constraint violation)
|
|
107
|
+
const newSubject = await new SubjectData("Patient-004").commit();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Clinical data retrieval
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { ItemGroupDef, ItemDef, ItemData } from "@openedc/sdk";
|
|
114
|
+
|
|
115
|
+
// Get data for specific subject and form (project-scoped from above)
|
|
116
|
+
const form = await ItemGroupDef
|
|
117
|
+
.where({
|
|
118
|
+
type: "Form",
|
|
119
|
+
name: "Demographics"
|
|
120
|
+
})
|
|
121
|
+
.first();
|
|
122
|
+
|
|
123
|
+
const formData = await ItemData
|
|
124
|
+
.where({
|
|
125
|
+
subject,
|
|
126
|
+
formOID: form?.oid
|
|
127
|
+
})
|
|
128
|
+
.all();
|
|
129
|
+
|
|
130
|
+
// Get data for specific subject, form, and item (using a form-scoped local search)
|
|
131
|
+
const item = form?.find(ItemDef, "name", "Gender");
|
|
132
|
+
|
|
133
|
+
const itemData = await ItemData
|
|
134
|
+
.where({
|
|
135
|
+
subject,
|
|
136
|
+
formOID: form?.oid,
|
|
137
|
+
itemOID: item?.oid
|
|
138
|
+
})
|
|
139
|
+
.all();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Live queries
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
// Subscribe to subject changes with a live query
|
|
146
|
+
await SubjectData.where({ location }).all((_, subject, method) => {
|
|
147
|
+
console.log(`Subject ${subject.subjectKey} was ${method} in ${location.name}.`);
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
// Subscribe to item data changes via the form status as proxy
|
|
153
|
+
await FormStatus.where().all(async (_, status) => {
|
|
154
|
+
const subject = await status.subject.data;
|
|
155
|
+
const items = await ItemData.where(ODMPath.with(status).toObject()).all();
|
|
156
|
+
console.log(`Updated form with ${items.length} items for subject ${subject.subjectKey}.`);
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Audit trail
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
// Get the audit trail of all subjects within a project
|
|
164
|
+
const auditTrailSubjects = await SubjectData.where().audit();
|
|
165
|
+
|
|
166
|
+
// Get the audit trail of all item data of a given subject
|
|
167
|
+
const auditTrailItemsBySubject = await ItemData.where({ subject }).audit();
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### File management
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
// Upload a file (only readable to users with access to the subject)
|
|
174
|
+
const file = new File(["exemplary-data"], "file.txt");
|
|
175
|
+
const fileMetadata = await new FileMetadata(file, subject.reference).commit();
|
|
176
|
+
const fileContent = await new FileContent(fileMetadata.reference, file).commit();
|
|
177
|
+
|
|
178
|
+
// Track upload progress in real time
|
|
179
|
+
await fileContent.upload(progress => {
|
|
180
|
+
console.log(`Upload progress: ${progress * 100}`);
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
// Download a file
|
|
186
|
+
const downloadMetadata = await FileMetadata.where({ fileName: "file.txt" }).first();
|
|
187
|
+
const downloadContent = await FileContent.where({ metadata: downloadMetadata }).first();
|
|
188
|
+
const downloadURL = await downloadContent?.getUrl();
|
|
189
|
+
```
|