@oystehr/sdk 4.3.7 → 4.3.9
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 +105 -41
- package/dist/cjs/client/client.cjs +137 -5
- package/dist/cjs/client/client.cjs.map +1 -1
- package/dist/cjs/client/client.d.ts +28 -3
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/cjs/index.min.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir-ext.cjs +108 -17
- package/dist/cjs/resources/classes/fhir-ext.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir-ext.d.ts +67 -12
- package/dist/cjs/resources/classes/fhir.cjs +3 -0
- package/dist/cjs/resources/classes/fhir.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir.d.ts +3 -0
- package/dist/cjs/resources/classes/zambda-ext.cjs +23 -3
- package/dist/cjs/resources/classes/zambda-ext.cjs.map +1 -1
- package/dist/cjs/resources/classes/zambda-ext.d.ts +3 -0
- package/dist/cjs/resources/classes/zambda.cjs +13 -0
- package/dist/cjs/resources/classes/zambda.cjs.map +1 -1
- package/dist/cjs/resources/classes/zambda.d.ts +12 -1
- package/dist/cjs/resources/types/ZambdaGetPresignedUrlParams.d.ts +11 -0
- package/dist/cjs/resources/types/ZambdaGetPresignedUrlResponse.d.ts +9 -0
- package/dist/cjs/resources/types/fhir.d.ts +67 -0
- package/dist/cjs/resources/types/index.d.ts +2 -0
- package/dist/esm/client/client.d.ts +28 -3
- package/dist/esm/client/client.js +137 -5
- package/dist/esm/client/client.js.map +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/resources/classes/fhir-ext.d.ts +67 -12
- package/dist/esm/resources/classes/fhir-ext.js +107 -19
- package/dist/esm/resources/classes/fhir-ext.js.map +1 -1
- package/dist/esm/resources/classes/fhir.d.ts +3 -0
- package/dist/esm/resources/classes/fhir.js +4 -1
- package/dist/esm/resources/classes/fhir.js.map +1 -1
- package/dist/esm/resources/classes/zambda-ext.d.ts +3 -0
- package/dist/esm/resources/classes/zambda-ext.js +23 -4
- package/dist/esm/resources/classes/zambda-ext.js.map +1 -1
- package/dist/esm/resources/classes/zambda.d.ts +12 -1
- package/dist/esm/resources/classes/zambda.js +14 -1
- package/dist/esm/resources/classes/zambda.js.map +1 -1
- package/dist/esm/resources/types/ZambdaGetPresignedUrlParams.d.ts +11 -0
- package/dist/esm/resources/types/ZambdaGetPresignedUrlResponse.d.ts +9 -0
- package/dist/esm/resources/types/fhir.d.ts +67 -0
- package/dist/esm/resources/types/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/client/client.ts +214 -7
- package/src/resources/classes/fhir-ext.ts +278 -38
- package/src/resources/classes/fhir.ts +3 -0
- package/src/resources/classes/zambda-ext.ts +30 -3
- package/src/resources/classes/zambda.ts +18 -0
- package/src/resources/types/ZambdaGetPresignedUrlParams.ts +13 -0
- package/src/resources/types/ZambdaGetPresignedUrlResponse.ts +11 -0
- package/src/resources/types/fhir.ts +88 -0
- package/src/resources/types/index.ts +2 -0
|
@@ -1,13 +1,32 @@
|
|
|
1
|
+
import { OystehrSdkError } from '../../errors/index.js';
|
|
2
|
+
|
|
1
3
|
function baseUrlThunk() {
|
|
2
|
-
return this.config.services?.['
|
|
4
|
+
return this.config.services?.['zambdaApiUrl'] ?? 'https://zambda-api.zapehr.com/v1';
|
|
3
5
|
}
|
|
4
6
|
async function uploadFile({ id, file, filename, }) {
|
|
5
|
-
const uploadUrl = await this.request('/zambda/{id}/
|
|
6
|
-
await fetch(uploadUrl.signedUrl, {
|
|
7
|
+
const uploadUrl = await this.request('/zambda/{id}/presigned-url', 'post', baseUrlThunk.bind(this))({ id, action: 'upload', filename });
|
|
8
|
+
const response = await fetch(uploadUrl.signedUrl, {
|
|
7
9
|
method: 'PUT',
|
|
8
10
|
body: file,
|
|
9
11
|
});
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
throw new OystehrSdkError({ message: 'Failed to upload file', code: response.status, cause: response.statusText });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function downloadFile({ id }) {
|
|
17
|
+
const downloadUrl = await this.request('/zambda/{id}/presigned-url', 'post', baseUrlThunk.bind(this))({ id, action: 'download' });
|
|
18
|
+
const response = await fetch(downloadUrl.signedUrl, {
|
|
19
|
+
method: 'GET',
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new OystehrSdkError({
|
|
23
|
+
message: 'Failed to download file',
|
|
24
|
+
code: response.status,
|
|
25
|
+
cause: response.statusText,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return response.arrayBuffer();
|
|
10
29
|
}
|
|
11
30
|
|
|
12
|
-
export { uploadFile };
|
|
31
|
+
export { downloadFile, uploadFile };
|
|
13
32
|
//# sourceMappingURL=zambda-ext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zambda-ext.js","sources":["../../../../src/resources/classes/zambda-ext.ts"],"sourcesContent":["import { SDKResource } from '../../client/client';\n\nfunction baseUrlThunk(this: SDKResource): string {\n return this.config.services?.['
|
|
1
|
+
{"version":3,"file":"zambda-ext.js","sources":["../../../../src/resources/classes/zambda-ext.ts"],"sourcesContent":["import { SDKResource } from '../../client/client';\nimport { OystehrSdkError } from '../../errors';\n\nfunction baseUrlThunk(this: SDKResource): string {\n return this.config.services?.['zambdaApiUrl'] ?? 'https://zambda-api.zapehr.com/v1';\n}\n\nexport async function uploadFile(\n this: SDKResource,\n {\n id,\n file,\n filename,\n }: {\n id: string;\n file: Blob;\n filename?: string | undefined;\n }\n): Promise<void> {\n const uploadUrl = await this.request(\n '/zambda/{id}/presigned-url',\n 'post',\n baseUrlThunk.bind(this)\n )({ id, action: 'upload', filename });\n const response = await fetch(uploadUrl.signedUrl, {\n method: 'PUT',\n body: file,\n });\n if (!response.ok) {\n throw new OystehrSdkError({ message: 'Failed to upload file', code: response.status, cause: response.statusText });\n }\n}\n\nexport async function downloadFile(this: SDKResource, { id }: { id: string }): Promise<ArrayBuffer> {\n const downloadUrl = await this.request(\n '/zambda/{id}/presigned-url',\n 'post',\n baseUrlThunk.bind(this)\n )({ id, action: 'download' });\n const response = await fetch(downloadUrl.signedUrl, {\n method: 'GET',\n });\n if (!response.ok) {\n throw new OystehrSdkError({\n message: 'Failed to download file',\n code: response.status,\n cause: response.statusText,\n });\n }\n return response.arrayBuffer();\n}\n"],"names":[],"mappings":";;AAGA,SAAS,YAAY,GAAA;IACnB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAC,IAAI,kCAAkC;AACrF;AAEO,eAAe,UAAU,CAE9B,EACE,EAAE,EACF,IAAI,EACJ,QAAQ,GAKT,EAAA;AAED,IAAA,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAClC,4BAA4B,EAC5B,MAAM,EACN,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CACxB,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE;AAChD,QAAA,MAAM,EAAE,KAAK;AACb,QAAA,IAAI,EAAE,IAAI;AACX,KAAA,CAAC;AACF,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;QAChB,MAAM,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;IACpH;AACF;AAEO,eAAe,YAAY,CAAoB,EAAE,EAAE,EAAkB,EAAA;IAC1E,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,OAAO,CACpC,4BAA4B,EAC5B,MAAM,EACN,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CACxB,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE;AAClD,QAAA,MAAM,EAAE,KAAK;AACd,KAAA,CAAC;AACF,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;QAChB,MAAM,IAAI,eAAe,CAAC;AACxB,YAAA,OAAO,EAAE,yBAAyB;YAClC,IAAI,EAAE,QAAQ,CAAC,MAAM;YACrB,KAAK,EAAE,QAAQ,CAAC,UAAU;AAC3B,SAAA,CAAC;IACJ;AACA,IAAA,OAAO,QAAQ,CAAC,WAAW,EAAE;AAC/B;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OystehrClientRequest, ZambdaCreateParams, ZambdaCreateResponse, ZambdaDeleteParams, ZambdaExecuteParams, ZambdaExecutePublicParams, ZambdaExecutePublicResponse, ZambdaExecuteResponse, ZambdaGetParams, ZambdaGetResponse, ZambdaListResponse, ZambdaS3UploadParams, ZambdaS3UploadResponse, ZambdaUpdateParams, ZambdaUpdateResponse } from '../..';
|
|
1
|
+
import { OystehrClientRequest, ZambdaCreateParams, ZambdaCreateResponse, ZambdaDeleteParams, ZambdaExecuteParams, ZambdaExecutePublicParams, ZambdaExecutePublicResponse, ZambdaExecuteResponse, ZambdaGetParams, ZambdaGetPresignedUrlParams, ZambdaGetPresignedUrlResponse, ZambdaGetResponse, ZambdaListResponse, ZambdaS3UploadParams, ZambdaS3UploadResponse, ZambdaUpdateParams, ZambdaUpdateResponse } from '../..';
|
|
2
2
|
import { SDKResource } from '../../client/client';
|
|
3
3
|
import { OystehrConfig } from '../../config';
|
|
4
4
|
import * as ext from './zambda-ext';
|
|
@@ -6,6 +6,7 @@ export declare class Zambda extends SDKResource {
|
|
|
6
6
|
#private;
|
|
7
7
|
constructor(config: OystehrConfig);
|
|
8
8
|
uploadFile: typeof ext.uploadFile;
|
|
9
|
+
downloadFile: typeof ext.downloadFile;
|
|
9
10
|
/**
|
|
10
11
|
* Get a list of all Zambda Functions in the Project. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.
|
|
11
12
|
*
|
|
@@ -55,10 +56,20 @@ export declare class Zambda extends SDKResource {
|
|
|
55
56
|
*/
|
|
56
57
|
executePublic(params: ZambdaExecutePublicParams, request?: OystehrClientRequest): Promise<ZambdaExecutePublicResponse>;
|
|
57
58
|
/**
|
|
59
|
+
* **Deprecated.** Use `POST /zambda/{id}/presigned-url` with `action: "upload"` instead. This endpoint will be removed in future releases.
|
|
60
|
+
*
|
|
58
61
|
* Returns a URL that is used to deploy code to the Zambda Function with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.
|
|
59
62
|
*
|
|
60
63
|
* Access Policy Action: `Zambda:UpdateFunction`
|
|
61
64
|
* Access Policy Resource: `Zambda:Function`
|
|
62
65
|
*/
|
|
63
66
|
s3Upload(params: ZambdaS3UploadParams, request?: OystehrClientRequest): Promise<ZambdaS3UploadResponse>;
|
|
67
|
+
/**
|
|
68
|
+
* Returns a presigned URL to upload or download code for the Zambda Function with the provided ID. Pass `action: "upload"` to get a URL for deploying a new code zip, or `action: "download"` to get a URL for retrieving the currently deployed zip. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.
|
|
69
|
+
*
|
|
70
|
+
* Upload: Access Policy Action: `Zambda:UpdateFunction`
|
|
71
|
+
* Download: Access Policy Action: `Zambda:GetFunctionSource`
|
|
72
|
+
* Access Policy Resource: `Zambda:Function`
|
|
73
|
+
*/
|
|
74
|
+
getPresignedUrl(params: ZambdaGetPresignedUrlParams, request?: OystehrClientRequest): Promise<ZambdaGetPresignedUrlResponse>;
|
|
64
75
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SDKResource } from '../../client/client.js';
|
|
2
|
-
import { uploadFile } from './zambda-ext.js';
|
|
2
|
+
import { uploadFile, downloadFile } from './zambda-ext.js';
|
|
3
3
|
|
|
4
4
|
// AUTOGENERATED -- DO NOT EDIT
|
|
5
5
|
class Zambda extends SDKResource {
|
|
@@ -10,6 +10,7 @@ class Zambda extends SDKResource {
|
|
|
10
10
|
return this.config.services?.['zambdaApiUrl'] ?? 'https://zambda-api.zapehr.com/v1';
|
|
11
11
|
}
|
|
12
12
|
uploadFile = uploadFile;
|
|
13
|
+
downloadFile = downloadFile;
|
|
13
14
|
/**
|
|
14
15
|
* Get a list of all Zambda Functions in the Project. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.
|
|
15
16
|
*
|
|
@@ -73,6 +74,8 @@ class Zambda extends SDKResource {
|
|
|
73
74
|
return this.request('/zambda/{id}/execute-public', 'post', this.#baseUrlThunk.bind(this))(params, request);
|
|
74
75
|
}
|
|
75
76
|
/**
|
|
77
|
+
* **Deprecated.** Use `POST /zambda/{id}/presigned-url` with `action: "upload"` instead. This endpoint will be removed in future releases.
|
|
78
|
+
*
|
|
76
79
|
* Returns a URL that is used to deploy code to the Zambda Function with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.
|
|
77
80
|
*
|
|
78
81
|
* Access Policy Action: `Zambda:UpdateFunction`
|
|
@@ -81,6 +84,16 @@ class Zambda extends SDKResource {
|
|
|
81
84
|
s3Upload(params, request) {
|
|
82
85
|
return this.request('/zambda/{id}/s3-upload', 'post', this.#baseUrlThunk.bind(this))(params, request);
|
|
83
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Returns a presigned URL to upload or download code for the Zambda Function with the provided ID. Pass `action: "upload"` to get a URL for deploying a new code zip, or `action: "download"` to get a URL for retrieving the currently deployed zip. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.
|
|
89
|
+
*
|
|
90
|
+
* Upload: Access Policy Action: `Zambda:UpdateFunction`
|
|
91
|
+
* Download: Access Policy Action: `Zambda:GetFunctionSource`
|
|
92
|
+
* Access Policy Resource: `Zambda:Function`
|
|
93
|
+
*/
|
|
94
|
+
getPresignedUrl(params, request) {
|
|
95
|
+
return this.request('/zambda/{id}/presigned-url', 'post', this.#baseUrlThunk.bind(this))(params, request);
|
|
96
|
+
}
|
|
84
97
|
}
|
|
85
98
|
|
|
86
99
|
export { Zambda };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zambda.js","sources":["../../../../src/resources/classes/zambda.ts"],"sourcesContent":["// AUTOGENERATED -- DO NOT EDIT\n\nimport {\n OystehrClientRequest,\n ZambdaCreateParams,\n ZambdaCreateResponse,\n ZambdaDeleteParams,\n ZambdaExecuteParams,\n ZambdaExecutePublicParams,\n ZambdaExecutePublicResponse,\n ZambdaExecuteResponse,\n ZambdaGetParams,\n ZambdaGetResponse,\n ZambdaListResponse,\n ZambdaS3UploadParams,\n ZambdaS3UploadResponse,\n ZambdaUpdateParams,\n ZambdaUpdateResponse,\n} from '../..';\nimport { SDKResource } from '../../client/client';\nimport { OystehrConfig } from '../../config';\nimport * as ext from './zambda-ext';\n\nexport class Zambda extends SDKResource {\n constructor(config: OystehrConfig) {\n super(config);\n }\n #baseUrlThunk(): string {\n return this.config.services?.['zambdaApiUrl'] ?? 'https://zambda-api.zapehr.com/v1';\n }\n uploadFile = ext.uploadFile;\n /**\n * Get a list of all Zambda Functions in the Project. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:ListAllFunctions`\n * Access Policy Resource: `Zambda:Function`\n */\n list(request?: OystehrClientRequest): Promise<ZambdaListResponse> {\n return this.request('/zambda', 'get', this.#baseUrlThunk.bind(this))(request);\n }\n /**\n * Create a new Zambda Function. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:CreateFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n create(params: ZambdaCreateParams, request?: OystehrClientRequest): Promise<ZambdaCreateResponse> {\n return this.request('/zambda', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Get the Zambda Function with the provided ID or name. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:GetFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n get(params: ZambdaGetParams, request?: OystehrClientRequest): Promise<ZambdaGetResponse> {\n return this.request('/zambda/{id}', 'get', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Update the Zambda Function with the provided ID or name. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:UpdateFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n update(params: ZambdaUpdateParams, request?: OystehrClientRequest): Promise<ZambdaUpdateResponse> {\n return this.request('/zambda/{id}', 'patch', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Delete the Zambda Function with the provided ID or name. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:DeleteFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n delete(params: ZambdaDeleteParams, request?: OystehrClientRequest): Promise<void> {\n return this.request('/zambda/{id}', 'delete', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Execute the [Authenticated Zambda Function](https://docs.oystehr.com/oystehr/services/zambda/types/authenticated/) with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:InvokeFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n execute(params: ZambdaExecuteParams, request?: OystehrClientRequest): Promise<ZambdaExecuteResponse> {\n return this.request('/zambda/{id}/execute', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Execute the [Public Zambda Function](https://docs.oystehr.com/oystehr/services/zambda/types/public/) with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Execute a zambda that has method http_open. This endpoint is public so there are no access policy requirements.\n */\n executePublic(\n params: ZambdaExecutePublicParams,\n request?: OystehrClientRequest\n ): Promise<ZambdaExecutePublicResponse> {\n return this.request('/zambda/{id}/execute-public', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Returns a URL that is used to deploy code to the Zambda Function with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:UpdateFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n s3Upload(params: ZambdaS3UploadParams, request?: OystehrClientRequest): Promise<ZambdaS3UploadResponse> {\n return this.request('/zambda/{id}/s3-upload', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n}\n"],"names":["ext.uploadFile"],"mappings":";;;AAAA;
|
|
1
|
+
{"version":3,"file":"zambda.js","sources":["../../../../src/resources/classes/zambda.ts"],"sourcesContent":["// AUTOGENERATED -- DO NOT EDIT\n\nimport {\n OystehrClientRequest,\n ZambdaCreateParams,\n ZambdaCreateResponse,\n ZambdaDeleteParams,\n ZambdaExecuteParams,\n ZambdaExecutePublicParams,\n ZambdaExecutePublicResponse,\n ZambdaExecuteResponse,\n ZambdaGetParams,\n ZambdaGetPresignedUrlParams,\n ZambdaGetPresignedUrlResponse,\n ZambdaGetResponse,\n ZambdaListResponse,\n ZambdaS3UploadParams,\n ZambdaS3UploadResponse,\n ZambdaUpdateParams,\n ZambdaUpdateResponse,\n} from '../..';\nimport { SDKResource } from '../../client/client';\nimport { OystehrConfig } from '../../config';\nimport * as ext from './zambda-ext';\n\nexport class Zambda extends SDKResource {\n constructor(config: OystehrConfig) {\n super(config);\n }\n #baseUrlThunk(): string {\n return this.config.services?.['zambdaApiUrl'] ?? 'https://zambda-api.zapehr.com/v1';\n }\n uploadFile = ext.uploadFile;\n downloadFile = ext.downloadFile;\n /**\n * Get a list of all Zambda Functions in the Project. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:ListAllFunctions`\n * Access Policy Resource: `Zambda:Function`\n */\n list(request?: OystehrClientRequest): Promise<ZambdaListResponse> {\n return this.request('/zambda', 'get', this.#baseUrlThunk.bind(this))(request);\n }\n /**\n * Create a new Zambda Function. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:CreateFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n create(params: ZambdaCreateParams, request?: OystehrClientRequest): Promise<ZambdaCreateResponse> {\n return this.request('/zambda', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Get the Zambda Function with the provided ID or name. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:GetFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n get(params: ZambdaGetParams, request?: OystehrClientRequest): Promise<ZambdaGetResponse> {\n return this.request('/zambda/{id}', 'get', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Update the Zambda Function with the provided ID or name. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:UpdateFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n update(params: ZambdaUpdateParams, request?: OystehrClientRequest): Promise<ZambdaUpdateResponse> {\n return this.request('/zambda/{id}', 'patch', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Delete the Zambda Function with the provided ID or name. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:DeleteFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n delete(params: ZambdaDeleteParams, request?: OystehrClientRequest): Promise<void> {\n return this.request('/zambda/{id}', 'delete', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Execute the [Authenticated Zambda Function](https://docs.oystehr.com/oystehr/services/zambda/types/authenticated/) with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:InvokeFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n execute(params: ZambdaExecuteParams, request?: OystehrClientRequest): Promise<ZambdaExecuteResponse> {\n return this.request('/zambda/{id}/execute', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Execute the [Public Zambda Function](https://docs.oystehr.com/oystehr/services/zambda/types/public/) with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Execute a zambda that has method http_open. This endpoint is public so there are no access policy requirements.\n */\n executePublic(\n params: ZambdaExecutePublicParams,\n request?: OystehrClientRequest\n ): Promise<ZambdaExecutePublicResponse> {\n return this.request('/zambda/{id}/execute-public', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * **Deprecated.** Use `POST /zambda/{id}/presigned-url` with `action: \"upload\"` instead. This endpoint will be removed in future releases.\n *\n * Returns a URL that is used to deploy code to the Zambda Function with the provided ID. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Access Policy Action: `Zambda:UpdateFunction`\n * Access Policy Resource: `Zambda:Function`\n */\n s3Upload(params: ZambdaS3UploadParams, request?: OystehrClientRequest): Promise<ZambdaS3UploadResponse> {\n return this.request('/zambda/{id}/s3-upload', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n /**\n * Returns a presigned URL to upload or download code for the Zambda Function with the provided ID. Pass `action: \"upload\"` to get a URL for deploying a new code zip, or `action: \"download\"` to get a URL for retrieving the currently deployed zip. [Zambdas](https://docs.oystehr.com/oystehr/services/zambda/) are functions that can be used to execute your code. They can be used to process data received from Oystehr's APIs or to perform operations on third-party services.\n *\n * Upload: Access Policy Action: `Zambda:UpdateFunction`\n * Download: Access Policy Action: `Zambda:GetFunctionSource`\n * Access Policy Resource: `Zambda:Function`\n */\n getPresignedUrl(\n params: ZambdaGetPresignedUrlParams,\n request?: OystehrClientRequest\n ): Promise<ZambdaGetPresignedUrlResponse> {\n return this.request('/zambda/{id}/presigned-url', 'post', this.#baseUrlThunk.bind(this))(params, request);\n }\n}\n"],"names":["ext.uploadFile","ext.downloadFile"],"mappings":";;;AAAA;AAyBM,MAAO,MAAO,SAAQ,WAAW,CAAA;AACrC,IAAA,WAAA,CAAY,MAAqB,EAAA;QAC/B,KAAK,CAAC,MAAM,CAAC;IACf;IACA,aAAa,GAAA;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAC,IAAI,kCAAkC;IACrF;AACA,IAAA,UAAU,GAAGA,UAAc;AAC3B,IAAA,YAAY,GAAGC,YAAgB;AAC/B;;;;;AAKG;AACH,IAAA,IAAI,CAAC,OAA8B,EAAA;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/E;AACA;;;;;AAKG;IACH,MAAM,CAAC,MAA0B,EAAE,OAA8B,EAAA;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IACxF;AACA;;;;;AAKG;IACH,GAAG,CAAC,MAAuB,EAAE,OAA8B,EAAA;QACzD,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5F;AACA;;;;;AAKG;IACH,MAAM,CAAC,MAA0B,EAAE,OAA8B,EAAA;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9F;AACA;;;;;AAKG;IACH,MAAM,CAAC,MAA0B,EAAE,OAA8B,EAAA;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/F;AACA;;;;;AAKG;IACH,OAAO,CAAC,MAA2B,EAAE,OAA8B,EAAA;QACjE,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IACrG;AACA;;;;AAIG;IACH,aAAa,CACX,MAAiC,EACjC,OAA8B,EAAA;QAE9B,OAAO,IAAI,CAAC,OAAO,CAAC,6BAA6B,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5G;AACA;;;;;;;AAOG;IACH,QAAQ,CAAC,MAA4B,EAAE,OAA8B,EAAA;QACnE,OAAO,IAAI,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IACvG;AACA;;;;;;AAMG;IACH,eAAe,CACb,MAAmC,EACnC,OAA8B,EAAA;QAE9B,OAAO,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3G;AACD;;;;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ZambdaGetPresignedUrlParams {
|
|
2
|
+
/**
|
|
3
|
+
* Whether to get a presigned URL for uploading or downloading the Zambda Function code zip.
|
|
4
|
+
*/
|
|
5
|
+
action: 'upload' | 'download';
|
|
6
|
+
/**
|
|
7
|
+
* Optional filename for the Zambda Function code zip (upload only). If not provided, the filename will be randomized.
|
|
8
|
+
*/
|
|
9
|
+
filename?: string;
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
@@ -117,4 +117,71 @@ export type BatchInputRequest<F extends FhirResource> = BatchInputGetRequest | B
|
|
|
117
117
|
export interface BatchInput<F extends FhirResource> {
|
|
118
118
|
requests: BatchInputRequest<F>[];
|
|
119
119
|
}
|
|
120
|
+
export interface FhirAsyncJobHandle {
|
|
121
|
+
jobId: string;
|
|
122
|
+
contentLocation: string;
|
|
123
|
+
mode: FhirAsyncResponseMode;
|
|
124
|
+
}
|
|
125
|
+
export type FhirResponseMode = 'sync' | 'async-bundle' | 'async-bulk';
|
|
126
|
+
export type FhirAsyncResponseMode = 'bundle' | 'bulk';
|
|
127
|
+
export interface FhirAsyncCompletionBundleEntry<T extends FhirResource> {
|
|
128
|
+
response?: {
|
|
129
|
+
status?: string;
|
|
130
|
+
outcome?: OperationOutcome;
|
|
131
|
+
};
|
|
132
|
+
resource?: T | OperationOutcome;
|
|
133
|
+
}
|
|
134
|
+
export type FhirAsyncCompletionBundle<T extends FhirResource> = EntrylessFhirBundle<T | OperationOutcome> & {
|
|
135
|
+
resourceType: 'Bundle';
|
|
136
|
+
type: 'batch-response';
|
|
137
|
+
entry?: Array<FhirAsyncCompletionBundleEntry<T>>;
|
|
138
|
+
};
|
|
139
|
+
export interface FhirAsyncJobInProgress {
|
|
140
|
+
status: 202;
|
|
141
|
+
xProgress?: string;
|
|
142
|
+
retryAfter?: string;
|
|
143
|
+
}
|
|
144
|
+
export interface FhirAsyncJobCompletedBundle<T extends FhirResource = FhirResource> {
|
|
145
|
+
status: 200;
|
|
146
|
+
mode: 'bundle';
|
|
147
|
+
bundle: FhirAsyncCompletionBundle<T>;
|
|
148
|
+
interactionStatus?: string;
|
|
149
|
+
resource?: T | OperationOutcome;
|
|
150
|
+
outcome?: OperationOutcome;
|
|
151
|
+
}
|
|
152
|
+
export interface FhirAsyncBulkOutputFile {
|
|
153
|
+
type: string;
|
|
154
|
+
url: string;
|
|
155
|
+
}
|
|
156
|
+
export interface FhirAsyncBulkManifest {
|
|
157
|
+
transactionTime: string;
|
|
158
|
+
request: string;
|
|
159
|
+
requiresAccessToken: boolean;
|
|
160
|
+
output: FhirAsyncBulkOutputFile[];
|
|
161
|
+
error: FhirAsyncBulkOutputFile[];
|
|
162
|
+
deleted?: FhirAsyncBulkOutputFile[];
|
|
163
|
+
extension?: Record<string, unknown>;
|
|
164
|
+
}
|
|
165
|
+
export interface FhirAsyncJobCompletedBulk {
|
|
166
|
+
status: 200;
|
|
167
|
+
mode: 'bulk';
|
|
168
|
+
manifest: FhirAsyncBulkManifest;
|
|
169
|
+
}
|
|
170
|
+
export interface FhirAsyncJobExpired {
|
|
171
|
+
status: 410;
|
|
172
|
+
}
|
|
173
|
+
export interface FhirAsyncJobNotFound {
|
|
174
|
+
status: 404;
|
|
175
|
+
}
|
|
176
|
+
export interface FhirAsyncJobUnexpected {
|
|
177
|
+
status: Exclude<number, 200 | 202 | 404 | 410>;
|
|
178
|
+
body: unknown;
|
|
179
|
+
}
|
|
180
|
+
export type FhirAsyncJobStatus<T extends FhirResource = FhirResource> = FhirAsyncJobInProgress | FhirAsyncJobCompletedBundle<T> | FhirAsyncJobCompletedBulk | FhirAsyncJobExpired | FhirAsyncJobNotFound | FhirAsyncJobUnexpected;
|
|
181
|
+
export interface FhirAsyncWaitOptions {
|
|
182
|
+
/** Poll interval in milliseconds. Defaults to 1000 (1 second). */
|
|
183
|
+
pollIntervalMs: number;
|
|
184
|
+
/** Maximum wait time in milliseconds before timing out. Defaults to 900000 (15 minutes). */
|
|
185
|
+
timeoutMs: number;
|
|
186
|
+
}
|
|
120
187
|
export {};
|
|
@@ -192,6 +192,8 @@ export * from './ZambdaLogStreamListParams';
|
|
|
192
192
|
export * from './ZambdaLogStreamListResponse';
|
|
193
193
|
export * from './ZambdaS3UploadParams';
|
|
194
194
|
export * from './ZambdaS3UploadResponse';
|
|
195
|
+
export * from './ZambdaGetPresignedUrlParams';
|
|
196
|
+
export * from './ZambdaGetPresignedUrlResponse';
|
|
195
197
|
export * from './ZambdaLogStreamSearchParams';
|
|
196
198
|
export * from './ZambdaLogStreamSearchResponse';
|
|
197
199
|
export * from './ZambdaLogStreamGetParams';
|
package/package.json
CHANGED
package/src/client/client.ts
CHANGED
|
@@ -2,7 +2,16 @@ import { v4 as uuidv4, validate as uuidValidate } from 'uuid';
|
|
|
2
2
|
import { OystehrConfig } from '../config';
|
|
3
3
|
import { OystehrFHIRError, OystehrSdkError } from '../errors';
|
|
4
4
|
import { Logger } from '../logger';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
FhirAsyncBulkManifest,
|
|
7
|
+
FhirAsyncCompletionBundle,
|
|
8
|
+
FhirAsyncJobHandle,
|
|
9
|
+
FhirAsyncJobStatus,
|
|
10
|
+
FhirBundle,
|
|
11
|
+
FhirResource,
|
|
12
|
+
FhirResponseMode,
|
|
13
|
+
OperationOutcome,
|
|
14
|
+
} from '../resources/types';
|
|
6
15
|
|
|
7
16
|
type HttpMethod = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace';
|
|
8
17
|
export const defaultProjectApiUrl = 'https://project-api.zapehr.com/v1';
|
|
@@ -41,10 +50,19 @@ export interface OystehrClientRequest {
|
|
|
41
50
|
* Unique identifier for this request.
|
|
42
51
|
*/
|
|
43
52
|
requestId?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Optional execution mode for FHIR requests that support async behavior.
|
|
55
|
+
* Defaults to `sync` when omitted.
|
|
56
|
+
*/
|
|
57
|
+
mode?: FhirResponseMode;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
interface InternalClientRequest extends OystehrClientRequest {
|
|
47
61
|
ifMatch?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Internal-only: returns raw response metadata ({ status, headers, body }) instead of throwing on non-2xx statuses.
|
|
64
|
+
*/
|
|
65
|
+
rawResponse?: boolean;
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
type FhirData<T extends FhirResource> = T | T[] | FhirBundle<T>;
|
|
@@ -75,14 +93,22 @@ export class SDKResource {
|
|
|
75
93
|
};
|
|
76
94
|
}
|
|
77
95
|
|
|
78
|
-
protected fhirRequest<T
|
|
79
|
-
|
|
96
|
+
protected fhirRequest<T = FhirResource>(
|
|
97
|
+
path: string,
|
|
98
|
+
method: string
|
|
99
|
+
): {
|
|
100
|
+
(params: any, request: InternalClientRequest & { rawResponse: true }, requestMode?: FhirResponseMode): Promise<
|
|
101
|
+
RawFetcherResponse<T>
|
|
102
|
+
>;
|
|
103
|
+
(params: any, request?: InternalClientRequest, requestMode?: FhirResponseMode): Promise<T>;
|
|
104
|
+
} {
|
|
105
|
+
return async (params: any, request?: InternalClientRequest, requestMode?: FhirResponseMode): Promise<any> => {
|
|
80
106
|
try {
|
|
81
107
|
const baseUrlThunk = (): string => this.config.services?.fhirApiUrl ?? defaultFhirApiUrl;
|
|
82
108
|
const configThunk = (): OystehrConfig => this.config;
|
|
83
109
|
const loggerThunk = (): Logger => this.logger;
|
|
84
110
|
// must await here to catch
|
|
85
|
-
return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request);
|
|
111
|
+
return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request, requestMode);
|
|
86
112
|
} catch (err: unknown) {
|
|
87
113
|
// FHIR API error messages are JSON strings
|
|
88
114
|
const fullError = err as { message: string | Record<string, any>; code: number; cause?: unknown };
|
|
@@ -100,13 +126,170 @@ export class SDKResource {
|
|
|
100
126
|
}
|
|
101
127
|
};
|
|
102
128
|
}
|
|
129
|
+
|
|
130
|
+
protected async startAsyncJob(
|
|
131
|
+
path: string,
|
|
132
|
+
method: string,
|
|
133
|
+
params: Record<string, unknown>,
|
|
134
|
+
requestMode: FhirResponseMode,
|
|
135
|
+
request?: InternalClientRequest
|
|
136
|
+
): Promise<FhirAsyncJobHandle> {
|
|
137
|
+
const mode = requestMode === 'async-bulk' ? 'bulk' : 'bundle';
|
|
138
|
+
const asyncPath = requestMode === 'async-bulk' ? this.appendBulkOutputFormat(path) : path;
|
|
139
|
+
|
|
140
|
+
const raw = await this.fhirRequest(asyncPath, method)(
|
|
141
|
+
params,
|
|
142
|
+
{
|
|
143
|
+
...request,
|
|
144
|
+
rawResponse: true,
|
|
145
|
+
},
|
|
146
|
+
requestMode
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (raw.status !== 202) {
|
|
150
|
+
throw new OystehrSdkError({
|
|
151
|
+
message: `Expected start async job to return 202 Accepted, received ${raw.status}`,
|
|
152
|
+
code: raw.status,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const contentLocation = this.readHeader(raw.headers, 'content-location');
|
|
157
|
+
if (!contentLocation) {
|
|
158
|
+
throw new OystehrSdkError({
|
|
159
|
+
message: 'Start Async job response missing Content-Location header',
|
|
160
|
+
code: 500,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const jobId = this.parseAsyncJobId(contentLocation);
|
|
165
|
+
if (!jobId) {
|
|
166
|
+
throw new OystehrSdkError({
|
|
167
|
+
message: `Could not parse async job id from Content-Location: ${contentLocation}`,
|
|
168
|
+
code: 500,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return { jobId, contentLocation, mode };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
protected async fetchAsyncJobStatus<T extends FhirResource>(
|
|
176
|
+
jobId: string,
|
|
177
|
+
request?: OystehrClientRequest
|
|
178
|
+
): Promise<FhirAsyncJobStatus<T>> {
|
|
179
|
+
const raw = await this.fhirRequest(`/async-job/${jobId}`, 'GET')(
|
|
180
|
+
{},
|
|
181
|
+
{
|
|
182
|
+
...request,
|
|
183
|
+
rawResponse: true,
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
if (raw.status === 202) {
|
|
188
|
+
return {
|
|
189
|
+
status: 202,
|
|
190
|
+
xProgress: this.readHeader(raw.headers, 'x-progress'),
|
|
191
|
+
retryAfter: this.readHeader(raw.headers, 'retry-after'),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (raw.status === 410) {
|
|
196
|
+
return { status: 410 };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (raw.status === 404) {
|
|
200
|
+
return { status: 404 };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (raw.status === 200) {
|
|
204
|
+
if (this.isBulkManifest(raw.body)) {
|
|
205
|
+
return {
|
|
206
|
+
status: 200,
|
|
207
|
+
mode: 'bulk',
|
|
208
|
+
manifest: raw.body,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const bundle = raw.body as FhirAsyncCompletionBundle<T>;
|
|
213
|
+
if (bundle?.resourceType === 'Bundle' && bundle?.type === 'batch-response') {
|
|
214
|
+
const entry0 = bundle.entry?.[0];
|
|
215
|
+
const interactionStatus = entry0?.response?.status;
|
|
216
|
+
const resource = entry0?.resource;
|
|
217
|
+
const outcome = entry0?.response?.outcome;
|
|
218
|
+
return {
|
|
219
|
+
status: 200,
|
|
220
|
+
mode: 'bundle',
|
|
221
|
+
bundle,
|
|
222
|
+
interactionStatus,
|
|
223
|
+
resource,
|
|
224
|
+
outcome,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
status: 200,
|
|
230
|
+
body: raw.body,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
status: raw.status,
|
|
236
|
+
body: raw.body,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private readHeader(headers: Record<string, string>, name: string): string | undefined {
|
|
241
|
+
const direct = headers[name];
|
|
242
|
+
if (direct != null) {
|
|
243
|
+
return direct;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const lower = name.toLowerCase();
|
|
247
|
+
const key = Object.keys(headers).find((h) => h.toLowerCase() === lower);
|
|
248
|
+
return key ? headers[key] : undefined;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private parseAsyncJobId(contentLocation: string): string | undefined {
|
|
252
|
+
const segments = contentLocation.split('/').filter(Boolean);
|
|
253
|
+
const asyncJobIndex = segments.lastIndexOf('async-job');
|
|
254
|
+
if (asyncJobIndex < 0 || asyncJobIndex + 1 >= segments.length) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return segments[asyncJobIndex + 1];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private appendBulkOutputFormat(path: string): string {
|
|
262
|
+
const separator = path.includes('?') ? '&' : '?';
|
|
263
|
+
return `${path}${separator}_outputFormat=${encodeURIComponent('application/fhir+ndjson')}`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private isBulkManifest(body: unknown): body is FhirAsyncBulkManifest {
|
|
267
|
+
if (body == null || typeof body !== 'object') {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const maybe = body as Record<string, unknown>;
|
|
272
|
+
return (
|
|
273
|
+
typeof maybe.transactionTime === 'string' &&
|
|
274
|
+
typeof maybe.request === 'string' &&
|
|
275
|
+
typeof maybe.requiresAccessToken === 'boolean' &&
|
|
276
|
+
Array.isArray(maybe.output) &&
|
|
277
|
+
Array.isArray(maybe.error)
|
|
278
|
+
);
|
|
279
|
+
}
|
|
103
280
|
}
|
|
104
281
|
|
|
105
282
|
export type FetcherError = { message: string; code: number };
|
|
106
283
|
export type FetcherResponse = any;
|
|
284
|
+
export type RawFetcherResponse<T = unknown> = {
|
|
285
|
+
status: number;
|
|
286
|
+
headers: Record<string, string>;
|
|
287
|
+
body: T | null;
|
|
288
|
+
};
|
|
107
289
|
export type FetcherFunction = (
|
|
108
290
|
params?: Record<string, any> | [any] | InternalClientRequest,
|
|
109
|
-
request?: InternalClientRequest
|
|
291
|
+
request?: InternalClientRequest,
|
|
292
|
+
requestMode?: FhirResponseMode
|
|
110
293
|
) => Promise<FetcherResponse>;
|
|
111
294
|
|
|
112
295
|
function isInternalClientRequest(request: Record<string, any>): request is InternalClientRequest {
|
|
@@ -115,10 +298,19 @@ function isInternalClientRequest(request: Record<string, any>): request is Inter
|
|
|
115
298
|
('projectId' in request && uuidValidate(request.projectId)) ||
|
|
116
299
|
('contentType' in request && request.contentType?.split('/').length === 2) ||
|
|
117
300
|
'requestId' in request ||
|
|
118
|
-
('ifMatch' in request && request.ifMatch.startsWith('W/"'))
|
|
301
|
+
('ifMatch' in request && request.ifMatch.startsWith('W/"')) ||
|
|
302
|
+
'mode' in request ||
|
|
303
|
+
'rawResponse' in request
|
|
119
304
|
);
|
|
120
305
|
}
|
|
121
306
|
|
|
307
|
+
function getPreferHeaderFromMode(mode: FhirResponseMode | undefined): string | undefined {
|
|
308
|
+
if (mode === 'async-bundle' || mode === 'async-bulk') {
|
|
309
|
+
return 'respond-async';
|
|
310
|
+
}
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
|
|
122
314
|
/**
|
|
123
315
|
* Parse XML response in format <response><status>...</status><output>...</output></response>
|
|
124
316
|
*/
|
|
@@ -151,7 +343,8 @@ function fetcher(
|
|
|
151
343
|
): FetcherFunction {
|
|
152
344
|
return async (
|
|
153
345
|
params?: Record<string, unknown> | [any] | InternalClientRequest,
|
|
154
|
-
request?: InternalClientRequest
|
|
346
|
+
request?: InternalClientRequest,
|
|
347
|
+
requestMode?: FhirResponseMode
|
|
155
348
|
): Promise<FetcherResponse> => {
|
|
156
349
|
// this function supports multiple signatures. fetcher(baseUrl, path, method)(params, request) or fetcher(baseUrl, path, method)(request)
|
|
157
350
|
// or fetcher(baseUrl, path, method)(params) or fetcher(baseUrl, path, method)(). the types for this are handled by Client<Path, Methods>
|
|
@@ -214,6 +407,8 @@ function fetcher(
|
|
|
214
407
|
requestId: requestCtx?.requestId,
|
|
215
408
|
});
|
|
216
409
|
|
|
410
|
+
const preferHeader = getPreferHeaderFromMode(requestMode);
|
|
411
|
+
|
|
217
412
|
const headers: Record<string, string> = Object.assign(
|
|
218
413
|
projectId
|
|
219
414
|
? {
|
|
@@ -224,6 +419,7 @@ function fetcher(
|
|
|
224
419
|
{
|
|
225
420
|
'content-type': requestCtx?.contentType ?? 'application/json',
|
|
226
421
|
},
|
|
422
|
+
preferHeader ? { Prefer: preferHeader } : {},
|
|
227
423
|
accessToken ? { Authorization: `Bearer ${accessToken}` } : {},
|
|
228
424
|
requestCtx?.ifMatch ? { 'If-Match': requestCtx.ifMatch } : {},
|
|
229
425
|
{ 'x-oystehr-request-id': requestCtx?.requestId }
|
|
@@ -301,6 +497,17 @@ function fetcher(
|
|
|
301
497
|
url,
|
|
302
498
|
requestId: requestCtx?.requestId,
|
|
303
499
|
});
|
|
500
|
+
if (requestCtx?.rawResponse) {
|
|
501
|
+
const headersRecord: Record<string, string> = {};
|
|
502
|
+
response.headers.forEach((value, key) => {
|
|
503
|
+
headersRecord[key] = value;
|
|
504
|
+
});
|
|
505
|
+
return {
|
|
506
|
+
status: response.status,
|
|
507
|
+
headers: headersRecord,
|
|
508
|
+
body: responseJson ?? responseBody,
|
|
509
|
+
} as RawFetcherResponse;
|
|
510
|
+
}
|
|
304
511
|
const isError = !response.ok || response.status >= 400;
|
|
305
512
|
if (isError) {
|
|
306
513
|
const errObj = {
|