@openedc/sdk 3.9.1 → 3.9.2

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 CHANGED
@@ -2,8 +2,9 @@
2
2
  <div align="center">
3
3
  <img src="https://openedc.health/logo.png" alt="OpenEDC Logo" width="48">
4
4
 
5
- ### SDK for the OpenEDC Health Platform
6
- #### OpenEDC Health is a modular, standards-compliant platform for medical research
5
+ ### Software Development Kit (SDK) for the OpenEDC Health Platform
6
+ #### OpenEDC Health is a modular, standards-compliant platform for clinical trials and medical research.
7
+ #### Compliant with ICH GCP and FDA CFR Part 11. Validated following GAMP 5 guidelines.
7
8
  </div>
8
9
  <br>
9
10
 
@@ -99,7 +100,7 @@ await subject.set({ subjectKey: "Patient-003" }).commit();
99
100
 
100
101
  #### Global project scope
101
102
 
102
- Instead of specifying the project per call, a global scope can be set for all upcoming statements. This works well for linear, sequential flows but should be avoided in parallel or callback-based code that handles multiple projects concurrently. Assumed for the rest of the examples.
103
+ Instead of specifying the project per call, a global scope can be set for all upcoming statements. This works well for linear, sequential flows but should be avoided in parallel or callback-based code that handles multiple projects concurrently. This scope is assumed for the rest of the examples.
103
104
 
104
105
  ```ts
105
106
  import { scope, Location, SubjectData } from "@openedc/sdk";
@@ -179,6 +180,8 @@ await SubjectData.where({ location }).all((_, subject, method) => {
179
180
  ```
180
181
 
181
182
  ```ts
183
+ import { FormStatus } from "@openedc/sdk";
184
+
182
185
  // Subscribe to item data changes via the form status as proxy
183
186
  await FormStatus.where().all(async (_, status) => {
184
187
  const subject = await status.subject.data;
@@ -200,6 +203,8 @@ const auditTrailItemsBySubject = await ItemData.where({ subject }).audit();
200
203
  ### File management
201
204
 
202
205
  ```ts
206
+ import { FileMetadata, FileContent } from "@openedc/sdk";
207
+
203
208
  // Upload a file (only readable to users with access to the subject)
204
209
  const file = new File(["exemplary-data"], "file.txt");
205
210
  const fileMetadata = await new FileMetadata(file, subject.reference).commit();
@@ -217,3 +222,63 @@ const downloadMetadata = await FileMetadata.where({ fileName: "file.txt" }).firs
217
222
  const downloadContent = await FileContent.where({ metadata: downloadMetadata }).first();
218
223
  const downloadURL = await downloadContent?.getUrl();
219
224
  ```
225
+
226
+ ### Further examples
227
+
228
+ <details>
229
+ <summary>Show</summary>
230
+
231
+ #### Create custom randomization schedule
232
+
233
+ If you want to use a custom randomization schedule that is not yet supported by OpenEDC Health natively, you can use the SDK to upload your own schedule.
234
+
235
+ For this, first create the treatment groups and randomization configuration within the web application that matches your desired configuration as good as possible (e.g., selecting a simple, permuted, or stratified block randomization and choosing stratification variables).
236
+
237
+ Then, fetch the created draft randomization plan and create your schedule programmatically:
238
+
239
+ ```ts
240
+ import { RandomizationPlan, RandomizationSchedule, StudyEventGroupDef } from "@openedc/sdk";
241
+
242
+ // First, fetch the created draft randomization plan
243
+ const plan = await RandomizationPlan.where().first();
244
+
245
+ // Also get the list of your study arms
246
+ const arms = await StudyEventGroupDef.where("armOID").notEquals(undefined).all();
247
+
248
+ // Then, generate and commit your custom randomization schedule as a batch using these parameters:
249
+ // new RandomizationSchedule(planReference, orderNumber, blockNumber, subjectKey, armReference).
250
+ // In this example, 6 entries with a block size of 3 and 2 arms with 2:1 ratio are created.
251
+ await RandomizationSchedule.commit([
252
+ new RandomizationSchedule(plan.reference, 0, 1, 1, arms[0].reference),
253
+ new RandomizationSchedule(plan.reference, 1, 1, 2, arms[0].reference),
254
+ new RandomizationSchedule(plan.reference, 2, 1, 3, arms[1].reference),
255
+ new RandomizationSchedule(plan.reference, 3, 2, 4, arms[1].reference),
256
+ new RandomizationSchedule(plan.reference, 4, 2, 5, arms[0].reference),
257
+ new RandomizationSchedule(plan.reference, 5, 2, 6, arms[0].reference)
258
+ ]);
259
+
260
+ // Finally, update the plan status to be able to see and review it within OpenEDC Health
261
+ await plan.info.set({ status: "review" }).commit();
262
+ ```
263
+
264
+ When using stratification variables, you can specify them for each randomization schedule entry. During randomization, the system will then automatically draw the next available entry for the given values of the current subject.
265
+
266
+ ```ts
267
+ // Specify values for one or more stratification variables (please use the actual
268
+ // location UUID instead of munich and the actual item OID instead of gender)
269
+ await RandomizationSchedule.commit([
270
+ new RandomizationSchedule(plan.reference, 0, 1, 1, arms[0].reference).set({ stratification: {
271
+ locationUUID: "munich",
272
+ gender: "female"
273
+ }}),
274
+ new RandomizationSchedule(plan.reference, 1, 1, 2, arms[0].reference).set({ stratification: {
275
+ locationUUID: "munich",
276
+ gender: "male"
277
+ }}),
278
+ // ...
279
+ ]);
280
+ ```
281
+
282
+ If you want to start over, you can either delete the created randomization schedule within the OpenEDC Health application or execute `await RandomizationSchedule.where({ plan }).delete();` using the SDK.
283
+
284
+ </details>
package/openedc-sdk.d.ts CHANGED
@@ -231,8 +231,8 @@ declare class DataBlock {
231
231
  refresh?: boolean;
232
232
  }, transaction?: string): Promise<this>;
233
233
  static commit(data: DataBlock[], project?: string, reasons?: Record<string, string>, refresh?: boolean): Promise<void>;
234
- protected beforeTrigger(): Promise<void> | void;
235
- protected afterTrigger(): Promise<void> | void;
234
+ protected beforeTrigger(changes: Record<string, unknown>): Promise<void> | void;
235
+ protected afterTrigger(changes: Record<string, unknown>): Promise<void> | void;
236
236
  prepareSerialization(): Promise<void> | void;
237
237
  discard(): Promise<void>;
238
238
  private updateLocalQueryCache;
@@ -240,7 +240,7 @@ declare class DataBlock {
240
240
  cascade?: boolean;
241
241
  reason?: string;
242
242
  }): Promise<undefined>;
243
- get changedFields(): Record<string, unknown>;
243
+ getChanges(state?: Record<string, unknown>): Record<string, unknown>;
244
244
  toObject(): Record<string, unknown>;
245
245
  toString(): string;
246
246
  clone(options?: {
@@ -874,7 +874,7 @@ export declare class Signature extends DataBlock {
874
874
  status: typeof SignatureStatus[keyof typeof SignatureStatus];
875
875
  lastUpdateDatetime: number;
876
876
  constructor(signee?: BlockReference<User>, form?: BlockReference<FormStatus>, dataHash?: string);
877
- beforeTrigger(): void;
877
+ beforeTrigger(changes: Record<string, unknown>): void;
878
878
  }
879
879
  export declare class SurveyInstance extends DataBlock {
880
880
  id: string;