@openhi/constructs 0.0.143 → 0.0.145

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/package.json CHANGED
@@ -55,9 +55,9 @@
55
55
  "pg": "^8.21.0",
56
56
  "type-fest": "^4",
57
57
  "ulid": "^3.0.2",
58
- "@openhi/types": "0.0.0",
58
+ "@openhi/config": "0.0.0",
59
59
  "@openhi/workflows": "0.0.0",
60
- "@openhi/config": "0.0.0"
60
+ "@openhi/types": "0.0.0"
61
61
  },
62
62
  "devEngines": {
63
63
  "packageManager": {
@@ -71,7 +71,7 @@
71
71
  "publishConfig": {
72
72
  "access": "public"
73
73
  },
74
- "version": "0.0.143",
74
+ "version": "0.0.145",
75
75
  "types": "lib/index.d.ts",
76
76
  "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm exec projen\".",
77
77
  "scripts": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/data/operations/control/user/user-find-by-sub-operation.ts","../src/data/operations/control/user/user-resource-helpers.ts","../src/data/operations/fhir-reference.ts","../src/data/operations/control/user/user-create-operation.ts","../src/data/operations/control/user/user-get-by-id-operation.ts","../src/data/operations/control/user/user-list-operation.ts","../src/data/operations/control/user/user-switch-tenant-workspace-operation.ts","../src/data/operations/control/membership/membership-list-by-user-operation.ts","../src/data/operations/control/user/user-update-operation.ts","../src/data/operations/control/user/user-delete-operation.ts"],"sourcesContent":["import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { OpenHiContext } from \"../../../openhi-context\";\n\nexport interface FindUserBySubParams {\n context: OpenHiContext;\n cognitoSub: string;\n tableName?: string;\n}\n\nexport interface FindUserBySubResult {\n id: string;\n cognitoSub?: string;\n resource: string;\n vid: string;\n}\n\n/**\n * Look up a User by Cognito sub via GSI2, projecting the row to a stable\n * result shape. Returns `undefined` when no row matches.\n */\nexport async function findUserBySubOperation(\n params: FindUserBySubParams,\n): Promise<FindUserBySubResult | undefined> {\n const { cognitoSub, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n const result = await service.entities.user.query\n .gsi2({ cognitoSub })\n .go({ limit: 1 });\n const item = result.data?.[0];\n if (!item) {\n return undefined;\n }\n return {\n id: item.id,\n cognitoSub: item.cognitoSub,\n resource: item.resource,\n vid: item.vid,\n };\n}\n","import type { User } from \"@openhi/types\";\n\n/**\n * Helpers for working with persisted OpenHI User resources. Co-located with\n * the User operations because both the Cognito triggers and the onboarding\n * workflow consume these alongside `findUserBySubOperation`.\n */\n\n// Defensive parse — JSON.parse may yield any shape, so every field is optional.\nexport type UserResource = Partial<User>;\n\n/**\n * Existing User resources are stored as JSON strings in the data store; parse\n * defensively so a malformed payload returns `undefined` rather than throwing.\n */\nexport function parseUserResource(resource: string): UserResource | undefined {\n try {\n return JSON.parse(resource) as UserResource;\n } catch {\n return undefined;\n }\n}\n","/**\n * Pure helpers for working with FHIR Reference fields. Shared across data-plane\n * and control-plane operations and the handlers that wrap them.\n */\n\n/**\n * Extract the id portion from a FHIR-style reference such as `Patient/<id>` or\n * `Tenant/<id>`. Returns `undefined` if the reference is missing, does not\n * match the prefix, or has an empty id after the prefix.\n */\nexport function idFromReference(\n reference: string | undefined,\n prefix: string,\n): string | undefined {\n if (!reference || !reference.startsWith(prefix)) {\n return undefined;\n }\n const id = reference.slice(prefix.length);\n return id.length > 0 ? id : undefined;\n}\n","import { extractSummary, type FhirResourceLike } from \"@openhi/types\";\nimport { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { OpenHiContext } from \"../../../openhi-context\";\n\nexport interface UserCreateParams {\n context: OpenHiContext;\n body: { id?: string; resource?: Record<string, unknown> | string };\n tableName?: string;\n}\n\nexport interface UserCreateResult {\n id: string;\n resource: { resourceType: string; id: string; [key: string]: unknown };\n meta: { lastUpdated: string; versionId: string };\n}\n\nexport async function createUserOperation(\n params: UserCreateParams,\n): Promise<UserCreateResult> {\n const { context, body, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n const id = body.id ?? `user-${Date.now()}`;\n const parsedResource =\n typeof body.resource === \"string\"\n ? (JSON.parse(body.resource) as Record<string, unknown>)\n : (body.resource ?? {});\n\n const lastUpdated = context.date ?? new Date().toISOString();\n const vid = `1`;\n\n const resource = { resourceType: \"User\", id, ...parsedResource };\n const summary = JSON.stringify(extractSummary(resource as FhirResourceLike));\n\n await service.entities.user\n .put({\n id,\n resource: JSON.stringify(resource),\n summary,\n vid,\n lastUpdated,\n })\n .go();\n\n return {\n id,\n resource,\n meta: { lastUpdated, versionId: vid },\n };\n}\n","import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { NotFoundError } from \"../../../errors\";\nimport { OpenHiContext } from \"../../../openhi-context\";\n\nexport interface UserGetByIdParams {\n context: OpenHiContext;\n id: string;\n tableName?: string;\n}\n\nexport interface UserGetByIdResult {\n id: string;\n resource: { resourceType: string; id: string; [key: string]: unknown };\n}\n\nexport async function getUserByIdOperation(\n params: UserGetByIdParams,\n): Promise<UserGetByIdResult> {\n const { id, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n const response = await service.entities.user.get({ id, sk: \"CURRENT\" }).go();\n\n const item = response.data;\n if (!item) {\n throw new NotFoundError(`User not found: ${id}`);\n }\n\n const parsedResource = JSON.parse(item.resource) as Record<string, unknown>;\n\n return {\n id,\n resource: { resourceType: \"User\", id, ...parsedResource },\n };\n}\n","import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { SHARD_COUNT } from \"../../../dynamo/shard\";\nimport { OpenHiContext } from \"../../../openhi-context\";\nimport {\n batchGetWithRetry,\n dispatchListMode,\n type ListOperationMode,\n} from \"../../data-operations-common\";\n\nconst SK = \"CURRENT\";\n\nexport interface UserListParams {\n context: OpenHiContext;\n tableName?: string;\n /** #853: defaults to `\"full\"`. `\"summary\"` skips BatchGet, `\"count\"` returns total only. */\n mode?: ListOperationMode;\n}\n\nexport interface UserListResult {\n entries: Array<{\n id: string;\n resource: { resourceType: string; id: string; [key: string]: unknown };\n }>;\n total: number;\n}\n\n/**\n * Lists Users via GSI1 (sharded). `mode` (default `\"full\"`) selects between BatchGet hydration,\n * summary-only (parse `summary` JSON projected on GSI1), or count-only (skip both). See\n * `dispatchListMode` in data-operations-common for the canonical mode contract.\n */\nexport async function listUsersOperation(\n params: UserListParams,\n): Promise<UserListResult> {\n const { tableName, mode = \"full\" } = params;\n const service = getDynamoControlService(tableName);\n\n const shardResults = await Promise.all(\n Array.from({ length: SHARD_COUNT }, (_, shard) =>\n service.entities.user.query.gsi1({ gsi1Shard: String(shard) }).go(),\n ),\n );\n\n return dispatchListMode<\n { id: string; resource: string },\n UserListResult[\"entries\"][number]\n >(mode, shardResults, {\n hydrate: (orderedIds) =>\n batchGetWithRetry(\n service.entities.user,\n orderedIds.map((id) => ({ id, sk: SK })),\n ) as Promise<Array<{ id: string; resource: string }>>,\n getId: (item) => item.id,\n buildEntry: (id, item) => ({\n id,\n resource: {\n resourceType: \"User\",\n id,\n ...(JSON.parse(item.resource) as Record<string, unknown>),\n },\n }),\n buildSummaryEntry: (id, parsed) => ({\n id,\n resource: { resourceType: \"User\", id, ...parsed },\n }),\n });\n}\n","import { extractSummary, type FhirResourceLike } from \"@openhi/types\";\nimport { findUserBySubOperation } from \"./user-find-by-sub-operation\";\nimport { parseUserResource } from \"./user-resource-helpers\";\nimport { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport {\n ForbiddenError,\n NotFoundError,\n ValidationError,\n} from \"../../../errors\";\nimport { idFromReference } from \"../../fhir-reference\";\nimport { membershipListByUserOperation } from \"../membership/membership-list-by-user-operation\";\n\nconst SK = \"CURRENT\";\n\nexport interface UserSwitchTenantWorkspaceParams {\n cognitoSub: string;\n tenantReference: string;\n workspaceReference: string;\n tableName?: string;\n /** Override the clock — used by tests for deterministic `lastUpdated`. */\n now?: () => Date;\n}\n\nexport interface UserSwitchTenantWorkspaceResult {\n id: string;\n resource: Record<string, unknown>;\n meta: { lastUpdated: string; versionId: string };\n}\n\n/**\n * Update `currentTenant` and `currentWorkspace` on the User resource for the\n * caller authenticated by the given Cognito `sub`. All other fields on the\n * User are preserved.\n *\n * Membership pre-condition uses the ADR-018 adjacency-list user projection\n * (pattern #4, workspace sub-lane). A single base-table Query on\n * `PK = USER#ID#<userId>` with\n * `SK begins_with 'MEMBERSHIP#WORKSPACE#TID#<tenantId>#'`\n * (via {@link membershipListByUserOperation} with `mode: \"workspaceInTenant\"`)\n * confirms the caller has a workspace-level Membership in the requested\n * tenant + workspace pair. No GSI1 fan-out, no scan.\n *\n * Throws:\n * - `ValidationError` when either reference is missing or malformed\n * - `NotFoundError` when no User matches the Cognito subject\n * - `ForbiddenError` when the caller has no Membership in the requested\n * `(tenantId, workspaceId)` pair on their user-partition projection\n *\n * @see https://github.com/codedrifters/openhi/issues/769\n * @see https://github.com/codedrifters/openhi/issues/1020\n * @see ADR-018 § Access Pattern Coverage (pattern #4)\n */\nexport async function switchUserTenantWorkspaceOperation(\n params: UserSwitchTenantWorkspaceParams,\n): Promise<UserSwitchTenantWorkspaceResult> {\n const { cognitoSub, tenantReference, workspaceReference, tableName } = params;\n\n const tenantId = idFromReference(tenantReference, \"Tenant/\");\n if (!tenantId) {\n throw new ValidationError(\n \"tenant.reference must be a 'Tenant/<id>' reference.\",\n );\n }\n const workspaceId = idFromReference(workspaceReference, \"Workspace/\");\n if (!workspaceId) {\n throw new ValidationError(\n \"workspace.reference must be a 'Workspace/<id>' reference.\",\n );\n }\n\n const user = await findUserBySubOperation({\n // findUserBySubOperation does not read context fields; pass a stub.\n context: {\n tenantId: \"\",\n workspaceId: \"\",\n date: \"\",\n actorId: \"\",\n actorName: \"\",\n actorType: \"internal-system\",\n },\n cognitoSub,\n tableName,\n });\n if (!user) {\n throw new NotFoundError(\n \"User not yet provisioned for the authenticated Cognito subject.\",\n );\n }\n\n // ADR-018: single Query on the user partition, narrowed to the workspace\n // sub-lane of the requested tenant. The lane includes `workspaceId` on\n // every row; a row with `workspaceId === <requested>` is sufficient and\n // necessary proof that the caller may switch to that pair.\n const projection = await membershipListByUserOperation({\n userId: user.id,\n mode: \"workspaceInTenant\",\n tenantId,\n tableName,\n });\n const hasMembership = projection.items.some(\n (row) => row.workspaceId === workspaceId,\n );\n if (!hasMembership) {\n throw new ForbiddenError(\n `User is not a member of Workspace/${workspaceId} in Tenant/${tenantId}.`,\n );\n }\n\n const existingResource = parseUserResource(user.resource) ?? {};\n const updatedResource: Record<string, unknown> = {\n ...existingResource,\n resourceType: \"User\",\n id: user.id,\n currentTenant: { reference: `Tenant/${tenantId}` },\n currentWorkspace: { reference: `Workspace/${workspaceId}` },\n };\n\n const lastUpdated = (params.now ? params.now() : new Date()).toISOString();\n const vid = `${Date.now()}`;\n const summary = JSON.stringify(\n extractSummary(updatedResource as FhirResourceLike),\n );\n\n const service = getDynamoControlService(tableName);\n await service.entities.user\n .patch({ id: user.id, sk: SK })\n .set({\n resource: JSON.stringify(updatedResource),\n summary,\n vid,\n lastUpdated,\n })\n .go();\n\n return {\n id: user.id,\n resource: updatedResource,\n meta: { lastUpdated, versionId: vid },\n };\n}\n","import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\n\n/**\n * Filter modes for {@link membershipListByUserOperation}.\n *\n * Maps directly to the ADR-018 sub-lane discriminator in the user-projection\n * SK (`MEMBERSHIP#TENANT#…` vs `MEMBERSHIP#WORKSPACE#…`):\n *\n * - `\"all\"` — `Query(PK = USER#ID#<userId>, SK begins_with 'MEMBERSHIP#')`.\n * Returns both lanes interleaved in raw SK order.\n * - `\"tenant\"` — `SK begins_with 'MEMBERSHIP#TENANT#'`. Pattern #3 only.\n * - `\"workspace\"` — `SK begins_with 'MEMBERSHIP#WORKSPACE#'`. Pattern #4\n * across every tenant.\n * - `\"workspaceInTenant\"` — `SK begins_with 'MEMBERSHIP#WORKSPACE#TID#<tenantId>#'`.\n * Pattern #4 narrowed to one tenant. Requires `tenantId`.\n */\nexport type MembershipListByUserMode =\n | \"all\"\n | \"tenant\"\n | \"workspace\"\n | \"workspaceInTenant\";\n\n/** Inputs accepted by {@link membershipListByUserOperation}. */\nexport interface MembershipListByUserParams {\n readonly userId: string;\n /** Filter mode — see {@link MembershipListByUserMode}. Defaults to `\"all\"`. */\n readonly mode?: MembershipListByUserMode;\n /** Required only when `mode === \"workspaceInTenant\"`. */\n readonly tenantId?: string;\n /** ElectroDB cursor from a prior page. Forwarded to `.go({ cursor })`. */\n readonly cursor?: string | null;\n /** Per-page item limit forwarded to `.go({ limit })`. */\n readonly limit?: number;\n /** Sort order forwarded to `.go({ order })`. Defaults to ElectroDB's `\"asc\"`. */\n readonly order?: \"asc\" | \"desc\";\n /** Optional table-name override; resolved via env when omitted. */\n readonly tableName?: string;\n}\n\n/** One projection-row payload as returned to a consumer. */\nexport interface MembershipUserProjectionEntry {\n readonly userId: string;\n readonly sk: string;\n readonly tenantId: string;\n readonly workspaceId?: string;\n readonly membershipId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedTenantName?: string;\n readonly denormalizedUserName?: string;\n readonly denormalizedWorkspaceName?: string;\n}\n\n/** Page returned by {@link membershipListByUserOperation}. */\nexport interface MembershipListByUserResult {\n readonly items: Array<MembershipUserProjectionEntry>;\n /** ElectroDB cursor for the next page, or `null` when exhausted. */\n readonly cursor: string | null;\n}\n\n/**\n * Compose the SK prefix for a given filter mode. Centralizing the\n * prefix string here keeps the SK grammar (owned by\n * `membership-user-projection.ts`) the single source of truth for the\n * lane discriminators — this function reads them, it does not invent them.\n */\nfunction buildSkPrefix(\n mode: MembershipListByUserMode,\n tenantId: string | undefined,\n): string {\n switch (mode) {\n case \"tenant\":\n return \"MEMBERSHIP#TENANT#\";\n case \"workspace\":\n return \"MEMBERSHIP#WORKSPACE#\";\n case \"workspaceInTenant\":\n // Pattern-#4 SK places `<tenantId>` directly after the\n // `MEMBERSHIP#WORKSPACE#TID#` segment so a `begins_with` filter\n // narrows the workspace lane to a single tenant.\n return `MEMBERSHIP#WORKSPACE#TID#${tenantId}#`;\n case \"all\":\n default:\n return \"MEMBERSHIP#\";\n }\n}\n\n/**\n * List Memberships for a user via the ADR-018 user-partition projection\n * (no GSI hop).\n *\n * Reads `MembershipUserProjectionEntity` rows under `PK = USER#ID#<userId>`\n * with an `SK begins_with` filter selected by `mode`:\n *\n * | Mode | SK begins_with | Covers |\n * |---|---|---|\n * | `all` (default) | `MEMBERSHIP#` | patterns #3 + #4 interleaved |\n * | `tenant` | `MEMBERSHIP#TENANT#` | pattern #3 only |\n * | `workspace` | `MEMBERSHIP#WORKSPACE#` | pattern #4 only, across tenants |\n * | `workspaceInTenant` | `MEMBERSHIP#WORKSPACE#TID#<tenantId>#` | pattern #4 in one tenant |\n *\n * Returns the projection rows verbatim (`summary`, `vid`, `lastUpdated`\n * plus the projection-discriminating fields) — full canonical-resource\n * hydration is opt-in for callers via\n * `MembershipEntity.get({ tenantId, id: membershipId })`. Pagination\n * mirrors ElectroDB's native `.go({ cursor })` shape; the returned\n * `cursor` is opaque to callers.\n *\n * @see ADR-018 § Access Pattern Coverage (patterns #3 and #4)\n * @see .state/adr-018-implementation-guide.md § 1 (SK grammar)\n */\nexport async function membershipListByUserOperation(\n params: MembershipListByUserParams,\n): Promise<MembershipListByUserResult> {\n const {\n userId,\n mode = \"all\",\n tenantId,\n cursor = null,\n limit,\n order,\n tableName,\n } = params;\n\n if (mode === \"workspaceInTenant\" && !tenantId) {\n throw new Error(\n 'membershipListByUserOperation: tenantId is required when mode === \"workspaceInTenant\"',\n );\n }\n\n const service = getDynamoControlService(tableName);\n const skPrefix = buildSkPrefix(mode, tenantId);\n\n const goOptions: {\n cursor?: string | null;\n limit?: number;\n order?: \"asc\" | \"desc\";\n } = {\n cursor,\n };\n if (limit !== undefined) {\n goOptions.limit = limit;\n }\n if (order !== undefined) {\n goOptions.order = order;\n }\n\n const result = await service.entities.membershipUserProjection.query\n .record({ userId })\n .begins({ sk: skPrefix })\n .go(goOptions);\n\n const items: Array<MembershipUserProjectionEntry> = (result.data ?? []).map(\n (row) => ({\n userId: row.userId,\n sk: row.sk,\n tenantId: row.tenantId,\n workspaceId: row.workspaceId,\n membershipId: row.membershipId,\n summary: row.summary,\n vid: row.vid,\n lastUpdated: row.lastUpdated,\n denormalizedTenantName: row.denormalizedTenantName,\n denormalizedUserName: row.denormalizedUserName,\n denormalizedWorkspaceName: row.denormalizedWorkspaceName,\n }),\n );\n\n return { items, cursor: result.cursor ?? null };\n}\n","import { extractSummary, type FhirResourceLike } from \"@openhi/types\";\nimport { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { NotFoundError } from \"../../../errors\";\nimport { OpenHiContext } from \"../../../openhi-context\";\n\nexport interface UserUpdateParams {\n context: OpenHiContext;\n id: string;\n body: { resource?: Record<string, unknown> | string };\n tableName?: string;\n}\n\nexport interface UserUpdateResult {\n id: string;\n resource: { resourceType: string; id: string; [key: string]: unknown };\n meta: { lastUpdated: string; versionId: string };\n}\n\nexport async function updateUserOperation(\n params: UserUpdateParams,\n): Promise<UserUpdateResult> {\n const { context, id, body, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n const existing = await service.entities.user.get({ id, sk: \"CURRENT\" }).go();\n if (!existing.data) {\n throw new NotFoundError(`User not found: ${id}`);\n }\n\n const parsedResource =\n typeof body.resource === \"string\"\n ? (JSON.parse(body.resource) as Record<string, unknown>)\n : (body.resource ?? {});\n\n const lastUpdated = context.date ?? new Date().toISOString();\n const vid = `${Date.now()}`;\n\n const resource = { resourceType: \"User\", id, ...parsedResource };\n const summary = JSON.stringify(extractSummary(resource as FhirResourceLike));\n\n await service.entities.user\n .put({\n id,\n resource: JSON.stringify(resource),\n summary,\n vid,\n lastUpdated,\n })\n .go();\n\n return {\n id,\n resource,\n meta: { lastUpdated, versionId: vid },\n };\n}\n","import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { OpenHiContext } from \"../../../openhi-context\";\n\nexport interface UserDeleteParams {\n context: OpenHiContext;\n id: string;\n tableName?: string;\n}\n\nexport async function deleteUserOperation(\n params: UserDeleteParams,\n): Promise<void> {\n const { id, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n await service.entities.user.delete({ id, sk: \"CURRENT\" }).go();\n}\n"],"mappings":"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","names":["extractSummary","SK","extractSummary","extractSummary","extractSummary"]}