@openhi/constructs 0.0.0 → 0.0.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.
Files changed (101) hide show
  1. package/lib/chunk-LZOMFHX3.mjs +38 -0
  2. package/lib/chunk-LZOMFHX3.mjs.map +1 -0
  3. package/lib/index.d.mts +788 -0
  4. package/lib/index.d.ts +869 -3
  5. package/lib/index.js +1318 -19
  6. package/lib/index.js.map +1 -0
  7. package/lib/index.mjs +1303 -0
  8. package/lib/index.mjs.map +1 -0
  9. package/lib/rest-api-lambda.handler.d.mts +6 -0
  10. package/lib/rest-api-lambda.handler.d.ts +6 -0
  11. package/lib/rest-api-lambda.handler.js +677 -0
  12. package/lib/rest-api-lambda.handler.js.map +1 -0
  13. package/lib/rest-api-lambda.handler.mjs +646 -0
  14. package/lib/rest-api-lambda.handler.mjs.map +1 -0
  15. package/package.json +37 -28
  16. package/lib/app/index.d.ts +0 -4
  17. package/lib/app/index.js +0 -21
  18. package/lib/app/open-hi-app.d.ts +0 -85
  19. package/lib/app/open-hi-app.js +0 -127
  20. package/lib/app/open-hi-environment.d.ts +0 -59
  21. package/lib/app/open-hi-environment.js +0 -72
  22. package/lib/app/open-hi-service.d.ts +0 -169
  23. package/lib/app/open-hi-service.js +0 -195
  24. package/lib/app/open-hi-stage.d.ts +0 -71
  25. package/lib/app/open-hi-stage.js +0 -70
  26. package/lib/components/acm/root-wildcard-certificate.d.ts +0 -15
  27. package/lib/components/acm/root-wildcard-certificate.js +0 -35
  28. package/lib/components/api-gateway/core-http-api.d.ts +0 -10
  29. package/lib/components/api-gateway/core-http-api.js +0 -44
  30. package/lib/components/api-gateway/http-lambda-integration-no-permissions.d.ts +0 -18
  31. package/lib/components/api-gateway/http-lambda-integration-no-permissions.js +0 -26
  32. package/lib/components/app-sync/core-graphql-api.d.ts +0 -12
  33. package/lib/components/app-sync/core-graphql-api.js +0 -54
  34. package/lib/components/auth.d.ts +0 -75
  35. package/lib/components/auth.js +0 -100
  36. package/lib/components/cognito/core-user-pool-client.d.ts +0 -10
  37. package/lib/components/cognito/core-user-pool-client.js +0 -47
  38. package/lib/components/cognito/core-user-pool-domain.d.ts +0 -10
  39. package/lib/components/cognito/core-user-pool-domain.js +0 -41
  40. package/lib/components/cognito/core-user-pool-kms-key.d.ts +0 -10
  41. package/lib/components/cognito/core-user-pool-kms-key.js +0 -37
  42. package/lib/components/cognito/core-user-pool.d.ts +0 -10
  43. package/lib/components/cognito/core-user-pool.js +0 -54
  44. package/lib/components/core.d.ts +0 -102
  45. package/lib/components/core.js +0 -79
  46. package/lib/components/dynamodb/dynamo-db-data-store.d.ts +0 -33
  47. package/lib/components/dynamodb/dynamo-db-data-store.js +0 -107
  48. package/lib/components/event-bridge/data-event-bus.d.ts +0 -19
  49. package/lib/components/event-bridge/data-event-bus.js +0 -34
  50. package/lib/components/event-bridge/ops-event-bus.d.ts +0 -19
  51. package/lib/components/event-bridge/ops-event-bus.js +0 -34
  52. package/lib/components/global.d.ts +0 -36
  53. package/lib/components/global.js +0 -63
  54. package/lib/components/index.d.ts +0 -1
  55. package/lib/components/index.js +0 -18
  56. package/lib/components/route-53/child-hosted-zone.d.ts +0 -20
  57. package/lib/components/route-53/child-hosted-zone.js +0 -48
  58. package/lib/components/route-53/root-hosted-zone.d.ts +0 -10
  59. package/lib/components/route-53/root-hosted-zone.js +0 -20
  60. package/lib/components/ssm/discoverable-string-parameter.d.ts +0 -59
  61. package/lib/components/ssm/discoverable-string-parameter.js +0 -50
  62. package/lib/components/ssm/index.d.ts +0 -1
  63. package/lib/components/ssm/index.js +0 -18
  64. package/lib/data/dynamo/ehr/r4/Patient.d.ts +0 -180
  65. package/lib/data/dynamo/ehr/r4/Patient.js +0 -192
  66. package/lib/data/dynamo/ehr/r4/ehr-r4-data-service.d.ts +0 -162
  67. package/lib/data/dynamo/ehr/r4/ehr-r4-data-service.js +0 -37
  68. package/lib/data/hello-world.d.ts +0 -39
  69. package/lib/data/hello-world.js +0 -59
  70. package/lib/data/import-patient-with-dynalite.d.ts +0 -1
  71. package/lib/data/import-patient-with-dynalite.js +0 -87
  72. package/lib/data/import-patient.d.ts +0 -47
  73. package/lib/data/import-patient.js +0 -158
  74. package/lib/data/lambda/rest-api-lambda.d.ts +0 -13
  75. package/lib/data/lambda/rest-api-lambda.handler.d.ts +0 -1
  76. package/lib/data/lambda/rest-api-lambda.handler.js +0 -10
  77. package/lib/data/lambda/rest-api-lambda.js +0 -22
  78. package/lib/data/middleware/open-hi-context.d.ts +0 -13
  79. package/lib/data/middleware/open-hi-context.js +0 -31
  80. package/lib/data/rest-api/ehr/r4/Patient.d.ts +0 -16
  81. package/lib/data/rest-api/ehr/r4/Patient.js +0 -234
  82. package/lib/data/rest-api/rest-api-local.d.ts +0 -1
  83. package/lib/data/rest-api/rest-api-local.js +0 -8
  84. package/lib/data/rest-api/rest-api-mockdata.d.ts +0 -7
  85. package/lib/data/rest-api/rest-api-mockdata.js +0 -585
  86. package/lib/data/rest-api/rest-api.d.ts +0 -3
  87. package/lib/data/rest-api/rest-api.js +0 -26
  88. package/lib/lib/compression.d.ts +0 -27
  89. package/lib/lib/compression.js +0 -87
  90. package/lib/services/index.d.ts +0 -5
  91. package/lib/services/index.js +0 -22
  92. package/lib/services/open-hi-auth-service.d.ts +0 -31
  93. package/lib/services/open-hi-auth-service.js +0 -31
  94. package/lib/services/open-hi-core-service.d.ts +0 -15
  95. package/lib/services/open-hi-core-service.js +0 -38
  96. package/lib/services/open-hi-data-service.d.ts +0 -18
  97. package/lib/services/open-hi-data-service.js +0 -18
  98. package/lib/services/open-hi-global-service.d.ts +0 -15
  99. package/lib/services/open-hi-global-service.js +0 -44
  100. package/lib/services/open-hi-rest-api-service.d.ts +0 -17
  101. package/lib/services/open-hi-rest-api-service.js +0 -107
