@awell-health/awell-extensions 2.1.151 → 2.1.152
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/dist/extensions/metriport/actions/index.d.ts +84 -0
- package/dist/extensions/metriport/settings.d.ts +12 -0
- package/dist/extensions/metriport/settings.js +61 -1
- package/dist/extensions/metriport/settings.js.map +1 -1
- package/dist/extensions/metriport/validation/settings.zod.d.ts +3 -0
- package/dist/extensions/metriport/validation/settings.zod.js +2 -0
- package/dist/extensions/metriport/validation/settings.zod.js.map +1 -1
- package/dist/extensions/metriport/webhooks/enrollment.js +30 -2
- package/dist/extensions/metriport/webhooks/enrollment.js.map +1 -1
- package/dist/extensions/metriport/webhooks/index.d.ts +7 -0
- package/package.json +1 -1
|
@@ -29,6 +29,13 @@ export declare const actions: {
|
|
|
29
29
|
description: string;
|
|
30
30
|
required: false;
|
|
31
31
|
};
|
|
32
|
+
rateLimitDuration: {
|
|
33
|
+
key: string;
|
|
34
|
+
label: string;
|
|
35
|
+
obfuscated: false;
|
|
36
|
+
description: string;
|
|
37
|
+
required: false;
|
|
38
|
+
};
|
|
32
39
|
}, "firstName" | "lastName" | "email" | "dob" | "phone" | "city" | "country" | "state" | "zip" | "addressLine1" | "addressLine2" | "genderAtBirth" | "driversLicenseValue" | "driversLicenseState">;
|
|
33
40
|
createPatient: import("@awell-health/extensions-core").Action<{
|
|
34
41
|
phone: {
|
|
@@ -159,6 +166,13 @@ export declare const actions: {
|
|
|
159
166
|
description: string;
|
|
160
167
|
required: false;
|
|
161
168
|
};
|
|
169
|
+
rateLimitDuration: {
|
|
170
|
+
key: string;
|
|
171
|
+
label: string;
|
|
172
|
+
obfuscated: false;
|
|
173
|
+
description: string;
|
|
174
|
+
required: false;
|
|
175
|
+
};
|
|
162
176
|
}, "patientId">;
|
|
163
177
|
updatePatient: import("@awell-health/extensions-core").Action<{
|
|
164
178
|
phone: {
|
|
@@ -296,6 +310,13 @@ export declare const actions: {
|
|
|
296
310
|
description: string;
|
|
297
311
|
required: false;
|
|
298
312
|
};
|
|
313
|
+
rateLimitDuration: {
|
|
314
|
+
key: string;
|
|
315
|
+
label: string;
|
|
316
|
+
obfuscated: false;
|
|
317
|
+
description: string;
|
|
318
|
+
required: false;
|
|
319
|
+
};
|
|
299
320
|
}, string>;
|
|
300
321
|
deletePatient: import("@awell-health/extensions-core").Action<{
|
|
301
322
|
facilityId: {
|
|
@@ -334,6 +355,13 @@ export declare const actions: {
|
|
|
334
355
|
description: string;
|
|
335
356
|
required: false;
|
|
336
357
|
};
|
|
358
|
+
rateLimitDuration: {
|
|
359
|
+
key: string;
|
|
360
|
+
label: string;
|
|
361
|
+
obfuscated: false;
|
|
362
|
+
description: string;
|
|
363
|
+
required: false;
|
|
364
|
+
};
|
|
337
365
|
}, string>;
|
|
338
366
|
listDocuments: import("@awell-health/extensions-core").Action<{
|
|
339
367
|
patientId: {
|
|
@@ -365,6 +393,13 @@ export declare const actions: {
|
|
|
365
393
|
description: string;
|
|
366
394
|
required: false;
|
|
367
395
|
};
|
|
396
|
+
rateLimitDuration: {
|
|
397
|
+
key: string;
|
|
398
|
+
label: string;
|
|
399
|
+
obfuscated: false;
|
|
400
|
+
description: string;
|
|
401
|
+
required: false;
|
|
402
|
+
};
|
|
368
403
|
}, "documents">;
|
|
369
404
|
queryDocs: import("@awell-health/extensions-core").Action<{
|
|
370
405
|
patientId: {
|
|
@@ -402,6 +437,13 @@ export declare const actions: {
|
|
|
402
437
|
description: string;
|
|
403
438
|
required: false;
|
|
404
439
|
};
|
|
440
|
+
rateLimitDuration: {
|
|
441
|
+
key: string;
|
|
442
|
+
label: string;
|
|
443
|
+
obfuscated: false;
|
|
444
|
+
description: string;
|
|
445
|
+
required: false;
|
|
446
|
+
};
|
|
405
447
|
}, "downloadStatus" | "downloadTotal" | "downloadSuccessful" | "requestId">;
|
|
406
448
|
getUrl: import("@awell-health/extensions-core").Action<{
|
|
407
449
|
fileName: {
|
|
@@ -433,6 +475,13 @@ export declare const actions: {
|
|
|
433
475
|
description: string;
|
|
434
476
|
required: false;
|
|
435
477
|
};
|
|
478
|
+
rateLimitDuration: {
|
|
479
|
+
key: string;
|
|
480
|
+
label: string;
|
|
481
|
+
obfuscated: false;
|
|
482
|
+
description: string;
|
|
483
|
+
required: false;
|
|
484
|
+
};
|
|
436
485
|
}, "url">;
|
|
437
486
|
startNetworkQuery: import("@awell-health/extensions-core").Action<{
|
|
438
487
|
patientId: {
|
|
@@ -464,6 +513,13 @@ export declare const actions: {
|
|
|
464
513
|
description: string;
|
|
465
514
|
required: false;
|
|
466
515
|
};
|
|
516
|
+
rateLimitDuration: {
|
|
517
|
+
key: string;
|
|
518
|
+
label: string;
|
|
519
|
+
obfuscated: false;
|
|
520
|
+
description: string;
|
|
521
|
+
required: false;
|
|
522
|
+
};
|
|
467
523
|
}, "status" | "requestId">;
|
|
468
524
|
startConsolidatedQuery: import("@awell-health/extensions-core").Action<{
|
|
469
525
|
patientId: {
|
|
@@ -519,6 +575,13 @@ export declare const actions: {
|
|
|
519
575
|
description: string;
|
|
520
576
|
required: false;
|
|
521
577
|
};
|
|
578
|
+
rateLimitDuration: {
|
|
579
|
+
key: string;
|
|
580
|
+
label: string;
|
|
581
|
+
obfuscated: false;
|
|
582
|
+
description: string;
|
|
583
|
+
required: false;
|
|
584
|
+
};
|
|
522
585
|
}, "status" | "requestId">;
|
|
523
586
|
getConsolidatedQueryStatus: import("@awell-health/extensions-core").Action<{
|
|
524
587
|
patientId: {
|
|
@@ -550,6 +613,13 @@ export declare const actions: {
|
|
|
550
613
|
description: string;
|
|
551
614
|
required: false;
|
|
552
615
|
};
|
|
616
|
+
rateLimitDuration: {
|
|
617
|
+
key: string;
|
|
618
|
+
label: string;
|
|
619
|
+
obfuscated: false;
|
|
620
|
+
description: string;
|
|
621
|
+
required: false;
|
|
622
|
+
};
|
|
553
623
|
}, "status" | "queries">;
|
|
554
624
|
getWebhookBundle: import("@awell-health/extensions-core").Action<{
|
|
555
625
|
url: {
|
|
@@ -601,6 +671,13 @@ export declare const actions: {
|
|
|
601
671
|
description: string;
|
|
602
672
|
required: false;
|
|
603
673
|
};
|
|
674
|
+
rateLimitDuration: {
|
|
675
|
+
key: string;
|
|
676
|
+
label: string;
|
|
677
|
+
obfuscated: false;
|
|
678
|
+
description: string;
|
|
679
|
+
required: false;
|
|
680
|
+
};
|
|
604
681
|
}, "bundle" | "transactionBundle">;
|
|
605
682
|
removePatientFromCohort: import("@awell-health/extensions-core").Action<{
|
|
606
683
|
cohortId: {
|
|
@@ -639,5 +716,12 @@ export declare const actions: {
|
|
|
639
716
|
description: string;
|
|
640
717
|
required: false;
|
|
641
718
|
};
|
|
719
|
+
rateLimitDuration: {
|
|
720
|
+
key: string;
|
|
721
|
+
label: string;
|
|
722
|
+
obfuscated: false;
|
|
723
|
+
description: string;
|
|
724
|
+
required: false;
|
|
725
|
+
};
|
|
642
726
|
}, "message" | "cohort">;
|
|
643
727
|
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { RateLimitConfig } from '@awell-health/extensions-core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const DEFAULT_DEDUPE_DURATION = "7 d";
|
|
1
4
|
export declare const settings: {
|
|
2
5
|
apiKey: {
|
|
3
6
|
key: string;
|
|
@@ -20,4 +23,13 @@ export declare const settings: {
|
|
|
20
23
|
description: string;
|
|
21
24
|
required: false;
|
|
22
25
|
};
|
|
26
|
+
rateLimitDuration: {
|
|
27
|
+
key: string;
|
|
28
|
+
label: string;
|
|
29
|
+
obfuscated: false;
|
|
30
|
+
description: string;
|
|
31
|
+
required: false;
|
|
32
|
+
};
|
|
23
33
|
};
|
|
34
|
+
export declare const rateLimitDurationSchema: z.ZodEffects<z.ZodString, string, string>;
|
|
35
|
+
export declare const transformRateLimitDuration: (val: string) => RateLimitConfig["duration"];
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.settings = void 0;
|
|
3
|
+
exports.transformRateLimitDuration = exports.rateLimitDurationSchema = exports.settings = exports.DEFAULT_DEDUPE_DURATION = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
exports.DEFAULT_DEDUPE_DURATION = '7 d';
|
|
4
7
|
exports.settings = {
|
|
5
8
|
apiKey: {
|
|
6
9
|
key: 'apiKey',
|
|
@@ -23,5 +26,62 @@ exports.settings = {
|
|
|
23
26
|
description: 'The Metriport webhook key used to verify incoming webhook requests. Metriport signs each request with an HMAC-SHA256 of the raw body using this key, sent in the `x-metriport-signature` header. Found in the Settings/Developers tab of the Metriport dashboard. When left empty, incoming webhook requests are not verified.',
|
|
24
27
|
required: false,
|
|
25
28
|
},
|
|
29
|
+
rateLimitDuration: {
|
|
30
|
+
key: 'rateLimitDuration',
|
|
31
|
+
label: 'Rate Limit Duration',
|
|
32
|
+
obfuscated: false,
|
|
33
|
+
description: "Rate limit Metriport enrollment webhooks at a certain duration (e.g. only enroll once for a given webhook message every '30 s', '1 m', '12 h', '30 d'). Prevents duplicate deliveries of the same message from re-enrolling a patient. Value should be {number} {unit}. Defaults to seven days as '7 d'",
|
|
34
|
+
required: false,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
exports.rateLimitDurationSchema = zod_1.z.string().refine((val) => {
|
|
38
|
+
if ((0, lodash_1.isNil)(val) || (0, lodash_1.isEmpty)(val)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const [number, unit] = val.split(' ');
|
|
43
|
+
const parsedUnit = parseDurationUnit(unit);
|
|
44
|
+
return (0, lodash_1.isFinite)(Number(number)) && !(0, lodash_1.isNil)(parsedUnit);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}, {
|
|
50
|
+
message: 'Duration must be in format {number} {unit} where unit is seconds, minutes, hours or days',
|
|
51
|
+
});
|
|
52
|
+
const parseDurationUnit = (unit) => {
|
|
53
|
+
if ((0, lodash_1.isNil)(unit) || (0, lodash_1.isEmpty)(unit))
|
|
54
|
+
throw new Error('Duration unit is required');
|
|
55
|
+
const normalized = unit.toLowerCase().trim();
|
|
56
|
+
switch (normalized) {
|
|
57
|
+
case 's':
|
|
58
|
+
case 'second':
|
|
59
|
+
case 'seconds':
|
|
60
|
+
return 'seconds';
|
|
61
|
+
case 'm':
|
|
62
|
+
case 'min':
|
|
63
|
+
case 'minute':
|
|
64
|
+
case 'minutes':
|
|
65
|
+
return 'minutes';
|
|
66
|
+
case 'h':
|
|
67
|
+
case 'hour':
|
|
68
|
+
case 'hours':
|
|
69
|
+
return 'hours';
|
|
70
|
+
case 'd':
|
|
71
|
+
case 'day':
|
|
72
|
+
case 'days':
|
|
73
|
+
return 'days';
|
|
74
|
+
default:
|
|
75
|
+
throw new Error(`Invalid duration unit: ${unit}. Valid units are: s, m, h, d`);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const transformRateLimitDuration = (val) => {
|
|
79
|
+
const [number, unit] = val.split(' ');
|
|
80
|
+
const parsedUnit = parseDurationUnit(unit);
|
|
81
|
+
return {
|
|
82
|
+
value: Number(number),
|
|
83
|
+
unit: parsedUnit,
|
|
84
|
+
};
|
|
26
85
|
};
|
|
86
|
+
exports.transformRateLimitDuration = transformRateLimitDuration;
|
|
27
87
|
//# sourceMappingURL=settings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../extensions/metriport/settings.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../extensions/metriport/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,13 @@ import { z } from 'zod';
|
|
|
2
2
|
export declare const settingsSchema: z.ZodObject<{
|
|
3
3
|
baseUrl: z.ZodOptional<z.ZodString>;
|
|
4
4
|
apiKey: z.ZodString;
|
|
5
|
+
rateLimitDuration: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>>;
|
|
5
6
|
}, "strip", z.ZodTypeAny, {
|
|
6
7
|
apiKey: string;
|
|
8
|
+
rateLimitDuration: string;
|
|
7
9
|
baseUrl?: string | undefined;
|
|
8
10
|
}, {
|
|
9
11
|
apiKey: string;
|
|
10
12
|
baseUrl?: string | undefined;
|
|
13
|
+
rateLimitDuration?: string | undefined;
|
|
11
14
|
}>;
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.settingsSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const settings_1 = require("../settings");
|
|
5
6
|
exports.settingsSchema = zod_1.z.object({
|
|
6
7
|
baseUrl: zod_1.z
|
|
7
8
|
.string({ errorMap: () => ({ message: 'Missing baseUrl' }) })
|
|
8
9
|
.optional(),
|
|
9
10
|
apiKey: zod_1.z.string({ errorMap: () => ({ message: 'Missing apiKey' }) }).min(1),
|
|
11
|
+
rateLimitDuration: settings_1.rateLimitDurationSchema.optional().default(settings_1.DEFAULT_DEDUPE_DURATION),
|
|
10
12
|
});
|
|
11
13
|
//# sourceMappingURL=settings.zod.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.zod.js","sourceRoot":"","sources":["../../../../extensions/metriport/validation/settings.zod.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;
|
|
1
|
+
{"version":3,"file":"settings.zod.js","sourceRoot":"","sources":["../../../../extensions/metriport/validation/settings.zod.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AACvB,0CAA8E;AAEjE,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,CAAC;IACrC,OAAO,EAAE,OAAC;SACP,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;SAC5D,QAAQ,EAAE;IACb,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5E,iBAAiB,EAAE,kCAAuB,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,kCAAuB,CAAC;CACvF,CAAC,CAAA"}
|
|
@@ -4,6 +4,7 @@ exports.enrollment = exports.METRIPORT_PATIENT_IDENTIFIER_SYSTEM = void 0;
|
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
6
|
const zod_validation_error_1 = require("zod-validation-error");
|
|
7
|
+
const settings_1 = require("../settings");
|
|
7
8
|
const verifyWebhookSignature_1 = require("../shared/verifyWebhookSignature");
|
|
8
9
|
const types_1 = require("./types");
|
|
9
10
|
const validation_zod_1 = require("./validation.zod");
|
|
@@ -48,8 +49,8 @@ exports.enrollment = {
|
|
|
48
49
|
key: 'enrollment',
|
|
49
50
|
description: 'Enrolls a patient when Metriport sends a real-time notification. The `eventType` data point carries the Metriport webhook type (`patient.admit` or `medical.discharge-summary`) so it can be distinguished on. The FHIR bundle is not fetched here — the pre-signed URL is passed on the `bundleUrl` data point and can be retrieved later with the "Get Webhook Bundle" action.',
|
|
50
51
|
dataPoints,
|
|
51
|
-
onEvent: async ({ payload: { payload, rawBody, headers, settings }, onSuccess, onError, }) => {
|
|
52
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
52
|
+
onEvent: async ({ payload: { payload, rawBody, headers, settings, endpoint }, onSuccess, onError, helpers: { rateLimiter }, }) => {
|
|
53
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
53
54
|
try {
|
|
54
55
|
// Verify the Metriport webhook signature (HMAC-SHA256 over the raw body)
|
|
55
56
|
// when a webhook key is configured. See `verifyWebhookSignature.ts`.
|
|
@@ -138,6 +139,33 @@ exports.enrollment = {
|
|
|
138
139
|
});
|
|
139
140
|
return;
|
|
140
141
|
}
|
|
142
|
+
// rate limiting
|
|
143
|
+
//
|
|
144
|
+
// Keyed on the guaranteed-unique `meta.messageId`. Metriport reuses the
|
|
145
|
+
// same messageId on retries, so this acts as an idempotency/dedup guard:
|
|
146
|
+
// a duplicate delivery of the same message within the configured window is
|
|
147
|
+
// acknowledged with 200 OK (so Metriport stops retrying) but does not
|
|
148
|
+
// re-enroll the patient. Distinct messages always pass.
|
|
149
|
+
const { success, data: durationString } = settings_1.rateLimitDurationSchema.safeParse(settings.rateLimitDuration);
|
|
150
|
+
if (success && !(0, lodash_1.isNil)(durationString)) {
|
|
151
|
+
const duration = (0, settings_1.transformRateLimitDuration)(durationString);
|
|
152
|
+
const limiterName = `metriport-enrollment-${webhook.meta.type}-${(_p = endpoint === null || endpoint === void 0 ? void 0 : endpoint.id) !== null && _p !== void 0 ? _p : 'global'}`;
|
|
153
|
+
const limiter = rateLimiter(limiterName, {
|
|
154
|
+
requests: 1,
|
|
155
|
+
duration,
|
|
156
|
+
});
|
|
157
|
+
const key = webhook.meta.messageId;
|
|
158
|
+
const { success } = await limiter.limit(key);
|
|
159
|
+
if (!success) {
|
|
160
|
+
await onError({
|
|
161
|
+
response: {
|
|
162
|
+
statusCode: 200,
|
|
163
|
+
message: `Rate limit exceeded on limiter ${limiterName} for messageId ${key}. 200 OK response sent to Metriport to prevent re-enrolling patient ${patientId} for a duplicate delivery of this message on endpoint ${(_q = endpoint === null || endpoint === void 0 ? void 0 : endpoint.url) !== null && _q !== void 0 ? _q : 'global'}.`,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
141
169
|
await onSuccess({
|
|
142
170
|
data_points,
|
|
143
171
|
patient_identifier: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrollment.js","sourceRoot":"","sources":["../../../../extensions/metriport/webhooks/enrollment.ts"],"names":[],"mappings":";;;AAAA,mCAA8B;AAC9B,6BAA8B;AAC9B,+DAAmD;
|
|
1
|
+
{"version":3,"file":"enrollment.js","sourceRoot":"","sources":["../../../../extensions/metriport/webhooks/enrollment.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,4 +21,11 @@ export declare const webhooks: import("@awell-health/extensions-core").Webhook<"
|
|
|
21
21
|
description: string;
|
|
22
22
|
required: false;
|
|
23
23
|
};
|
|
24
|
+
rateLimitDuration: {
|
|
25
|
+
key: string;
|
|
26
|
+
label: string;
|
|
27
|
+
obfuscated: false;
|
|
28
|
+
description: string;
|
|
29
|
+
required: false;
|
|
30
|
+
};
|
|
24
31
|
}>[];
|