@openhi/constructs 0.0.0 → 0.0.1

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 +664 -0
  4. package/lib/index.d.ts +745 -3
  5. package/lib/index.js +1133 -19
  6. package/lib/index.js.map +1 -0
  7. package/lib/index.mjs +1120 -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 @@
1
+ {"version":3,"sources":["../src/data/lambda/rest-api-lambda.handler.ts","../src/data/rest-api/rest-api.ts","../src/data/middleware/open-hi-context.ts","../src/data/rest-api/ehr/r4/Patient.ts","../src/lib/compression.ts","../src/data/dynamo/ehr/r4/ehr-r4-data-service.ts","../src/data/dynamo/ehr/r4/Patient.ts","../src/data/import-patient.ts"],"sourcesContent":["import serverlessExpress from \"@codegenie/serverless-express\";\nimport { app } from \"../rest-api/rest-api\";\n\nexport const handler = serverlessExpress({ app });\n","import path from \"path\";\nimport cors from \"cors\";\nimport express, { Express, Request, Response } from \"express\";\nimport { openHiContextMiddleware } from \"../middleware/open-hi-context\";\nimport { patientRouter } from \"./ehr/r4/Patient\";\n\nconst app: Express = express();\n\napp.set(\"view engine\", \"ejs\");\napp.set(\"views\", path.join(__dirname, \"views\"));\n\napp.use(cors());\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\n\napp.get(\"/\", (_req: Request, res: Response) => {\n return res.status(200).json({ message: \"POC App is running\" });\n});\n\n// Tenant/workspace resolved from headers/env (or JWT when implemented); attached to req for /ehr routes\napp.use(\"/ehr\", openHiContextMiddleware);\n\n// FHIR R4 EHR endpoints: path structure mirrors folder structure (ehr/r4/Patient.ts → /ehr/r4/Patient)\napp.use(\"/ehr/r4/Patient\", patientRouter);\n\nexport { app };\n","import type { Request, Response, NextFunction } from \"express\";\n\n/** Static context used until JWT claims are implemented. */\nconst STATIC_TENANT_ID = \"tenant-1\";\nconst STATIC_WORKSPACE_ID = \"ws-1\";\nconst STATIC_USER_ID = \"rest-api\";\nconst STATIC_USER_NAME = \"REST API\";\n\n/**\n * Express middleware that sets req.openhiContext for /ehr (and other domain API)\n * routes. Context includes tenantId, workspaceId, and the three standard audit\n * fields (date, userId, username) for audit records and for merging into FHIR\n * data on mutations.\n *\n * **TODO: A future task will populate context from JWT claims** (e.g. after\n * verifying the token). For now, static values are used.\n *\n * @see sites/www-docs/content/packages/@openhi/constructs/rest-api.md — Middleware\n */\nexport function openHiContextMiddleware(\n req: Request,\n _res: Response,\n next: NextFunction,\n): void {\n const now = new Date().toISOString();\n req.openhiContext = {\n tenantId: STATIC_TENANT_ID,\n workspaceId: STATIC_WORKSPACE_ID,\n date: now,\n userId: STATIC_USER_ID,\n username: STATIC_USER_NAME,\n };\n next();\n}\n","import express, { Request, Response } from \"express\";\nimport {\n compressResource,\n decompressResource,\n} from \"../../../../lib/compression\";\nimport { getEhrR4DataService } from \"../../../dynamo/ehr/r4/ehr-r4-data-service\";\nimport {\n mergeAuditIntoMeta,\n patientToPutAttrs,\n type ImportPatientOptions,\n} from \"../../../import-patient\";\n\nconst BASE_PATH = \"/ehr/r4/Patient\";\nconst router: express.Router = express.Router();\nconst SK = \"CURRENT\";\n\nconst TABLE_NAME = process.env.DYNAMO_TABLE_NAME ?? \"jesttesttable\";\n\n/**\n * GET /ehr/r4/Patient — search/list: returns a FHIR Bundle (searchset) from the data store.\n * Uses GSI4 (Resource Type Index) to list all Patients in the workspace without a table scan.\n * @see {@link https://github.com/codedrifters/openhi/blob/main/sites/www-docs/content/architecture/dynamodb-single-table-design.md | DynamoDB Single-Table Design} — GSI4, Query and Access Rules (no scans).\n */\nexport async function listPatients(\n req: Request,\n res: Response,\n): Promise<Response> {\n const { tenantId, workspaceId } = req.openhiContext!;\n const service = getEhrR4DataService(TABLE_NAME);\n\n try {\n const result = await service.entities.patient.query\n .gsi4({ tenantId, workspaceId })\n .go();\n\n const entries = (result.data ?? []).map((item) => {\n const resource = JSON.parse(decompressResource(item.resource)) as Record<\n string,\n unknown\n >;\n return {\n fullUrl: `${BASE_PATH}/${item.id}`,\n resource: { ...resource, id: item.id },\n };\n });\n const bundle = {\n resourceType: \"Bundle\",\n type: \"searchset\",\n total: entries.length,\n link: [{ relation: \"self\", url: BASE_PATH }],\n entry: entries,\n };\n return res.json(bundle);\n } catch (err: unknown) {\n console.error(\"GET /Patient list error:\", err);\n return res.status(500).json({\n resourceType: \"OperationOutcome\",\n issue: [\n {\n severity: \"error\",\n code: \"exception\",\n diagnostics: String(err),\n },\n ],\n });\n }\n}\n\nrouter.get(\"/\", listPatients);\n\nexport async function getPatientById(\n req: Request,\n res: Response,\n): Promise<Response> {\n const id = String(req.params.id);\n const { tenantId, workspaceId } = req.openhiContext!;\n const service = getEhrR4DataService(TABLE_NAME);\n\n try {\n const result = await service.entities.patient\n .get({ tenantId, workspaceId, id, sk: \"CURRENT\" })\n .go();\n\n if (!result.data) {\n return res.status(404).json({\n resourceType: \"OperationOutcome\",\n issue: [\n {\n severity: \"error\",\n code: \"not-found\",\n diagnostics: `Patient ${id} not found`,\n },\n ],\n });\n }\n\n const resource = JSON.parse(\n decompressResource(result.data.resource),\n ) as Record<string, unknown>;\n return res.json({ ...resource, id: result.data.id });\n } catch (err: unknown) {\n console.error(\"GET Patient error:\", err);\n return res.status(500).json({\n resourceType: \"OperationOutcome\",\n issue: [\n {\n severity: \"error\",\n code: \"exception\",\n diagnostics: String(err),\n },\n ],\n });\n }\n}\n\n/** GET /ehr/r4/Patient/:id — read: returns a single Patient resource from the data store or 404. */\nrouter.get(\"/:id\", getPatientById);\n\n/** POST /ehr/r4/Patient — create: accepts Patient in body, persists via data store, returns 201. */\nexport async function createPatient(\n req: Request,\n res: Response,\n): Promise<Response> {\n const ctx = req.openhiContext!;\n const { tenantId, workspaceId, date, userId, username } = ctx;\n const body = req.body as Record<string, unknown>;\n const id = (body?.id as string) ?? `patient-${Date.now()}`;\n const patient = {\n ...body,\n resourceType: \"Patient\",\n id,\n meta: {\n ...((body?.meta as object) ?? {}),\n lastUpdated: date,\n versionId: \"1\",\n },\n } as { resourceType: string; id: string; meta?: { lastUpdated?: string } };\n const options: ImportPatientOptions = {\n tenantId,\n workspaceId,\n createdDate: date,\n createdById: userId,\n createdByName: username,\n modifiedDate: date,\n modifiedById: userId,\n modifiedByName: username,\n };\n const service = getEhrR4DataService(TABLE_NAME);\n\n try {\n const attrs = patientToPutAttrs(patient, options);\n await service.entities.patient\n .put(\n attrs as unknown as Parameters<typeof service.entities.patient.put>[0],\n )\n .go();\n return res.status(201).location(`${BASE_PATH}/${id}`).json(patient);\n } catch (err: unknown) {\n console.error(\"POST Patient error:\", err);\n return res.status(500).json({\n resourceType: \"OperationOutcome\",\n issue: [\n { severity: \"error\", code: \"exception\", diagnostics: String(err) },\n ],\n });\n }\n}\n\nrouter.post(\"/\", createPatient);\n\n/** PUT /ehr/r4/Patient/:id — update: accepts Patient in body, persists via data store, returns 200. */\nexport async function updatePatient(\n req: Request,\n res: Response,\n): Promise<Response> {\n const id = String(req.params.id);\n const ctx = req.openhiContext!;\n const { tenantId, workspaceId, date, userId, username } = ctx;\n const body = req.body as Record<string, unknown>;\n const patient = {\n ...body,\n resourceType: \"Patient\",\n id,\n meta: {\n ...((body?.meta as object) ?? {}),\n lastUpdated: date,\n versionId: \"2\",\n },\n };\n const service = getEhrR4DataService(TABLE_NAME);\n\n try {\n const existing = await service.entities.patient\n .get({ tenantId, workspaceId, id, sk: SK })\n .go();\n if (!existing.data) {\n return res.status(404).json({\n resourceType: \"OperationOutcome\",\n issue: [\n {\n severity: \"error\",\n code: \"not-found\",\n diagnostics: `Patient ${id} not found`,\n },\n ],\n });\n }\n const existingMeta =\n existing.data.resource != null\n ? (\n JSON.parse(decompressResource(existing.data.resource)) as {\n meta?: Record<string, unknown>;\n }\n ).meta\n : undefined;\n const patientWithMeta = {\n ...patient,\n meta: mergeAuditIntoMeta(\n (patient.meta as Record<string, unknown> | undefined) ?? existingMeta,\n {\n modifiedDate: date,\n modifiedById: userId,\n modifiedByName: username,\n },\n ),\n };\n await service.entities.patient\n .patch({ tenantId, workspaceId, id, sk: SK })\n .set({\n resource: compressResource(JSON.stringify(patientWithMeta)),\n lastUpdated: date,\n })\n .go();\n return res.json(patientWithMeta);\n } catch (err: unknown) {\n console.error(\"PUT Patient error:\", err);\n return res.status(500).json({\n resourceType: \"OperationOutcome\",\n issue: [\n { severity: \"error\", code: \"exception\", diagnostics: String(err) },\n ],\n });\n }\n}\n\nrouter.put(\"/:id\", updatePatient);\n\n/** DELETE /ehr/r4/Patient/:id — delete: removes from data store, returns 204. */\nexport async function deletePatient(\n req: Request,\n res: Response,\n): Promise<Response> {\n const id = String(req.params.id);\n const { tenantId, workspaceId } = req.openhiContext!;\n const service = getEhrR4DataService(TABLE_NAME);\n\n try {\n await service.entities.patient\n .delete({ tenantId, workspaceId, id, sk: SK })\n .go();\n return res.status(204).send();\n } catch (err: unknown) {\n console.error(\"DELETE Patient error:\", err);\n return res.status(500).json({\n resourceType: \"OperationOutcome\",\n issue: [\n { severity: \"error\", code: \"exception\", diagnostics: String(err) },\n ],\n });\n }\n}\n\nrouter.delete(\"/:id\", deletePatient);\n\nexport { router as patientRouter };\n","import { gzipSync, gunzipSync } from \"node:zlib\";\n\n/** Envelope format version. See ADR 2026-02-15-02 (data layer compression). */\nconst ENVELOPE_VERSION = 1;\n\n/**\n * Compression algorithm identifiers supported by the envelope (string values).\n * Only algos that Node.js supports out of the box (zlib): gzip, brotli, deflate.\n * \"none\" = uncompressed payload. zstd was considered in the ADR but requires native addon/WASM.\n */\nexport const COMPRESSION_ALGOS = {\n NONE: \"none\",\n GZIP: \"gzip\",\n BROTLI: \"brotli\",\n DEFLATE: \"deflate\",\n} as const;\n\n/** Algorithm value for envelope `algo`; only gzip and none are implemented today. */\nexport type CompressionAlgo =\n (typeof COMPRESSION_ALGOS)[keyof typeof COMPRESSION_ALGOS];\n\n/** Stored value is a JSON string of this envelope. */\ninterface CompressionEnvelope {\n v: number;\n algo: string;\n payload: string;\n}\n\nfunction isEnvelope(obj: unknown): obj is CompressionEnvelope {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"v\" in obj &&\n \"algo\" in obj &&\n \"payload\" in obj &&\n typeof (obj as CompressionEnvelope).payload === \"string\"\n );\n}\n\n/**\n * Compresses a JSON string (e.g. serialized FHIR resource) for storage in DynamoDB.\n * Uses a versioned envelope: { v, algo, payload } with gzip+base64 in payload.\n * Used by the data layer on write; see REST API docs (compression in data layer).\n * Optional compression: pass `{ algo: COMPRESSION_ALGOS.NONE }` to store in envelope without compressing.\n */\nexport function compressResource(\n jsonString: string,\n options?: { algo?: CompressionAlgo },\n): string {\n const algo = options?.algo ?? COMPRESSION_ALGOS.GZIP;\n if (algo === COMPRESSION_ALGOS.NONE) {\n const envelope: CompressionEnvelope = {\n v: ENVELOPE_VERSION,\n algo: COMPRESSION_ALGOS.NONE,\n payload: jsonString,\n };\n return JSON.stringify(envelope);\n }\n const buf = Buffer.from(jsonString, \"utf-8\");\n const payload = gzipSync(buf).toString(\"base64\");\n const envelope: CompressionEnvelope = {\n v: ENVELOPE_VERSION,\n algo: COMPRESSION_ALGOS.GZIP,\n payload,\n };\n return JSON.stringify(envelope);\n}\n\n/**\n * Decompresses a stored value: versioned envelope (v, algo, payload) or legacy gzip+base64 / raw.\n * If the value is not valid envelope JSON, falls back to legacy: try gzip magic on base64, else return as-is.\n */\nexport function decompressResource(compressedOrRaw: string): string {\n try {\n const parsed = JSON.parse(compressedOrRaw) as unknown;\n if (isEnvelope(parsed)) {\n if (parsed.algo === COMPRESSION_ALGOS.GZIP) {\n const buf = Buffer.from(parsed.payload, \"base64\");\n return gunzipSync(buf).toString(\"utf-8\");\n }\n if (parsed.algo === COMPRESSION_ALGOS.NONE) {\n return parsed.payload;\n }\n // Unknown algo: return payload as-is (safe fallback per ADR)\n return parsed.payload;\n }\n } catch {\n // Not valid envelope JSON — legacy path\n }\n\n // Legacy: pre-envelope gzip+base64 or raw\n try {\n const buf = Buffer.from(compressedOrRaw, \"base64\");\n if (buf.length >= 2 && buf[0] === 0x1f && buf[1] === 0x8b) {\n return gunzipSync(buf).toString(\"utf-8\");\n }\n } catch {\n // not base64 or gunzip failed\n }\n return compressedOrRaw;\n}\n","import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { Service } from \"electrodb\";\nimport { Patient } from \"./Patient\";\n\n/**\n * DynamoDB table name for the data store. Set via DYNAMO_TABLE_NAME at runtime\n * (e.g. from Lambda env); defaults for local/test.\n */\nconst table = process.env.DYNAMO_TABLE_NAME ?? \"jesttesttable\";\n\n/**\n * DynamoDB client. When MOCK_DYNAMODB_ENDPOINT is set (e.g. local DynamoDB or\n * jest-dynalite), uses that endpoint with no SSL and region \"local\".\n */\nconst client = new DynamoDBClient({\n ...(process.env.MOCK_DYNAMODB_ENDPOINT && {\n endpoint: process.env.MOCK_DYNAMODB_ENDPOINT,\n sslEnabled: false,\n region: \"local\",\n }),\n});\n\nconst entities = { patient: Patient };\n\n/**\n * ElectroDB Service for the single-table data store. Provides access to Patient\n * and other entities; use with the data store table (PK, SK, GSI1, GSI2, GSI3, GSI4).\n */\nexport const EhrR4DataService = new Service(entities, { table, client });\n\n/**\n * Returns an ElectroDB Service for the data store using the given table name.\n * Use in tests with a dedicated table (e.g. \"data-store-test\" in jest-dynalite).\n */\nexport function getEhrR4DataService(\n tableName: string,\n): typeof EhrR4DataService {\n return new Service(entities, { table: tableName, client });\n}\n","import { Entity } from \"electrodb\";\n\n/**\n * Patient data-store entity based on FHIR (single-table store).\n *\n * Key structure: PK = TID#<tenantId>#WID#<workspaceId>#RT#Patient#ID#<id>, SK = CURRENT.\n * Standard attributes (FHIR source and entity purpose) are documented in the Data-Store Entity Standards (FHIR).\n *\n * @see sites/www-docs/content/reference/data-store-entities.md — Standard attributes (all FHIR domain resources)\n * @see sites/www-docs/content/architecture/dynamodb-single-table-design.md\n */\nexport const Patient = new Entity({\n model: {\n entity: \"patient\",\n service: \"fhir\",\n version: \"01\",\n },\n attributes: {\n /** Sort key. \"CURRENT\" for current version; version history in S3. */\n sk: {\n type: \"string\",\n required: true,\n default: \"CURRENT\",\n },\n tenantId: {\n type: \"string\",\n required: true,\n },\n workspaceId: {\n type: \"string\",\n required: true,\n },\n /** FHIR Resource.id; logical id in URL and PK. */\n id: {\n type: \"string\",\n required: true,\n },\n /** FHIR resource as JSON string. JSON.stringify(resource) on write; JSON.parse(item.resource) on read. */\n resource: {\n type: \"string\",\n required: true,\n },\n /** Version id (e.g. ULID). Tracks current version; S3 history key. */\n vid: {\n type: \"string\",\n required: true,\n },\n lastUpdated: {\n type: \"string\",\n required: true,\n },\n deleted: {\n type: \"boolean\",\n required: false,\n },\n bundleId: {\n type: \"string\",\n required: false,\n },\n msgId: {\n type: \"string\",\n required: false,\n },\n // Audit is in FHIR resource meta (meta.extension), not item attributes. See data-store-entities.md.\n // --- GSI2 (Identifier Lookup): optional; set when indexing this patient by identifier (e.g. MRN)\n /** Identifier system (e.g. MRN system URI). When set with identifierValue, item is written to GSI2. */\n identifierSystem: {\n type: \"string\",\n required: false,\n },\n /** Identifier value (e.g. MRN). When set with identifierSystem, item is written to GSI2. */\n identifierValue: {\n type: \"string\",\n required: false,\n },\n /** For GSI2/GSI3 projection: base table PK/SK so GetItem can be used after query. */\n resourcePk: {\n type: \"string\",\n required: false,\n },\n resourceSk: {\n type: \"string\",\n required: false,\n },\n /** For GSI2 projection: display name for roster/lookup. */\n display: {\n type: \"string\",\n required: false,\n },\n /** For GSI2 projection: resource status if applicable. */\n status: {\n type: \"string\",\n required: false,\n },\n // --- GSI3 (Facility Ops): optional; set when indexing this patient on a facility roster\n /** Facility id. When set with normalizedName, item is written to GSI3. */\n facilityId: {\n type: \"string\",\n required: false,\n },\n /** Normalized display name for roster sort. When set with facilityId, item is written to GSI3. */\n normalizedName: {\n type: \"string\",\n required: false,\n },\n },\n indexes: {\n /** Base table: PK, SK (data store key names). PK is built from tenantId, workspaceId, id; do not supply PK from outside. */\n record: {\n pk: {\n field: \"PK\",\n composite: [\"tenantId\", \"workspaceId\", \"id\"],\n template: \"TID#${tenantId}#WID#${workspaceId}#RT#Patient#ID#${id}\",\n },\n sk: {\n field: \"SK\",\n composite: [\"sk\"],\n },\n },\n\n /**\n * GSI1 — Reverse Reference: query \"what references this patient?\".\n * Patient items are never written to GSI1 (condition: false); reference index items\n * are written by other resources. This index enables querying GSI1 by REFTO#RT#Patient#ID#<id>.\n */\n gsi1: {\n index: \"GSI1\",\n condition: () => false,\n pk: {\n field: \"GSI1PK\",\n composite: [\"tenantId\", \"workspaceId\", \"id\"],\n template:\n \"TID#${tenantId}#WID#${workspaceId}#REFTO#RT#Patient#ID#${id}\",\n },\n sk: {\n field: \"GSI1SK\",\n composite: [],\n },\n },\n\n /** GSI2 — Identifier Lookup: MRN, NPI, member ID, etc. Keys built from identifier components. */\n gsi2: {\n index: \"GSI2\",\n condition: (attr) =>\n attr.identifierSystem != null && attr.identifierValue != null,\n pk: {\n field: \"GSI2PK\",\n composite: [\n \"tenantId\",\n \"workspaceId\",\n \"identifierSystem\",\n \"identifierValue\",\n ],\n template:\n \"TID#${tenantId}#WID#${workspaceId}#IDENT#${identifierSystem}#${identifierValue}\",\n },\n sk: {\n field: \"GSI2SK\",\n composite: [\"id\"],\n template: \"RT#Patient#ID#${id}\",\n },\n },\n /** GSI3 — Facility Ops: facility roster, worklists. Keys built from facility + name. */\n gsi3: {\n index: \"GSI3\",\n condition: (attr) =>\n attr.facilityId != null && attr.normalizedName != null,\n pk: {\n field: \"GSI3PK\",\n composite: [\"tenantId\", \"workspaceId\", \"facilityId\"],\n template: \"TID#${tenantId}#WID#${workspaceId}#FAC#${facilityId}\",\n },\n sk: {\n field: \"GSI3SK\",\n composite: [\"id\", \"normalizedName\"],\n template: \"TYPE#PATIENT#PAT#${id}#NAME#${normalizedName}\",\n },\n },\n /** GSI4 — Resource Type Index: list all Patients in workspace (no scan). */\n gsi4: {\n index: \"GSI4\",\n condition: () => true,\n pk: {\n field: \"GSI4PK\",\n composite: [\"tenantId\", \"workspaceId\"],\n template: \"TID#${tenantId}#WID#${workspaceId}#RT#Patient\",\n },\n sk: {\n field: \"GSI4SK\",\n composite: [\"id\"],\n template: \"ID#${id}\",\n },\n },\n },\n});\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { compressResource } from \"../lib/compression\";\nimport { getEhrR4DataService } from \"./dynamo/ehr/r4/ehr-r4-data-service\";\n\n/** OpenHI extension URLs for audit in resource meta (per ADR 2026-01-13-06). */\nconst OPENHI_EXT = \"http://openhi.org/fhir/StructureDefinition\";\n\n/** Audit fields stored in FHIR resource meta.extension. */\nexport interface AuditFields {\n createdDate?: string;\n createdById?: string;\n createdByName?: string;\n modifiedDate?: string;\n modifiedById?: string;\n modifiedByName?: string;\n deletedDate?: string;\n deletedById?: string;\n deletedByName?: string;\n}\n\n/** Builds meta.extension entries for audit; merges with existing meta. */\nexport function mergeAuditIntoMeta(\n meta: Record<string, unknown> | undefined,\n audit: AuditFields,\n): Record<string, unknown> {\n const existing = meta ?? {};\n const ext: Array<{\n url: string;\n valueString?: string;\n valueDateTime?: string;\n }> = [\n ...(Array.isArray(existing.extension)\n ? (existing.extension as Array<{\n url: string;\n valueString?: string;\n valueDateTime?: string;\n }>)\n : []),\n ];\n const byUrl = new Map(ext.map((e) => [e.url, e]));\n function set(\n url: string,\n value: string | undefined,\n type: \"valueString\" | \"valueDateTime\",\n ) {\n if (value == null) return;\n byUrl.set(url, { url, [type]: value });\n }\n set(`${OPENHI_EXT}/created-date`, audit.createdDate, \"valueDateTime\");\n set(`${OPENHI_EXT}/created-by-id`, audit.createdById, \"valueString\");\n set(`${OPENHI_EXT}/created-by-name`, audit.createdByName, \"valueString\");\n set(`${OPENHI_EXT}/modified-date`, audit.modifiedDate, \"valueDateTime\");\n set(`${OPENHI_EXT}/modified-by-id`, audit.modifiedById, \"valueString\");\n set(`${OPENHI_EXT}/modified-by-name`, audit.modifiedByName, \"valueString\");\n set(`${OPENHI_EXT}/deleted-date`, audit.deletedDate, \"valueDateTime\");\n set(`${OPENHI_EXT}/deleted-by-id`, audit.deletedById, \"valueString\");\n set(`${OPENHI_EXT}/deleted-by-name`, audit.deletedByName, \"valueString\");\n return { ...existing, extension: Array.from(byUrl.values()) };\n}\n\n/** Minimal FHIR Patient shape needed for import (id and resourceType required). */\ninterface FhirPatientLike {\n resourceType: string;\n id: string;\n meta?: Record<string, unknown>;\n}\n\n/** FHIR Bundle entry (e.g. Synthea transaction bundle). */\ninterface BundleEntry {\n fullUrl?: string;\n resource?: {\n resourceType?: string;\n id?: string;\n meta?: { lastUpdated?: string };\n };\n}\n\n/**\n * Extracts a Patient from parsed JSON. Accepts either:\n * - A standalone Patient resource (root has resourceType \"Patient\"), or\n * - A FHIR Bundle (e.g. Synthea transaction) — uses the first entry whose resource is a Patient.\n */\nfunction extractPatient(parsed: unknown): FhirPatientLike {\n if (parsed && typeof parsed === \"object\" && \"resourceType\" in parsed) {\n const root = parsed as {\n resourceType?: string;\n id?: string;\n meta?: { lastUpdated?: string };\n };\n if (root.resourceType === \"Patient\" && root.id) {\n return root as FhirPatientLike;\n }\n if (root.resourceType === \"Bundle\" && \"entry\" in parsed) {\n const entries = (parsed as { entry?: BundleEntry[] }).entry;\n if (Array.isArray(entries)) {\n const patientEntry = entries.find(\n (e) => e?.resource?.resourceType === \"Patient\" && e.resource.id,\n );\n if (patientEntry?.resource) {\n return patientEntry.resource as FhirPatientLike;\n }\n }\n }\n }\n throw new Error(\n \"File must be a FHIR Patient resource or a Bundle containing at least one Patient entry\",\n );\n}\n\nconst SK = \"CURRENT\";\n\n/** Default audit values for create/modify when importing. */\nconst defaultAudit = {\n createdDate: new Date().toISOString(),\n createdById: \"import\",\n createdByName: \"Bulk import\",\n modifiedDate: new Date().toISOString(),\n modifiedById: \"import\",\n modifiedByName: \"Bulk import\",\n};\n\nexport interface ImportPatientOptions {\n tenantId: string;\n workspaceId: string;\n tableName?: string;\n /** Audit fields at same level as tenantId/workspaceId; merged with defaults. */\n createdDate?: string;\n createdById?: string;\n createdByName?: string;\n modifiedDate?: string;\n modifiedById?: string;\n modifiedByName?: string;\n}\n\n/**\n * Maps a FHIR Patient (from JSON) to the attributes required for Patient.put().\n * Uses placeholder GSI2/GSI3 fields so ElectroDB index conditions are satisfied.\n */\nexport function patientToPutAttrs(\n patient: FhirPatientLike,\n options: ImportPatientOptions,\n): Record<string, unknown> {\n const {\n tenantId,\n workspaceId,\n createdDate,\n createdById,\n createdByName,\n modifiedDate,\n modifiedById,\n modifiedByName,\n } = options;\n const lastUpdated =\n (patient.meta?.lastUpdated as string | undefined) ??\n modifiedDate ??\n defaultAudit.modifiedDate ??\n new Date().toISOString();\n const auditMerged: AuditFields = {\n ...defaultAudit,\n ...(createdDate != null && { createdDate }),\n ...(createdById != null && { createdById }),\n ...(createdByName != null && { createdByName }),\n ...(modifiedDate != null && { modifiedDate }),\n ...(modifiedById != null && { modifiedById }),\n ...(modifiedByName != null && { modifiedByName }),\n };\n\n const patientWithMeta = {\n ...patient,\n meta: mergeAuditIntoMeta(patient.meta, auditMerged),\n };\n if (lastUpdated && !patientWithMeta.meta.lastUpdated) {\n (patientWithMeta.meta as Record<string, unknown>).lastUpdated = lastUpdated;\n }\n\n return {\n sk: SK,\n tenantId,\n workspaceId,\n id: patient.id,\n resource: compressResource(JSON.stringify(patientWithMeta)),\n vid:\n lastUpdated.replace(/[-:T.Z]/g, \"\").slice(0, 12) ||\n Date.now().toString(36),\n lastUpdated,\n identifierSystem: \"\",\n identifierValue: \"\",\n facilityId: \"\",\n normalizedName: \"\",\n };\n}\n\n/**\n * Reads a single Patient JSON file and imports it into the FHIR store.\n * Table name: options.tableName ?? process.env.DYNAMO_TABLE_NAME ?? \"jesttesttable\".\n */\nexport async function importPatientFromFile(\n filePath: string,\n options: ImportPatientOptions,\n): Promise<{ id: string; tenantId: string; workspaceId: string }> {\n const resolved = resolve(filePath);\n const raw = readFileSync(resolved, \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n const patient = extractPatient(parsed);\n\n const tableName =\n options.tableName ?? process.env.DYNAMO_TABLE_NAME ?? \"jesttesttable\";\n const service = getEhrR4DataService(tableName);\n const attrs = patientToPutAttrs(patient, options);\n\n const result = await service.entities.patient\n .put(attrs as unknown as Parameters<typeof service.entities.patient.put>[0])\n .go();\n\n const data = (\n result as { data?: { id: string; tenantId: string; workspaceId: string } }\n ).data;\n if (!data) {\n throw new Error(`Put failed for Patient ${patient.id}`);\n }\n\n return {\n id: data.id,\n tenantId: data.tenantId,\n workspaceId: data.workspaceId,\n };\n}\n\n/** Run as script: node/ts-node import-patient.ts <path-to-patient.json> [tenantId] [workspaceId] */\nasync function main(): Promise<void> {\n const [, , fileArg, tenantId = \"tenant-1\", workspaceId = \"ws-1\"] =\n process.argv;\n\n if (!fileArg) {\n console.error(\n \"Usage: import-patient.ts <path-to-patient.json> [tenantId] [workspaceId]\",\n );\n process.exit(1);\n }\n\n try {\n const result = await importPatientFromFile(fileArg, {\n tenantId,\n workspaceId,\n });\n console.log(\n `Imported Patient ${result.id} (tenant=${result.tenantId}, workspace=${result.workspaceId})`,\n );\n } catch (err) {\n console.error(err);\n process.exit(1);\n }\n}\n\nif (require.main === module) {\n void main();\n}\n"],"mappings":"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","names":["import_express","envelope","import_electrodb","express","SK","express","path","cors","serverlessExpress"]}