@@ -0,0 +1,677 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/data/lambda/rest-api-lambda.handler.ts
31
+ var rest_api_lambda_handler_exports = {};
32
+ __export(rest_api_lambda_handler_exports, {
33
+ handler: () => handler
34
+ });
35
+ module.exports = __toCommonJS(rest_api_lambda_handler_exports);
36
+ var import_serverless_express = __toESM(require("@codegenie/serverless-express"));
37
+
38
+ // src/data/rest-api/rest-api.ts
39
+ var import_path = __toESM(require("path"));
40
+ var import_cors = __toESM(require("cors"));
41
+ var import_express2 = __toESM(require("express"));
42
+
43
+ // src/data/middleware/open-hi-context.ts
44
+ var STATIC_TENANT_ID = "tenant-1";
45
+ var STATIC_WORKSPACE_ID = "ws-1";
46
+ var STATIC_USER_ID = "rest-api";
47
+ var STATIC_USER_NAME = "REST API";
48
+ function openHiContextMiddleware(req, _res, next) {
49
+ const now = (/* @__PURE__ */ new Date()).toISOString();
50
+ req.openhiContext = {
51
+ tenantId: STATIC_TENANT_ID,
52
+ workspaceId: STATIC_WORKSPACE_ID,
53
+ date: now,
54
+ userId: STATIC_USER_ID,
55
+ username: STATIC_USER_NAME
56
+ };
57
+ next();
58
+ }
59
+
60
+ // src/data/rest-api/ehr/r4/Patient.ts
61
+ var import_express = __toESM(require("express"));
62
+
63
+ // src/lib/compression.ts
64
+ var import_node_zlib = require("zlib");
65
+ var ENVELOPE_VERSION = 1;
66
+ var COMPRESSION_ALGOS = {
67
+ NONE: "none",
68
+ GZIP: "gzip",
69
+ BROTLI: "brotli",
70
+ DEFLATE: "deflate"
71
+ };
72
+ function isEnvelope(obj) {
73
+ return typeof obj === "object" && obj !== null && "v" in obj && "algo" in obj && "payload" in obj && typeof obj.payload === "string";
74
+ }
75
+ function compressResource(jsonString, options) {
76
+ const algo = options?.algo ?? COMPRESSION_ALGOS.GZIP;
77
+ if (algo === COMPRESSION_ALGOS.NONE) {
78
+ const envelope2 = {
79
+ v: ENVELOPE_VERSION,
80
+ algo: COMPRESSION_ALGOS.NONE,
81
+ payload: jsonString
82
+ };
83
+ return JSON.stringify(envelope2);
84
+ }
85
+ const buf = Buffer.from(jsonString, "utf-8");
86
+ const payload = (0, import_node_zlib.gzipSync)(buf).toString("base64");
87
+ const envelope = {
88
+ v: ENVELOPE_VERSION,
89
+ algo: COMPRESSION_ALGOS.GZIP,
90
+ payload
91
+ };
92
+ return JSON.stringify(envelope);
93
+ }
94
+ function decompressResource(compressedOrRaw) {
95
+ try {
96
+ const parsed = JSON.parse(compressedOrRaw);
97
+ if (isEnvelope(parsed)) {
98
+ if (parsed.algo === COMPRESSION_ALGOS.GZIP) {
99
+ const buf = Buffer.from(parsed.payload, "base64");
100
+ return (0, import_node_zlib.gunzipSync)(buf).toString("utf-8");
101
+ }
102
+ if (parsed.algo === COMPRESSION_ALGOS.NONE) {
103
+ return parsed.payload;
104
+ }
105
+ return parsed.payload;
106
+ }
107
+ } catch {
108
+ }
109
+ try {
110
+ const buf = Buffer.from(compressedOrRaw, "base64");
111
+ if (buf.length >= 2 && buf[0] === 31 && buf[1] === 139) {
112
+ return (0, import_node_zlib.gunzipSync)(buf).toString("utf-8");
113
+ }
114
+ } catch {
115
+ }
116
+ return compressedOrRaw;
117
+ }
118
+
119
+ // src/data/dynamo/ehr/r4/ehr-r4-data-service.ts
120
+ var import_client_dynamodb = require("@aws-sdk/client-dynamodb");
121
+ var import_electrodb2 = require("electrodb");
122
+
123
+ // src/data/dynamo/ehr/r4/Patient.ts
124
+ var import_electrodb = require("electrodb");
125
+ var Patient = new import_electrodb.Entity({
126
+ model: {
127
+ entity: "patient",
128
+ service: "fhir",
129
+ version: "01"
130
+ },
131
+ attributes: {
132
+ /** Sort key. "CURRENT" for current version; version history in S3. */
133
+ sk: {
134
+ type: "string",
135
+ required: true,
136
+ default: "CURRENT"
137
+ },
138
+ tenantId: {
139
+ type: "string",
140
+ required: true
141
+ },
142
+ workspaceId: {
143
+ type: "string",
144
+ required: true
145
+ },
146
+ /** FHIR Resource.id; logical id in URL and PK. */
147
+ id: {
148
+ type: "string",
149
+ required: true
150
+ },
151
+ /** FHIR resource as JSON string. JSON.stringify(resource) on write; JSON.parse(item.resource) on read. */
152
+ resource: {
153
+ type: "string",
154
+ required: true
155
+ },
156
+ /** Version id (e.g. ULID). Tracks current version; S3 history key. */
157
+ vid: {
158
+ type: "string",
159
+ required: true
160
+ },
161
+ lastUpdated: {
162
+ type: "string",
163
+ required: true
164
+ },
165
+ deleted: {
166
+ type: "boolean",
167
+ required: false
168
+ },
169
+ bundleId: {
170
+ type: "string",
171
+ required: false
172
+ },
173
+ msgId: {
174
+ type: "string",
175
+ required: false
176
+ },
177
+ // Audit is in FHIR resource meta (meta.extension), not item attributes. See data-store-entities.md.
178
+ // --- GSI2 (Identifier Lookup): optional; set when indexing this patient by identifier (e.g. MRN)
179
+ /** Identifier system (e.g. MRN system URI). When set with identifierValue, item is written to GSI2. */
180
+ identifierSystem: {
181
+ type: "string",
182
+ required: false
183
+ },
184
+ /** Identifier value (e.g. MRN). When set with identifierSystem, item is written to GSI2. */
185
+ identifierValue: {
186
+ type: "string",
187
+ required: false
188
+ },
189
+ /** For GSI2/GSI3 projection: base table PK/SK so GetItem can be used after query. */
190
+ resourcePk: {
191
+ type: "string",
192
+ required: false
193
+ },
194
+ resourceSk: {
195
+ type: "string",
196
+ required: false
197
+ },
198
+ /** For GSI2 projection: display name for roster/lookup. */
199
+ display: {
200
+ type: "string",
201
+ required: false
202
+ },
203
+ /** For GSI2 projection: resource status if applicable. */
204
+ status: {
205
+ type: "string",
206
+ required: false
207
+ },
208
+ // --- GSI3 (Facility Ops): optional; set when indexing this patient on a facility roster
209
+ /** Facility id. When set with normalizedName, item is written to GSI3. */
210
+ facilityId: {
211
+ type: "string",
212
+ required: false
213
+ },
214
+ /** Normalized display name for roster sort. When set with facilityId, item is written to GSI3. */
215
+ normalizedName: {
216
+ type: "string",
217
+ required: false
218
+ }
219
+ },
220
+ indexes: {
221
+ /** Base table: PK, SK (data store key names). PK is built from tenantId, workspaceId, id; do not supply PK from outside. */
222
+ record: {
223
+ pk: {
224
+ field: "PK",
225
+ composite: ["tenantId", "workspaceId", "id"],
226
+ template: "TID#${tenantId}#WID#${workspaceId}#RT#Patient#ID#${id}"
227
+ },
228
+ sk: {
229
+ field: "SK",
230
+ composite: ["sk"]
231
+ }
232
+ },
233
+ /**
234
+ * GSI1 — Reverse Reference: query "what references this patient?".
235
+ * Patient items are never written to GSI1 (condition: false); reference index items
236
+ * are written by other resources. This index enables querying GSI1 by REFTO#RT#Patient#ID#<id>.
237
+ */
238
+ gsi1: {
239
+ index: "GSI1",
240
+ condition: () => false,
241
+ pk: {
242
+ field: "GSI1PK",
243
+ composite: ["tenantId", "workspaceId", "id"],
244
+ template: "TID#${tenantId}#WID#${workspaceId}#REFTO#RT#Patient#ID#${id}"
245
+ },
246
+ sk: {
247
+ field: "GSI1SK",
248
+ composite: []
249
+ }
250
+ },
251
+ /** GSI2 — Identifier Lookup: MRN, NPI, member ID, etc. Keys built from identifier components. */
252
+ gsi2: {
253
+ index: "GSI2",
254
+ condition: (attr) => attr.identifierSystem != null && attr.identifierValue != null,
255
+ pk: {
256
+ field: "GSI2PK",
257
+ composite: [
258
+ "tenantId",
259
+ "workspaceId",
260
+ "identifierSystem",
261
+ "identifierValue"
262
+ ],
263
+ template: "TID#${tenantId}#WID#${workspaceId}#IDENT#${identifierSystem}#${identifierValue}"
264
+ },
265
+ sk: {
266
+ field: "GSI2SK",
267
+ composite: ["id"],
268
+ template: "RT#Patient#ID#${id}"
269
+ }
270
+ },
271
+ /** GSI3 — Facility Ops: facility roster, worklists. Keys built from facility + name. */
272
+ gsi3: {
273
+ index: "GSI3",
274
+ condition: (attr) => attr.facilityId != null && attr.normalizedName != null,
275
+ pk: {
276
+ field: "GSI3PK",
277
+ composite: ["tenantId", "workspaceId", "facilityId"],
278
+ template: "TID#${tenantId}#WID#${workspaceId}#FAC#${facilityId}"
279
+ },
280
+ sk: {
281
+ field: "GSI3SK",
282
+ composite: ["id", "normalizedName"],
283
+ template: "TYPE#PATIENT#PAT#${id}#NAME#${normalizedName}"
284
+ }
285
+ },
286
+ /** GSI4 — Resource Type Index: list all Patients in workspace (no scan). */
287
+ gsi4: {
288
+ index: "GSI4",
289
+ condition: () => true,
290
+ pk: {
291
+ field: "GSI4PK",
292
+ composite: ["tenantId", "workspaceId"],
293
+ template: "TID#${tenantId}#WID#${workspaceId}#RT#Patient"
294
+ },
295
+ sk: {
296
+ field: "GSI4SK",
297
+ composite: ["id"],
298
+ template: "ID#${id}"
299
+ }
300
+ }
301
+ }
302
+ });
303
+
304
+ // src/data/dynamo/ehr/r4/ehr-r4-data-service.ts
305
+ var table = process.env.DYNAMO_TABLE_NAME ?? "jesttesttable";
306
+ var client = new import_client_dynamodb.DynamoDBClient({
307
+ ...process.env.MOCK_DYNAMODB_ENDPOINT && {
308
+ endpoint: process.env.MOCK_DYNAMODB_ENDPOINT,
309
+ sslEnabled: false,
310
+ region: "local"
311
+ }
312
+ });
313
+ var entities = { patient: Patient };
314
+ var EhrR4DataService = new import_electrodb2.Service(entities, { table, client });
315
+ function getEhrR4DataService(tableName) {
316
+ return new import_electrodb2.Service(entities, { table: tableName, client });
317
+ }
318
+
319
+ // src/data/import-patient.ts
320
+ var import_node_fs = require("fs");
321
+ var import_node_path = require("path");
322
+ var OPENHI_EXT = "http://openhi.org/fhir/StructureDefinition";
323
+ function mergeAuditIntoMeta(meta, audit) {
324
+ const existing = meta ?? {};
325
+ const ext = [
326
+ ...Array.isArray(existing.extension) ? existing.extension : []
327
+ ];
328
+ const byUrl = new Map(ext.map((e) => [e.url, e]));
329
+ function set(url, value, type) {
330
+ if (value == null) return;
331
+ byUrl.set(url, { url, [type]: value });
332
+ }
333
+ set(`${OPENHI_EXT}/created-date`, audit.createdDate, "valueDateTime");
334
+ set(`${OPENHI_EXT}/created-by-id`, audit.createdById, "valueString");
335
+ set(`${OPENHI_EXT}/created-by-name`, audit.createdByName, "valueString");
336
+ set(`${OPENHI_EXT}/modified-date`, audit.modifiedDate, "valueDateTime");
337
+ set(`${OPENHI_EXT}/modified-by-id`, audit.modifiedById, "valueString");
338
+ set(`${OPENHI_EXT}/modified-by-name`, audit.modifiedByName, "valueString");
339
+ set(`${OPENHI_EXT}/deleted-date`, audit.deletedDate, "valueDateTime");
340
+ set(`${OPENHI_EXT}/deleted-by-id`, audit.deletedById, "valueString");
341
+ set(`${OPENHI_EXT}/deleted-by-name`, audit.deletedByName, "valueString");
342
+ return { ...existing, extension: Array.from(byUrl.values()) };
343
+ }
344
+ function extractPatient(parsed) {
345
+ if (parsed && typeof parsed === "object" && "resourceType" in parsed) {
346
+ const root = parsed;
347
+ if (root.resourceType === "Patient" && root.id) {
348
+ return root;
349
+ }
350
+ if (root.resourceType === "Bundle" && "entry" in parsed) {
351
+ const entries = parsed.entry;
352
+ if (Array.isArray(entries)) {
353
+ const patientEntry = entries.find(
354
+ (e) => e?.resource?.resourceType === "Patient" && e.resource.id
355
+ );
356
+ if (patientEntry?.resource) {
357
+ return patientEntry.resource;
358
+ }
359
+ }
360
+ }
361
+ }
362
+ throw new Error(
363
+ "File must be a FHIR Patient resource or a Bundle containing at least one Patient entry"
364
+ );
365
+ }
366
+ var SK = "CURRENT";
367
+ var defaultAudit = {
368
+ createdDate: (/* @__PURE__ */ new Date()).toISOString(),
369
+ createdById: "import",
370
+ createdByName: "Bulk import",
371
+ modifiedDate: (/* @__PURE__ */ new Date()).toISOString(),
372
+ modifiedById: "import",
373
+ modifiedByName: "Bulk import"
374
+ };
375
+ function patientToPutAttrs(patient, options) {
376
+ const {
377
+ tenantId,
378
+ workspaceId,
379
+ createdDate,
380
+ createdById,
381
+ createdByName,
382
+ modifiedDate,
383
+ modifiedById,
384
+ modifiedByName
385
+ } = options;
386
+ const lastUpdated = patient.meta?.lastUpdated ?? modifiedDate ?? defaultAudit.modifiedDate ?? (/* @__PURE__ */ new Date()).toISOString();
387
+ const auditMerged = {
388
+ ...defaultAudit,
389
+ ...createdDate != null && { createdDate },
390
+ ...createdById != null && { createdById },
391
+ ...createdByName != null && { createdByName },
392
+ ...modifiedDate != null && { modifiedDate },
393
+ ...modifiedById != null && { modifiedById },
394
+ ...modifiedByName != null && { modifiedByName }
395
+ };
396
+ const patientWithMeta = {
397
+ ...patient,
398
+ meta: mergeAuditIntoMeta(patient.meta, auditMerged)
399
+ };
400
+ if (lastUpdated && !patientWithMeta.meta.lastUpdated) {
401
+ patientWithMeta.meta.lastUpdated = lastUpdated;
402
+ }
403
+ return {
404
+ sk: SK,
405
+ tenantId,
406
+ workspaceId,
407
+ id: patient.id,
408
+ resource: compressResource(JSON.stringify(patientWithMeta)),
409
+ vid: lastUpdated.replace(/[-:T.Z]/g, "").slice(0, 12) || Date.now().toString(36),
410
+ lastUpdated,
411
+ identifierSystem: "",
412
+ identifierValue: "",
413
+ facilityId: "",
414
+ normalizedName: ""
415
+ };
416
+ }
417
+ async function importPatientFromFile(filePath, options) {
418
+ const resolved = (0, import_node_path.resolve)(filePath);
419
+ const raw = (0, import_node_fs.readFileSync)(resolved, "utf-8");
420
+ const parsed = JSON.parse(raw);
421
+ const patient = extractPatient(parsed);
422
+ const tableName = options.tableName ?? process.env.DYNAMO_TABLE_NAME ?? "jesttesttable";
423
+ const service = getEhrR4DataService(tableName);
424
+ const attrs = patientToPutAttrs(patient, options);
425
+ const result = await service.entities.patient.put(attrs).go();
426
+ const data = result.data;
427
+ if (!data) {
428
+ throw new Error(`Put failed for Patient ${patient.id}`);
429
+ }
430
+ return {
431
+ id: data.id,
432
+ tenantId: data.tenantId,
433
+ workspaceId: data.workspaceId
434
+ };
435
+ }
436
+ async function main() {
437
+ const [, , fileArg, tenantId = "tenant-1", workspaceId = "ws-1"] = process.argv;
438
+ if (!fileArg) {
439
+ console.error(
440
+ "Usage: import-patient.ts <path-to-patient.json> [tenantId] [workspaceId]"
441
+ );
442
+ process.exit(1);
443
+ }
444
+ try {
445
+ const result = await importPatientFromFile(fileArg, {
446
+ tenantId,
447
+ workspaceId
448
+ });
449
+ console.log(
450
+ `Imported Patient ${result.id} (tenant=${result.tenantId}, workspace=${result.workspaceId})`
451
+ );
452
+ } catch (err) {
453
+ console.error(err);
454
+ process.exit(1);
455
+ }
456
+ }
457
+ if (require.main === module) {
458
+ void main();
459
+ }
460
+
461
+ // src/data/rest-api/ehr/r4/Patient.ts
462
+ var BASE_PATH = "/ehr/r4/Patient";
463
+ var router = import_express.default.Router();
464
+ var SK2 = "CURRENT";
465
+ var TABLE_NAME = process.env.DYNAMO_TABLE_NAME ?? "jesttesttable";
466
+ async function listPatients(req, res) {
467
+ const { tenantId, workspaceId } = req.openhiContext;
468
+ const service = getEhrR4DataService(TABLE_NAME);
469
+ try {
470
+ const result = await service.entities.patient.query.gsi4({ tenantId, workspaceId }).go();
471
+ const entries = (result.data ?? []).map((item) => {
472
+ const resource = JSON.parse(decompressResource(item.resource));
473
+ return {
474
+ fullUrl: `${BASE_PATH}/${item.id}`,
475
+ resource: { ...resource, id: item.id }
476
+ };
477
+ });
478
+ const bundle = {
479
+ resourceType: "Bundle",
480
+ type: "searchset",
481
+ total: entries.length,
482
+ link: [{ relation: "self", url: BASE_PATH }],
483
+ entry: entries
484
+ };
485
+ return res.json(bundle);
486
+ } catch (err) {
487
+ console.error("GET /Patient list error:", err);
488
+ return res.status(500).json({
489
+ resourceType: "OperationOutcome",
490
+ issue: [
491
+ {
492
+ severity: "error",
493
+ code: "exception",
494
+ diagnostics: String(err)
495
+ }
496
+ ]
497
+ });
498
+ }
499
+ }
500
+ router.get("/", listPatients);
501
+ async function getPatientById(req, res) {
502
+ const id = String(req.params.id);
503
+ const { tenantId, workspaceId } = req.openhiContext;
504
+ const service = getEhrR4DataService(TABLE_NAME);
505
+ try {
506
+ const result = await service.entities.patient.get({ tenantId, workspaceId, id, sk: "CURRENT" }).go();
507
+ if (!result.data) {
508
+ return res.status(404).json({
509
+ resourceType: "OperationOutcome",
510
+ issue: [
511
+ {
512
+ severity: "error",
513
+ code: "not-found",
514
+ diagnostics: `Patient ${id} not found`
515
+ }
516
+ ]
517
+ });
518
+ }
519
+ const resource = JSON.parse(
520
+ decompressResource(result.data.resource)
521
+ );
522
+ return res.json({ ...resource, id: result.data.id });
523
+ } catch (err) {
524
+ console.error("GET Patient error:", err);
525
+ return res.status(500).json({
526
+ resourceType: "OperationOutcome",
527
+ issue: [
528
+ {
529
+ severity: "error",
530
+ code: "exception",
531
+ diagnostics: String(err)
532
+ }
533
+ ]
534
+ });
535
+ }
536
+ }
537
+ router.get("/:id", getPatientById);
538
+ async function createPatient(req, res) {
539
+ const ctx = req.openhiContext;
540
+ const { tenantId, workspaceId, date, userId, username } = ctx;
541
+ const body = req.body;
542
+ const id = body?.id ?? `patient-${Date.now()}`;
543
+ const patient = {
544
+ ...body,
545
+ resourceType: "Patient",
546
+ id,
547
+ meta: {
548
+ ...body?.meta ?? {},
549
+ lastUpdated: date,
550
+ versionId: "1"
551
+ }
552
+ };
553
+ const options = {
554
+ tenantId,
555
+ workspaceId,
556
+ createdDate: date,
557
+ createdById: userId,
558
+ createdByName: username,
559
+ modifiedDate: date,
560
+ modifiedById: userId,
561
+ modifiedByName: username
562
+ };
563
+ const service = getEhrR4DataService(TABLE_NAME);
564
+ try {
565
+ const attrs = patientToPutAttrs(patient, options);
566
+ await service.entities.patient.put(
567
+ attrs
568
+ ).go();
569
+ return res.status(201).location(`${BASE_PATH}/${id}`).json(patient);
570
+ } catch (err) {
571
+ console.error("POST Patient error:", err);
572
+ return res.status(500).json({
573
+ resourceType: "OperationOutcome",
574
+ issue: [
575
+ { severity: "error", code: "exception", diagnostics: String(err) }
576
+ ]
577
+ });
578
+ }
579
+ }
580
+ router.post("/", createPatient);
581
+ async function updatePatient(req, res) {
582
+ const id = String(req.params.id);
583
+ const ctx = req.openhiContext;
584
+ const { tenantId, workspaceId, date, userId, username } = ctx;
585
+ const body = req.body;
586
+ const patient = {
587
+ ...body,
588
+ resourceType: "Patient",
589
+ id,
590
+ meta: {
591
+ ...body?.meta ?? {},
592
+ lastUpdated: date,
593
+ versionId: "2"
594
+ }
595
+ };
596
+ const service = getEhrR4DataService(TABLE_NAME);
597
+ try {
598
+ const existing = await service.entities.patient.get({ tenantId, workspaceId, id, sk: SK2 }).go();
599
+ if (!existing.data) {
600
+ return res.status(404).json({
601
+ resourceType: "OperationOutcome",
602
+ issue: [
603
+ {
604
+ severity: "error",
605
+ code: "not-found",
606
+ diagnostics: `Patient ${id} not found`
607
+ }
608
+ ]
609
+ });
610
+ }
611
+ const existingMeta = existing.data.resource != null ? JSON.parse(decompressResource(existing.data.resource)).meta : void 0;
612
+ const patientWithMeta = {
613
+ ...patient,
614
+ meta: mergeAuditIntoMeta(
615
+ patient.meta ?? existingMeta,
616
+ {
617
+ modifiedDate: date,
618
+ modifiedById: userId,
619
+ modifiedByName: username
620
+ }
621
+ )
622
+ };
623
+ await service.entities.patient.patch({ tenantId, workspaceId, id, sk: SK2 }).set({
624
+ resource: compressResource(JSON.stringify(patientWithMeta)),
625
+ lastUpdated: date
626
+ }).go();
627
+ return res.json(patientWithMeta);
628
+ } catch (err) {
629
+ console.error("PUT Patient error:", err);
630
+ return res.status(500).json({
631
+ resourceType: "OperationOutcome",
632
+ issue: [
633
+ { severity: "error", code: "exception", diagnostics: String(err) }
634
+ ]
635
+ });
636
+ }
637
+ }
638
+ router.put("/:id", updatePatient);
639
+ async function deletePatient(req, res) {
640
+ const id = String(req.params.id);
641
+ const { tenantId, workspaceId } = req.openhiContext;
642
+ const service = getEhrR4DataService(TABLE_NAME);
643
+ try {
644
+ await service.entities.patient.delete({ tenantId, workspaceId, id, sk: SK2 }).go();
645
+ return res.status(204).send();
646
+ } catch (err) {
647
+ console.error("DELETE Patient error:", err);
648
+ return res.status(500).json({
649
+ resourceType: "OperationOutcome",
650
+ issue: [
651
+ { severity: "error", code: "exception", diagnostics: String(err) }
652
+ ]
653
+ });
654
+ }
655
+ }
656
+ router.delete("/:id", deletePatient);
657
+
658
+ // src/data/rest-api/rest-api.ts
659
+ var app = (0, import_express2.default)();
660
+ app.set("view engine", "ejs");
661
+ app.set("views", import_path.default.join(__dirname, "views"));
662
+ app.use((0, import_cors.default)());
663
+ app.use(import_express2.default.json());
664
+ app.use(import_express2.default.urlencoded({ extended: true }));
665
+ app.get("/", (_req, res) => {
666
+ return res.status(200).json({ message: "POC App is running" });
667
+ });
668
+ app.use("/ehr", openHiContextMiddleware);
669
+ app.use("/ehr/r4/Patient", router);
670
+
671
+ // src/data/lambda/rest-api-lambda.handler.ts
672
+ var handler = (0, import_serverless_express.default)({ app });
673
+ // Annotate the CommonJS export names for ESM import in node:
674
+ 0 && (module.exports = {
675
+ handler
676
+ });
677
+ //# sourceMappingURL=rest-api-lambda.handler.js.map