rxome-generator 1.0.4-beta.1 → 1.0.4-beta.3

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.
@@ -0,0 +1,380 @@
1
+ # RxOME QR Code Generator -- JSON Input Format
2
+
3
+ ## Overview
4
+
5
+ The RxOME QR code generator accepts a JSON object following the
6
+ **PhenoPacket v2** standard with RxOME-specific extensions. The input
7
+ describes a patient's clinical and genomic data, which is then
8
+ protobuf-encoded, encrypted, and rendered as a QR code.
9
+
10
+ ---
11
+
12
+ ## Top-Level Structure
13
+
14
+ ```json
15
+ {
16
+ "id": "string",
17
+ "comment": "string",
18
+ "subject": { ... },
19
+ "phenotypicFeatures": [ ... ],
20
+ "compressedFeatures": { ... },
21
+ "interpretations": [ ... ],
22
+ "diagnosis": { ... },
23
+ "metaData": { ... },
24
+ "credentials": { ... }
25
+ }
26
+ ```
27
+
28
+ All top-level fields are optional except `credentials` (required for QR
29
+ generation but stripped before encoding).
30
+
31
+ ---
32
+
33
+ ## Field Reference
34
+
35
+ ### Root Fields
36
+
37
+ | Field | Type | Required | Description |
38
+ |-------|------|----------|-------------|
39
+ | `id` | string | No | Unique QR code / record identifier |
40
+ | `comment` | string | No | Free-text remarks |
41
+ | `subject` | object | No | Patient demographics |
42
+ | `phenotypicFeatures` | array | No | HPO terms (detailed form) |
43
+ | `compressedFeatures` | object | No | HPO terms (compact form, preferred) |
44
+ | `interpretations` | array | No | Genomic findings and diagnoses |
45
+ | `diagnosis` | object | No | Disease/condition information |
46
+ | `metaData` | object | No | Creator info, timestamps, schema version |
47
+ | `credentials` | object | **Yes** | API credentials (never encoded in QR) |
48
+
49
+ > **Note:** Supply either `phenotypicFeatures` or `compressedFeatures`,
50
+ > not both. If `phenotypicFeatures` is provided it is automatically
51
+ > converted to `compressedFeatures` during preprocessing.
52
+
53
+ ---
54
+
55
+ ### `subject` -- Patient Information
56
+
57
+ ```json
58
+ "subject": {
59
+ "id": "proband A",
60
+ "dateOfBirth": "1994-01-01T00:00:00Z",
61
+ "sex": "FEMALE",
62
+ "gender": { "id": "...", "label": "..." },
63
+ "alternateIds": ["ID-2"],
64
+ "vitalStatus": { ... },
65
+ "karyotypicSex": "XX",
66
+ "taxonomy": { "id": "NCBITaxon:9606", "label": "Homo sapiens" },
67
+ "timeAtLastEncounter": { ... }
68
+ }
69
+ ```
70
+
71
+ **Sex values:** `"UNKNOWN_SEX"` / `0`, `"FEMALE"` / `1`, `"MALE"` / `2`,
72
+ `"OTHER_SEX"` / `3`. String values are converted to numbers during
73
+ sanitisation.
74
+
75
+ ---
76
+
77
+ ### `phenotypicFeatures` -- Detailed HPO Terms
78
+
79
+ ```json
80
+ "phenotypicFeatures": [
81
+ {
82
+ "type": { "id": "HP:0030084", "label": "Clinodactyly" },
83
+ "excluded": false,
84
+ "severity": { "id": "HP:0012825", "label": "Mild" },
85
+ "modifiers": [],
86
+ "onset": { ... },
87
+ "resolution": { ... },
88
+ "evidence": [],
89
+ "description": "..."
90
+ }
91
+ ]
92
+ ```
93
+
94
+ Set `excluded: true` to indicate a feature is explicitly absent.
95
+
96
+ ---
97
+
98
+ ### `compressedFeatures` -- Compact HPO Terms (Preferred)
99
+
100
+ ```json
101
+ "compressedFeatures": {
102
+ "includes": ["HP:0030084", "HP:0000555", "HP:0000486"],
103
+ "excludes": ["HP:0031360"]
104
+ }
105
+ ```
106
+
107
+ This is the preferred input form. It contains only the HPO IDs, separated
108
+ into present (`includes`) and absent (`excludes`) features.
109
+
110
+ ---
111
+
112
+ ### `interpretations` -- Genomic Findings
113
+
114
+ ```json
115
+ "interpretations": [
116
+ {
117
+ "id": "interpretation.id",
118
+ "progressStatus": "SOLVED",
119
+ "diagnosis": {
120
+ "disease": {
121
+ "id": "OMIM:263750",
122
+ "label": "Optional disease label"
123
+ },
124
+ "genomicInterpretations": [
125
+ {
126
+ "subjectOrBiosampleId": "optional.id",
127
+ "interpretationStatus": 0,
128
+ "variantInterpretation": {
129
+ "acmgPathogenicityClassification": "PATHOGENIC",
130
+ "variationDescriptor": {
131
+ "geneContext": {
132
+ "valueId": "HGNC:9884",
133
+ "symbol": "RB1",
134
+ "alternateIds": ["5925"],
135
+ "description": "..."
136
+ },
137
+ "expressions": [
138
+ { "syntax": "hgvs.c", "value": "NM_000321.2:c.958C>T" },
139
+ { "syntax": "iscn", "value": "..." }
140
+ ],
141
+ "allelicState": {
142
+ "id": "GENO:0000135",
143
+ "label": "heterozygous"
144
+ },
145
+ "extensions": [
146
+ { "name": "test-type", "value": "Exome, short read" },
147
+ { "name": "cnv", "value": "1" },
148
+ { "name": "meth", "value": "1" },
149
+ { "name": "af", "value": "0.5" },
150
+ { "name": "rl", "value": "42" },
151
+ { "name": "chr", "value": "13q14.2" },
152
+ { "name": "site", "value": "..." },
153
+ { "name": "upd", "value": "..." }
154
+ ]
155
+ }
156
+ }
157
+ }
158
+ ]
159
+ }
160
+ }
161
+ ]
162
+ ```
163
+
164
+ #### Enum Values
165
+
166
+ **progressStatus:**
167
+ `"UNKNOWN_PROGRESS"` (0), `"IN_PROGRESS"` (1), `"COMPLETED"` (2),
168
+ `"SOLVED"` (3), `"UNSOLVED"` (4)
169
+
170
+ **acmgPathogenicityClassification:**
171
+ `"NOT_PROVIDED"` (0), `"BENIGN"` (1), `"LIKELY_BENIGN"` (2),
172
+ `"UNCERTAIN_SIGNIFICANCE"` (3), `"LIKELY_PATHOGENIC"` (4),
173
+ `"PATHOGENIC"` (5), `"RISK_ALLELE"` (999)
174
+
175
+ > **Note that `RISK_ALLELE` is a RxOME specific extension of the PhenoPackage standard.**
176
+
177
+ **allelicState (Zygosity, GENO ontology):**
178
+
179
+ | Code | Meaning |
180
+ |------|---------|
181
+ | `GENO_0000137` | Unspecified zygosity |
182
+ | `GENO_0000136` | Homozygous |
183
+ | `GENO_0000135` | Heterozygous |
184
+ | `GENO_0000402` | Compound heterozygous |
185
+ | `GENO_0000134` | Hemizygous |
186
+ | `GENO_0000604` | Hemizygous X-linked |
187
+ | `GENO_0000605` | Hemizygous Y-linked |
188
+ | `GENO_0000606` | Hemizygous insertion-linked |
189
+ | `GENO_0000392` | Aneusomic zygosity |
190
+ | `GENO_0000393` | Trisomic homozygous |
191
+ | `GENO_0000394` | Trisomic heterozygous |
192
+ | `GENO_0000602` | Homoplasmic |
193
+ | `GENO_0000603` | Heteroplasmic |
194
+ | `GENO_0000964` | Mosaic |
195
+
196
+ #### RxOME Extension Fields
197
+
198
+ These are carried in the `extensions` array of a `variationDescriptor`:
199
+
200
+ | Name | Values | Description |
201
+ |------|--------|-------------|
202
+ | `test-type` | Free text (e.g. "Exome, short read", "Multigene panel") | Genetic test performed |
203
+ | `cnv` | `0` = not provided, `1` = deletion, `2` = duplication | Copy-number variation |
204
+ | `meth` | `0` = not provided, `1` = hyper, `2` = hypo, `3` = intermediate | Methylation status |
205
+ | `af` | Numeric string | Allele frequency |
206
+ | `rl` | Numeric string | Repeat length |
207
+ | `chr` | String (e.g. "13q14.2") | Chromosomal region |
208
+ | `site` | String | Methylation site |
209
+ | `upd` | String | Uniparental disomy |
210
+
211
+ ---
212
+
213
+ ### `metaData`
214
+
215
+ ```json
216
+ "metaData": {
217
+ "created": "2021-05-14T10:35:00Z",
218
+ "createdBy": "MGZ Munich",
219
+ "submittedBy": "clinician@mgz-muenchen.de",
220
+ "pseudonym": "WDJ6GW2MMZ6A",
221
+ "phenopacketSchemaVersion": "2.0",
222
+ "resources": [],
223
+ "externalReferences": []
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ### `credentials` -- API Access (Never in QR Code)
230
+
231
+ ```json
232
+ "credentials": {
233
+ "keyId": "rxome",
234
+ "key": "Rf7VbeUBQmjvAagwsWx6riaZYc7h4OBD4CuxYyZ5bgA=",
235
+ "keyFile": "/path/to/key",
236
+ "user": "clinician@mgz-muenchen.de"
237
+ }
238
+ ```
239
+
240
+ Provide either `key` (Base64-encoded Ed25519 private key) or `keyFile`
241
+ (path to key file), not both. This object is stripped before any data
242
+ enters the QR code.
243
+
244
+ ---
245
+
246
+ ## Encoding Pipeline: Plain vs. Protobuf-Compressed Fields
247
+
248
+ The QR code contains two distinct areas: **plain-text metadata** (the
249
+ outer JSON envelope) and an **encrypted payload** (protobuf-encoded
250
+ medical data). The pipeline is:
251
+
252
+ ```
253
+ Input JSON
254
+ |
255
+ v
256
+ [1] Whitelist -- keep only recognised PhenoPacket fields; strip credentials
257
+ |
258
+ v
259
+ [2] Sanitise -- convert string enums to numeric (sex, progressStatus, ACMG)
260
+ |
261
+ v
262
+ [3] HPO compress -- convert phenotypicFeatures[] to compressedFeatures{}
263
+ |
264
+ v
265
+ [4] Protobuf encode -- encode entire medical object to binary (PhenoPacket v2 schema)
266
+ |
267
+ v
268
+ [5] Base64
269
+ |
270
+ v
271
+ [6] PGP encrypt (OpenPGP, Curve25519)
272
+ |
273
+ v
274
+ [7] Assemble QR JSON envelope
275
+ |
276
+ v
277
+ [8] Render QR code (PNG)
278
+ ```
279
+
280
+ ### What Ends Up in the QR Code
281
+
282
+ The final QR code contains a JSON string with this structure:
283
+
284
+ ```json
285
+ {
286
+ "createdBy": "MGZ Munich",
287
+ "labid": "rxome",
288
+ "keyver": "2",
289
+ "apiver": "1.0",
290
+ "pseudonym": "WDJ6GW2MMZ6A",
291
+ "payload": "<PGP-encrypted, Base64-encoded protobuf binary>"
292
+ }
293
+ ```
294
+
295
+ ### Field Classification: Plain-Text vs. Protobuf+Encrypted
296
+
297
+ | Field | Storage in QR | Explanation |
298
+ |-------|--------------|-------------|
299
+ | **PLAIN-TEXT (QR envelope, readable without decryption)** | |
300
+ | `createdBy` | plain | Lab/creator name from metaData |
301
+ | `submittedBy` | plain | Submitter email from metaData |
302
+ | `created` | plain | Creation timestamp from metaData |
303
+ | `labid` | plain | Lab identifier from credentials.keyId |
304
+ | `keyver` | plain | Encryption key version (from API) |
305
+ | `apiver` | plain | API version string |
306
+ | `pseudonym` | plain | Patient pseudonym (from API) |
307
+ | **PROTOBUF-ENCODED + ENCRYPTED (inside `payload`)** | |
308
+ | `id` | protobuf + encrypted | Record identifier |
309
+ | `comment` | protobuf + encrypted | Free-text remarks |
310
+ | `subject` | protobuf + encrypted | All patient demographics (DOB, sex, ...) |
311
+ | `compressedFeatures` | protobuf + encrypted | HPO phenotype terms (includes + excludes) |
312
+ | `interpretations` | protobuf + encrypted | All genomic findings, variants, diagnoses |
313
+ | `diagnosis` | protobuf + encrypted | Disease/condition information |
314
+ | `metaData` | protobuf + encrypted | Full metadata structure (without pseudonym) |
315
+ | **NEVER IN QR** | |
316
+ | `credentials` | not stored | Stripped before encoding; used only for API auth |
317
+
318
+ > **Key insight:** The outer QR envelope carries only non-sensitive
319
+ > routing metadata (who created it, pseudonym, key version). All clinical
320
+ > and genomic data is protobuf-serialised, Base64-encoded, then
321
+ > PGP-encrypted before being placed in the `payload` field.
322
+
323
+ ---
324
+
325
+ ## Complete Example
326
+
327
+ ```json
328
+ {
329
+ "id": "QR-Code ID",
330
+ "comment": "useful remarks",
331
+ "subject": {
332
+ "id": "proband A",
333
+ "dateOfBirth": "1994-01-01T00:00:00Z",
334
+ "sex": "FEMALE"
335
+ },
336
+ "compressedFeatures": {
337
+ "includes": ["HP:0030084", "HP:0000555", "HP:0000486"],
338
+ "excludes": ["HP:0031360"]
339
+ },
340
+ "interpretations": [
341
+ {
342
+ "id": "interpretation.id",
343
+ "progressStatus": "SOLVED",
344
+ "diagnosis": {
345
+ "disease": { "id": "OMIM:263750" },
346
+ "genomicInterpretations": [
347
+ {
348
+ "variantInterpretation": {
349
+ "acmgPathogenicityClassification": "PATHOGENIC",
350
+ "variationDescriptor": {
351
+ "geneContext": {
352
+ "valueId": "HGNC:9884",
353
+ "symbol": "RB1"
354
+ },
355
+ "expressions": [
356
+ { "syntax": "hgvs.c", "value": "NM_000321.2:c.958C>T" }
357
+ ],
358
+ "allelicState": { "id": "GENO:0000135" },
359
+ "extensions": [
360
+ { "name": "test-type", "value": "Exome, short read" }
361
+ ]
362
+ }
363
+ }
364
+ }
365
+ ]
366
+ }
367
+ }
368
+ ],
369
+ "metaData": {
370
+ "created": "2021-05-14T10:35:00Z",
371
+ "createdBy": "MGZ Munich",
372
+ "submittedBy": "clinician@mgz-muenchen.de"
373
+ },
374
+ "credentials": {
375
+ "key": "Rf7VbeUBQmjvAagwsWx6riaZYc7h4OBD4CuxYyZ5bgA=",
376
+ "keyId": "rxome",
377
+ "user": "clinician@mgz-muenchen.de"
378
+ }
379
+ }
380
+ ```
@@ -0,0 +1,144 @@
1
+ {
2
+ "id": "QR-Code ID",
3
+ "comment": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in",
4
+ "subject": {
5
+ "id": "proband A",
6
+ "dateOfBirth": "1994-01-01T00:00:00Z",
7
+ "sex": "FEMALE"
8
+ },
9
+ "phenotypicFeatures": [
10
+ {
11
+ "type": {
12
+ "id": "HP:0030084"
13
+ }
14
+ },
15
+ {
16
+ "type": {
17
+ "id": "HP:0000555"
18
+ }
19
+ },
20
+ {
21
+ "type": {
22
+ "id": "HP:0000486"
23
+ }
24
+ },
25
+ {
26
+ "type": {
27
+ "id": "HP:0000541"
28
+ }
29
+ },
30
+ {
31
+ "type": {
32
+ "id": "HP:0084369"
33
+ }
34
+ },
35
+ {
36
+ "type": {
37
+ "id": "HP:0112358"
38
+ }
39
+ },
40
+ {
41
+ "type": {
42
+ "id": "HP:0000145"
43
+ }
44
+ },
45
+ {
46
+ "type": {
47
+ "id": "HP:1234567"
48
+ }
49
+ },
50
+ {
51
+ "type": {
52
+ "id": "HP:9876543"
53
+ }
54
+ },
55
+ {
56
+ "type": {
57
+ "id": "HP:5678912"
58
+ }
59
+ },
60
+ {
61
+ "type": {
62
+ "id": "HP:0031360"
63
+ },
64
+ "excluded": true
65
+ },
66
+ {
67
+ "type": {
68
+ "id": "HP:0001234"
69
+ },
70
+ "excluded": true
71
+ }
72
+ ],
73
+ "interpretations": [
74
+ {
75
+ "id": "interpretation.id",
76
+ "progressStatus": "SOLVED",
77
+ "diagnosis": {
78
+ "disease": {
79
+ "id": "OMIM:263750"
80
+ },
81
+ "genomicInterpretations": [
82
+ {
83
+ "variantInterpretation": {
84
+ "acmgPathogenicityClassification": "PATHOGENIC",
85
+ "variationDescriptor": {
86
+ "geneContext": {
87
+ "valueId": "HGNC:9884",
88
+ "symbol": "RB1"
89
+ },
90
+ "expressions": [
91
+ {
92
+ "syntax": "hgvs.c",
93
+ "value": "NM_000321.2:c.958C>T"
94
+ }
95
+ ],
96
+ "allelicState": {
97
+ "id": "GENO:0000135"
98
+ },
99
+ "extensions": [
100
+ {
101
+ "name": "test-type",
102
+ "value": "Exome, short read"
103
+ }
104
+ ]
105
+ }
106
+ }
107
+ },
108
+ {
109
+ "variantInterpretation": {
110
+ "acmgPathogenicityClassification": "LIKELY_PATHOGENIC",
111
+ "variationDescriptor": {
112
+ "geneContext": {
113
+ "valueId": "HGNC:9884",
114
+ "symbol": "RB1"
115
+ },
116
+ "expressions": [
117
+ {
118
+ "syntax": "hgvs.c",
119
+ "value": "NM_000321.2:c.1234A>G"
120
+ }
121
+ ],
122
+ "allelicState": {
123
+ "label": "heterozygous"
124
+ },
125
+ "extensions": [
126
+ {
127
+ "name": "test-type",
128
+ "value": "Exome, short read"
129
+ }
130
+ ]
131
+ }
132
+ }
133
+ }
134
+ ]
135
+ }
136
+ }
137
+ ],
138
+ "metaData": {
139
+ "created": "2021-05-14T10:35:00Z",
140
+ "createdBy": "mgz",
141
+ "submittedBy": "a_clinician@mgz-muenchen.de",
142
+ "phenopacketSchemaVersion": "2.0"
143
+ }
144
+ }
@@ -679,7 +679,8 @@ export default
679
679
  "LIKELY_BENIGN": 2,
680
680
  "UNCERTAIN_SIGNIFICANCE": 3,
681
681
  "LIKELY_PATHOGENIC": 4,
682
- "PATHOGENIC": 5
682
+ "PATHOGENIC": 5,
683
+ "RISK_ALLELE": 999
683
684
  }
684
685
  },
685
686
  "TherapeuticActionability": {
package/lib/rxome-api.js CHANGED
@@ -3,6 +3,14 @@ import * as ED from 'noble-ed25519';
3
3
  import Protobuf from 'protobufjs';
4
4
  import { stringify } from 'querystring';
5
5
 
6
+ // Environment-aware fetch function
7
+ export async function getFetch() {
8
+ if (typeof window !== 'undefined') {
9
+ return window.fetch;
10
+ }
11
+ return (await import('node-fetch')).default;
12
+ }
13
+
6
14
  const API = 'https://app.findme2care.de';
7
15
  const TESTAPI = 'https://stage.findme2care.de';
8
16
  const APIENTRY = 'api/v1';
@@ -122,6 +130,7 @@ export const fetchData = async ( url, credentials, pseudonym = '', debug = false
122
130
  const controller = new AbortController();
123
131
  const timeoutId = setTimeout(() => controller.abort(), 5000);
124
132
 
133
+ const fetch = await getFetch();
125
134
  return fetch(fullUrl, {
126
135
  method: 'GET',
127
136
  headers: {
@@ -186,6 +195,7 @@ export const pushData = async ( url, credentials, msg, debug = false ) => {
186
195
  const controller = new AbortController();
187
196
  const timeoutId = setTimeout(() => controller.abort(), 5000);
188
197
 
198
+ const fetch = await getFetch();
189
199
  return fetch(url, {
190
200
  method: 'POST',
191
201
  headers: {
@@ -150,11 +150,15 @@ export const sanitizeProgState = ( str ) =>
150
150
  : +str;
151
151
 
152
152
 
153
- export const sanitizeACMG = ( str ) =>
153
+ export const sanitizeACMG = ( str ) => {
154
+ // special case for 'RISK_ALLELE'
155
+ if ( str == 'RISK_ALLELE' ) {
156
+ return 999;
157
+ }
154
158
  isNaN(+(str.toString()))
155
159
  ? Math.max(0, ENUM_ACMG.indexOf(str.toUpperCase()))
156
160
  : +str
157
-
161
+ }
158
162
 
159
163
  export const whiteListPhenoPacket = ( data ) => {
160
164
  let res = {};
@@ -1,6 +1,7 @@
1
1
  import * as Coder from './rxome-generator.js';
2
2
  import * as RxAPI from './rxome-api.js';
3
3
  import * as ApiDemo from './rxome-api-demo.js';
4
+ import { getFetch } from './rxome-api.js';
4
5
 
5
6
  import { readFileSync } from 'fs';
6
7
  // Using native fetch API instead of axios
@@ -294,6 +295,7 @@ describe('Rails', () => {
294
295
  const params = new URLSearchParams({
295
296
  cipher: cipher
296
297
  });
298
+ const fetch = await getFetch();
297
299
  const res = await fetch(`${RXTESTAPI}/api/v1/decryptTest?${params}`, {
298
300
  method: 'GET',
299
301
  headers: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rxome-generator",
3
- "version": "1.0.4-beta.1",
3
+ "version": "1.0.4-beta.3",
4
4
  "description": "Generates QR codes containing medical information for use with the FindMe2Care platform.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -32,9 +32,10 @@
32
32
  "homepage": "https://github.com/GeneTalkTK/rxome-qrcode-generator#readme",
33
33
  "dependencies": {
34
34
  "@noble/ed25519": "^2.2.3",
35
- "commander": "^13.1.0",
35
+ "commander": "^9.4.0",
36
36
  "json-key-converter": "^1.0.0",
37
37
  "noble-ed25519": "^1.2.6",
38
+ "node-fetch": "^3.3.2",
38
39
  "openpgp": "^6.1.0",
39
40
  "protobufjs": "^7.4.0",
40
41
  "protobufjs-cli": "^1.1.3",
package/rxcode.js CHANGED
@@ -186,6 +186,10 @@ program.command('preprocess')
186
186
  .option('-c, --compress', 'Compact HPO term list')
187
187
  .action( async (inputfile, options) => {
188
188
  let data = JSON.parse(FS.readFileSync( inputfile || '/dev/stdin' ));
189
+ if (! (options.case || options.whitelist || options.sanitize || options.compress)) {
190
+ process.stderr.write( 'Error: at least one preprocessing option must be selected (-C, -w, -s, -c).');
191
+ return 1;
192
+ }
189
193
  options.case && (data = Coder.convertToCamelCase( data ));
190
194
  options.whitelist && (data = Coder.whiteListPhenoPacket( data ));
191
195
  options.sanitize && (data = Coder.sanitizePhenoPacket( data ));