@openhi/constructs 0.0.168 → 0.0.170
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/lib/{chunk-DWSWCUZR.mjs → chunk-6HGSR3TG.mjs} +2 -2
- package/lib/chunk-APVVG7BO.mjs +61 -0
- package/lib/chunk-APVVG7BO.mjs.map +1 -0
- package/lib/{chunk-ZODGX37H.mjs → chunk-E2OWEBBH.mjs} +3 -3
- package/lib/{chunk-GJTPXJKD.mjs → chunk-EBB4RNUG.mjs} +2 -2
- package/lib/{chunk-O5VQWB6U.mjs → chunk-FDBBTNCI.mjs} +5 -61
- package/lib/chunk-FDBBTNCI.mjs.map +1 -0
- package/lib/{chunk-P3CTZWC2.mjs → chunk-GG2WD6TA.mjs} +2 -2
- package/lib/{chunk-Q64MOYJ7.mjs → chunk-JUSVETWK.mjs} +3 -3
- package/lib/{chunk-KA3OMP3X.mjs → chunk-USNOOCSZ.mjs} +9 -3
- package/lib/chunk-USNOOCSZ.mjs.map +1 -0
- package/lib/{chunk-2O3CXY2C.mjs → chunk-XJ5SRUGN.mjs} +2 -2
- package/lib/{chunk-2O3CXY2C.mjs.map → chunk-XJ5SRUGN.mjs.map} +1 -1
- package/lib/{chunk-P3NFCKTZ.mjs → chunk-XNUCKVSE.mjs} +2 -2
- package/lib/{chunk-WFTDH2NM.mjs → chunk-Y4RGUAM2.mjs} +2 -2
- package/lib/{chunk-XHG4SODS.mjs → chunk-Z4PZSLYY.mjs} +2 -2
- package/lib/counter-reconciliation.handler.mjs +5 -4
- package/lib/counter-reconciliation.handler.mjs.map +1 -1
- package/lib/data-store-postgres-replication.handler.js +42 -4
- package/lib/data-store-postgres-replication.handler.js.map +1 -1
- package/lib/data-store-postgres-replication.handler.mjs +9 -4
- package/lib/data-store-postgres-replication.handler.mjs.map +1 -1
- package/lib/firehose-archive-transform.handler.d.mts +2 -1
- package/lib/firehose-archive-transform.handler.d.ts +2 -1
- package/lib/firehose-archive-transform.handler.js +42 -2
- package/lib/firehose-archive-transform.handler.js.map +1 -1
- package/lib/firehose-archive-transform.handler.mjs +4 -1
- package/lib/index.js +21 -2
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +26 -6
- package/lib/index.mjs.map +1 -1
- package/lib/pre-token-generation.handler.mjs +6 -5
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +5 -4
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rest-api-lambda.handler.js +1 -1
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +14 -12
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.mjs +5 -4
- package/package.json +10 -10
- package/lib/chunk-KA3OMP3X.mjs.map +0 -1
- package/lib/chunk-O5VQWB6U.mjs.map +0 -1
- /package/lib/{chunk-DWSWCUZR.mjs.map → chunk-6HGSR3TG.mjs.map} +0 -0
- /package/lib/{chunk-ZODGX37H.mjs.map → chunk-E2OWEBBH.mjs.map} +0 -0
- /package/lib/{chunk-GJTPXJKD.mjs.map → chunk-EBB4RNUG.mjs.map} +0 -0
- /package/lib/{chunk-P3CTZWC2.mjs.map → chunk-GG2WD6TA.mjs.map} +0 -0
- /package/lib/{chunk-Q64MOYJ7.mjs.map → chunk-JUSVETWK.mjs.map} +0 -0
- /package/lib/{chunk-P3NFCKTZ.mjs.map → chunk-XNUCKVSE.mjs.map} +0 -0
- /package/lib/{chunk-WFTDH2NM.mjs.map → chunk-Y4RGUAM2.mjs.map} +0 -0
- /package/lib/{chunk-XHG4SODS.mjs.map → chunk-Z4PZSLYY.mjs.map} +0 -0
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listPractitionerRolesOperation,
|
|
3
3
|
listRoleAssignmentsOperation
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GG2WD6TA.mjs";
|
|
5
5
|
import {
|
|
6
6
|
listMembershipsOperation
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EBB4RNUG.mjs";
|
|
8
8
|
import {
|
|
9
9
|
findUserBySubOperation,
|
|
10
10
|
idFromReference,
|
|
11
11
|
parseUserResource
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-Y4RGUAM2.mjs";
|
|
13
|
+
import "./chunk-6HGSR3TG.mjs";
|
|
14
14
|
import "./chunk-6BB4CRSS.mjs";
|
|
15
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-FDBBTNCI.mjs";
|
|
16
|
+
import "./chunk-APVVG7BO.mjs";
|
|
16
17
|
import "./chunk-FYHBHHWK.mjs";
|
|
17
18
|
import "./chunk-EUIP2U5F.mjs";
|
|
18
19
|
import "./chunk-TRY7JGWO.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/cognito/pre-token-generation.handler.ts"],"sourcesContent":["import {\n getLinkedDataIdentity,\n type HumanName,\n organizationRoleCodeSchema,\n type OrganizationRoleCode,\n type PlatformRoleCode,\n platformRoleCodeSchema,\n type PractitionerRole,\n} from \"@openhi/types\";\nimport type {\n Context,\n PreTokenGenerationTriggerEvent,\n PreTokenGenerationTriggerHandler,\n} from \"aws-lambda\";\nimport type { OpenHiContext } from \"../../data/openhi-context\";\nimport { listMembershipsOperation } from \"../../data/operations/control/membership/membership-list-operation\";\nimport { listRoleAssignmentsOperation } from \"../../data/operations/control/roleassignment/roleassignment-list-operation\";\nimport {\n findUserBySubOperation,\n parseUserResource,\n type UserResource,\n} from \"../../data/operations/control/user\";\nimport { listPractitionerRolesOperation } from \"../../data/operations/data/practitionerrole/practitionerrole-list-operation\";\nimport { idFromReference } from \"../../data/operations/fhir-reference\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/pre-token-generation-lambda.md\n *\n * Cognito Pre Token Generation trigger (V2_0).\n *\n * Resolves the OpenHI User by Cognito `sub` via GSI2 and injects `ohi_tid`,\n * `ohi_wid`, `ohi_uid`, `ohi_uname` into both the ID token and the access\n * token (ADR 2026-03-17-01 §3, ADR-014).\n *\n * Absent-claims behavior (ADR-014): if the User cannot be resolved (legacy /\n * unprovisioned account) or the resolved User is missing `currentTenant` /\n * `currentWorkspace`, the Lambda stamps placeholder `ohi_*` claims rather than\n * emitting the token without any claims. Token issuance itself must never\n * fail: any DynamoDB or unexpected error is logged and placeholder claims are\n * stamped so the failure surfaces visibly downstream instead of producing a\n * silent 403.\n *\n * No fallback to Membership: #770 populates `currentTenant`/`currentWorkspace`\n * at sign-up, so a missing pointer indicates legacy/corrupt data that is\n * cheaper to surface (via the placeholder-claims path) than to repair on the\n * hot token path. Repair belongs in a separate backfill, not here — keeping\n * this Lambda's IAM grant to read-only on the table.\n */\n\nconst REFERENCE_TYPES = {\n Tenant: \"Tenant/\",\n Workspace: \"Workspace/\",\n} as const;\n\nfunction displayNameFor(user: UserResource): string | undefined {\n const names = user.name as Array<HumanName> | undefined;\n const first = names?.[0];\n return first?.text ?? first?.family ?? undefined;\n}\n\ninterface ResolvedClaims {\n ohi_tid: string;\n ohi_wid: string;\n ohi_uid: string;\n ohi_uname: string;\n /**\n * Flat, deduplicated list of organization-role codes for the user in the\n * current workspace. Absent when no Membership / no linked-data-identity\n * exists; present and possibly empty when source data exists but yields\n * no PractitionerRole codes.\n */\n ohi_organization_roles?: ReadonlyArray<OrganizationRoleCode>;\n /**\n * Flat, deduplicated list of platform-role codes for the user that apply\n * to the current workspace scope (tenant-scoped assignments + assignments\n * scoped to this workspace). Absent when no RoleAssignment exists for the\n * user; present and possibly empty when assignments exist but yield no\n * recognized codes.\n */\n ohi_platform_roles?: ReadonlyArray<PlatformRoleCode>;\n}\n\n// Pre Token Generation runs before tenant/workspace claims exist — the User\n// lookup is the operation we use to discover them. The data operation requires\n// a context object for convention, but findUserBySubOperation does not read\n// any of its fields, so a synthetic placeholder is correct here.\nconst lookupContext: OpenHiContext = {\n tenantId: \"\",\n workspaceId: \"\",\n date: \"\",\n actorId: \"\",\n actorName: \"\",\n actorType: \"internal-system\",\n};\n\nasync function resolveClaims(\n cognitoSub: string,\n): Promise<ResolvedClaims | undefined> {\n const user = await findUserBySubOperation({\n context: lookupContext,\n cognitoSub,\n });\n if (!user) {\n console.warn(\n `PreTokenGeneration: no User found for cognitoSub; emitting token without OpenHI claims (sub=${cognitoSub})`,\n );\n return undefined;\n }\n const parsed = parseUserResource(user.resource);\n if (!parsed) {\n console.warn(\n `PreTokenGeneration: User resource JSON could not be parsed (sub=${cognitoSub}, id=${user.id})`,\n );\n return undefined;\n }\n\n const tenantId = idFromReference(\n parsed.currentTenant?.reference,\n REFERENCE_TYPES.Tenant,\n );\n const workspaceId = idFromReference(\n parsed.currentWorkspace?.reference,\n REFERENCE_TYPES.Workspace,\n );\n const displayName = displayNameFor(parsed);\n\n if (!tenantId || !workspaceId || !displayName) {\n console.warn(\n `PreTokenGeneration: resolved User missing currentTenant/currentWorkspace/name; emitting token without OpenHI claims (sub=${cognitoSub}, id=${user.id})`,\n );\n return undefined;\n }\n\n const [ohi_organization_roles, ohi_platform_roles] = await Promise.all([\n resolveOrganizationRoles(tenantId, workspaceId, user.id),\n resolvePlatformRoles(tenantId, workspaceId, user.id),\n ]);\n\n return {\n ohi_tid: tenantId,\n ohi_wid: workspaceId,\n ohi_uid: user.id,\n ohi_uname: displayName,\n ...(ohi_organization_roles !== undefined ? { ohi_organization_roles } : {}),\n ...(ohi_platform_roles !== undefined ? { ohi_platform_roles } : {}),\n };\n}\n\n/**\n * Read `PractitionerRole` resources for the user in the current workspace and\n * return the deduplicated `organization-role` codes. Returns `undefined`\n * (claim absent) when the user has no Membership in the workspace or the\n * Membership lacks a `linked-data-identity` extension. Returns an empty array\n * when the Membership is linked but no matching PractitionerRoles exist.\n *\n * Read path per ADR-019 §1.2 — invariant across Phase 1 and Phase 2 (Phase 2\n * enriches PractitionerRole fields but does not change the source).\n */\nasync function resolveOrganizationRoles(\n tenantId: string,\n workspaceId: string,\n userId: string,\n): Promise<ReadonlyArray<OrganizationRoleCode> | undefined> {\n const claimContext: OpenHiContext = {\n ...lookupContext,\n tenantId,\n workspaceId,\n };\n\n const memberships = await listMembershipsOperation({\n context: claimContext,\n mode: \"full\",\n });\n const userRef = `User/${userId}`;\n const workspaceRef = `Workspace/${workspaceId}`;\n const matching = memberships.entries.find((entry) => {\n const r = entry.resource as {\n user?: { reference?: string };\n workspace?: { reference?: string };\n };\n return (\n r.user?.reference === userRef && r.workspace?.reference === workspaceRef\n );\n });\n if (matching === undefined) {\n return undefined;\n }\n\n const linked = getLinkedDataIdentity(\n matching.resource as { extension?: Array<{ url: string }> },\n );\n if (linked?.reference === undefined) {\n return undefined;\n }\n\n const practitionerRoleList = await listPractitionerRolesOperation({\n context: claimContext,\n mode: \"full\",\n });\n const organizationRef = `Organization/${workspaceId}`;\n const codes = new Set<OrganizationRoleCode>();\n for (const entry of practitionerRoleList.entries) {\n const role: PractitionerRole = entry.resource;\n if (role.practitioner?.reference !== linked.reference) continue;\n if (role.organization?.reference !== organizationRef) continue;\n const codings = role.code?.flatMap((cc) => cc.coding ?? []) ?? [];\n for (const c of codings) {\n if (typeof c.code !== \"string\") continue;\n const parsed = organizationRoleCodeSchema.safeParse(c.code);\n if (parsed.success) {\n codes.add(parsed.data);\n }\n }\n }\n return Array.from(codes);\n}\n\n/**\n * Read `RoleAssignment` resources for the user that apply to the current\n * workspace scope and return the deduplicated platform-role codes. Tenant-\n * scoped assignments (no `workspace` field) and workspace-scoped assignments\n * matching the current workspace both contribute, per ADR 2026-03-13-02 §2 / §5.\n *\n * Returns `undefined` (claim absent) when the user has no RoleAssignments at\n * all. Returns an empty array when assignments exist but yield no recognized\n * platform-role codes.\n */\nasync function resolvePlatformRoles(\n tenantId: string,\n workspaceId: string,\n userId: string,\n): Promise<ReadonlyArray<PlatformRoleCode> | undefined> {\n const claimContext: OpenHiContext = {\n ...lookupContext,\n tenantId,\n workspaceId,\n };\n\n const assignments = await listRoleAssignmentsOperation({\n context: claimContext,\n mode: \"full\",\n });\n const userRef = `User/${userId}`;\n const workspaceRef = `Workspace/${workspaceId}`;\n\n const userAssignments = assignments.entries.filter((entry) => {\n const r = entry.resource as {\n user?: { reference?: string };\n workspace?: { reference?: string };\n };\n if (r.user?.reference !== userRef) return false;\n const wsRef = r.workspace?.reference;\n return wsRef === undefined || wsRef === workspaceRef;\n });\n if (userAssignments.length === 0) {\n return undefined;\n }\n\n const codes = new Set<PlatformRoleCode>();\n for (const entry of userAssignments) {\n const r = entry.resource as { role?: { reference?: string } };\n const ref = r.role?.reference;\n if (typeof ref !== \"string\") continue;\n const roleId = idFromReference(ref, \"Role/\");\n if (roleId === undefined) continue;\n const candidate = roleId.startsWith(\"role-\")\n ? roleId.slice(\"role-\".length)\n : roleId;\n const parsed = platformRoleCodeSchema.safeParse(candidate);\n if (parsed.success) {\n codes.add(parsed.data);\n }\n }\n return Array.from(codes);\n}\n\n/**\n * Placeholder claim set stamped when the User cannot be resolved or an\n * unexpected error is thrown inside `resolveClaims`. Surfacing these values\n * in downstream API responses is preferable to emitting a token with no\n * `ohi_*` claims (which `openHiContextMiddleware` rejects with a silent 403).\n */\nfunction placeholderClaims(): ResolvedClaims {\n return {\n ohi_tid: \"placeholder-tenant-id\",\n ohi_wid: \"placeholder-workspace-id\",\n ohi_uid: \"placeholder-user-id\",\n ohi_uname: \"placeholder\",\n };\n}\n\nfunction stampClaims(\n event: PreTokenGenerationTriggerEvent,\n claims: ResolvedClaims,\n): void {\n if (!event.response) {\n (event as { response: Record<string, unknown> }).response = {};\n }\n const response = event.response as Record<string, unknown>;\n response.claimsAndScopeOverrideDetails = {\n accessTokenGeneration: {\n claimsToAddOrOverride: { ...claims },\n },\n idTokenGeneration: {\n claimsToAddOrOverride: { ...claims },\n },\n };\n}\n\nexport const handler: PreTokenGenerationTriggerHandler = async (\n event: PreTokenGenerationTriggerEvent,\n _context: Context,\n): Promise<PreTokenGenerationTriggerEvent> => {\n try {\n const cognitoSub = event.request?.userAttributes?.sub;\n if (!cognitoSub) {\n console.warn(\n \"PreTokenGeneration: event has no Cognito sub; returning event unchanged\",\n );\n return event;\n }\n\n const resolved = await resolveClaims(cognitoSub);\n\n /**\n * temporarily provide safe fallback during transition period: when the\n * User cannot be resolved (or is missing currentTenant/currentWorkspace),\n * stamp placeholder claims so downstream API responses surface the\n * failure visibly instead of producing a silent 403.\n */\n stampClaims(event, resolved ?? placeholderClaims());\n } catch (err) {\n // Token issuance must never fail: log and stamp placeholder claims so the\n // failure surfaces in downstream API responses (visible \"placeholder-*\"\n // values) instead of producing a silent 403 from openHiContextMiddleware.\n console.warn(\n \"PreTokenGeneration: unexpected error; stamping placeholder claims\",\n err,\n );\n try {\n stampClaims(event, placeholderClaims());\n } catch (stampErr) {\n // If even stamping fails, return the event unchanged rather than\n // throwing — token issuance must still succeed.\n console.warn(\n \"PreTokenGeneration: failed to stamp placeholder claims after error; returning event unchanged\",\n stampErr,\n );\n }\n }\n return event;\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/components/cognito/pre-token-generation.handler.ts"],"sourcesContent":["import {\n getLinkedDataIdentity,\n type HumanName,\n organizationRoleCodeSchema,\n type OrganizationRoleCode,\n type PlatformRoleCode,\n platformRoleCodeSchema,\n type PractitionerRole,\n} from \"@openhi/types\";\nimport type {\n Context,\n PreTokenGenerationTriggerEvent,\n PreTokenGenerationTriggerHandler,\n} from \"aws-lambda\";\nimport type { OpenHiContext } from \"../../data/openhi-context\";\nimport { listMembershipsOperation } from \"../../data/operations/control/membership/membership-list-operation\";\nimport { listRoleAssignmentsOperation } from \"../../data/operations/control/roleassignment/roleassignment-list-operation\";\nimport {\n findUserBySubOperation,\n parseUserResource,\n type UserResource,\n} from \"../../data/operations/control/user\";\nimport { listPractitionerRolesOperation } from \"../../data/operations/data/practitionerrole/practitionerrole-list-operation\";\nimport { idFromReference } from \"../../data/operations/fhir-reference\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/pre-token-generation-lambda.md\n *\n * Cognito Pre Token Generation trigger (V2_0).\n *\n * Resolves the OpenHI User by Cognito `sub` via GSI2 and injects `ohi_tid`,\n * `ohi_wid`, `ohi_uid`, `ohi_uname` into both the ID token and the access\n * token (ADR 2026-03-17-01 §3, ADR-014).\n *\n * Absent-claims behavior (ADR-014): if the User cannot be resolved (legacy /\n * unprovisioned account) or the resolved User is missing `currentTenant` /\n * `currentWorkspace`, the Lambda stamps placeholder `ohi_*` claims rather than\n * emitting the token without any claims. Token issuance itself must never\n * fail: any DynamoDB or unexpected error is logged and placeholder claims are\n * stamped so the failure surfaces visibly downstream instead of producing a\n * silent 403.\n *\n * No fallback to Membership: #770 populates `currentTenant`/`currentWorkspace`\n * at sign-up, so a missing pointer indicates legacy/corrupt data that is\n * cheaper to surface (via the placeholder-claims path) than to repair on the\n * hot token path. Repair belongs in a separate backfill, not here — keeping\n * this Lambda's IAM grant to read-only on the table.\n */\n\nconst REFERENCE_TYPES = {\n Tenant: \"Tenant/\",\n Workspace: \"Workspace/\",\n} as const;\n\nfunction displayNameFor(user: UserResource): string | undefined {\n const names = user.name as Array<HumanName> | undefined;\n const first = names?.[0];\n return first?.text ?? first?.family ?? undefined;\n}\n\ninterface ResolvedClaims {\n ohi_tid: string;\n ohi_wid: string;\n ohi_uid: string;\n ohi_uname: string;\n /**\n * Flat, deduplicated list of organization-role codes for the user in the\n * current workspace. Absent when no Membership / no linked-data-identity\n * exists; present and possibly empty when source data exists but yields\n * no PractitionerRole codes.\n */\n ohi_organization_roles?: ReadonlyArray<OrganizationRoleCode>;\n /**\n * Flat, deduplicated list of platform-role codes for the user that apply\n * to the current workspace scope (tenant-scoped assignments + assignments\n * scoped to this workspace). Absent when no RoleAssignment exists for the\n * user; present and possibly empty when assignments exist but yield no\n * recognized codes.\n */\n ohi_platform_roles?: ReadonlyArray<PlatformRoleCode>;\n}\n\n// Pre Token Generation runs before tenant/workspace claims exist — the User\n// lookup is the operation we use to discover them. The data operation requires\n// a context object for convention, but findUserBySubOperation does not read\n// any of its fields, so a synthetic placeholder is correct here.\nconst lookupContext: OpenHiContext = {\n tenantId: \"\",\n workspaceId: \"\",\n date: \"\",\n actorId: \"\",\n actorName: \"\",\n actorType: \"internal-system\",\n};\n\nasync function resolveClaims(\n cognitoSub: string,\n): Promise<ResolvedClaims | undefined> {\n const user = await findUserBySubOperation({\n context: lookupContext,\n cognitoSub,\n });\n if (!user) {\n console.warn(\n `PreTokenGeneration: no User found for cognitoSub; emitting token without OpenHI claims (sub=${cognitoSub})`,\n );\n return undefined;\n }\n const parsed = parseUserResource(user.resource);\n if (!parsed) {\n console.warn(\n `PreTokenGeneration: User resource JSON could not be parsed (sub=${cognitoSub}, id=${user.id})`,\n );\n return undefined;\n }\n\n const tenantId = idFromReference(\n parsed.currentTenant?.reference,\n REFERENCE_TYPES.Tenant,\n );\n const workspaceId = idFromReference(\n parsed.currentWorkspace?.reference,\n REFERENCE_TYPES.Workspace,\n );\n const displayName = displayNameFor(parsed);\n\n if (!tenantId || !workspaceId || !displayName) {\n console.warn(\n `PreTokenGeneration: resolved User missing currentTenant/currentWorkspace/name; emitting token without OpenHI claims (sub=${cognitoSub}, id=${user.id})`,\n );\n return undefined;\n }\n\n const [ohi_organization_roles, ohi_platform_roles] = await Promise.all([\n resolveOrganizationRoles(tenantId, workspaceId, user.id),\n resolvePlatformRoles(tenantId, workspaceId, user.id),\n ]);\n\n return {\n ohi_tid: tenantId,\n ohi_wid: workspaceId,\n ohi_uid: user.id,\n ohi_uname: displayName,\n ...(ohi_organization_roles !== undefined ? { ohi_organization_roles } : {}),\n ...(ohi_platform_roles !== undefined ? { ohi_platform_roles } : {}),\n };\n}\n\n/**\n * Read `PractitionerRole` resources for the user in the current workspace and\n * return the deduplicated `organization-role` codes. Returns `undefined`\n * (claim absent) when the user has no Membership in the workspace or the\n * Membership lacks a `linked-data-identity` extension. Returns an empty array\n * when the Membership is linked but no matching PractitionerRoles exist.\n *\n * Read path per ADR-019 §1.2 — invariant across Phase 1 and Phase 2 (Phase 2\n * enriches PractitionerRole fields but does not change the source).\n */\nasync function resolveOrganizationRoles(\n tenantId: string,\n workspaceId: string,\n userId: string,\n): Promise<ReadonlyArray<OrganizationRoleCode> | undefined> {\n const claimContext: OpenHiContext = {\n ...lookupContext,\n tenantId,\n workspaceId,\n };\n\n const memberships = await listMembershipsOperation({\n context: claimContext,\n mode: \"full\",\n });\n const userRef = `User/${userId}`;\n const workspaceRef = `Workspace/${workspaceId}`;\n const matching = memberships.entries.find((entry) => {\n const r = entry.resource as {\n user?: { reference?: string };\n workspace?: { reference?: string };\n };\n return (\n r.user?.reference === userRef && r.workspace?.reference === workspaceRef\n );\n });\n if (matching === undefined) {\n return undefined;\n }\n\n const linked = getLinkedDataIdentity(\n matching.resource as { extension?: Array<{ url: string }> },\n );\n if (linked?.reference === undefined) {\n return undefined;\n }\n\n const practitionerRoleList = await listPractitionerRolesOperation({\n context: claimContext,\n mode: \"full\",\n });\n const organizationRef = `Organization/${workspaceId}`;\n const codes = new Set<OrganizationRoleCode>();\n for (const entry of practitionerRoleList.entries) {\n const role: PractitionerRole = entry.resource;\n if (role.practitioner?.reference !== linked.reference) continue;\n if (role.organization?.reference !== organizationRef) continue;\n const codings = role.code?.flatMap((cc) => cc.coding ?? []) ?? [];\n for (const c of codings) {\n if (typeof c.code !== \"string\") continue;\n const parsed = organizationRoleCodeSchema.safeParse(c.code);\n if (parsed.success) {\n codes.add(parsed.data);\n }\n }\n }\n return Array.from(codes);\n}\n\n/**\n * Read `RoleAssignment` resources for the user that apply to the current\n * workspace scope and return the deduplicated platform-role codes. Tenant-\n * scoped assignments (no `workspace` field) and workspace-scoped assignments\n * matching the current workspace both contribute, per ADR 2026-03-13-02 §2 / §5.\n *\n * Returns `undefined` (claim absent) when the user has no RoleAssignments at\n * all. Returns an empty array when assignments exist but yield no recognized\n * platform-role codes.\n */\nasync function resolvePlatformRoles(\n tenantId: string,\n workspaceId: string,\n userId: string,\n): Promise<ReadonlyArray<PlatformRoleCode> | undefined> {\n const claimContext: OpenHiContext = {\n ...lookupContext,\n tenantId,\n workspaceId,\n };\n\n const assignments = await listRoleAssignmentsOperation({\n context: claimContext,\n mode: \"full\",\n });\n const userRef = `User/${userId}`;\n const workspaceRef = `Workspace/${workspaceId}`;\n\n const userAssignments = assignments.entries.filter((entry) => {\n const r = entry.resource as {\n user?: { reference?: string };\n workspace?: { reference?: string };\n };\n if (r.user?.reference !== userRef) return false;\n const wsRef = r.workspace?.reference;\n return wsRef === undefined || wsRef === workspaceRef;\n });\n if (userAssignments.length === 0) {\n return undefined;\n }\n\n const codes = new Set<PlatformRoleCode>();\n for (const entry of userAssignments) {\n const r = entry.resource as { role?: { reference?: string } };\n const ref = r.role?.reference;\n if (typeof ref !== \"string\") continue;\n const roleId = idFromReference(ref, \"Role/\");\n if (roleId === undefined) continue;\n const candidate = roleId.startsWith(\"role-\")\n ? roleId.slice(\"role-\".length)\n : roleId;\n const parsed = platformRoleCodeSchema.safeParse(candidate);\n if (parsed.success) {\n codes.add(parsed.data);\n }\n }\n return Array.from(codes);\n}\n\n/**\n * Placeholder claim set stamped when the User cannot be resolved or an\n * unexpected error is thrown inside `resolveClaims`. Surfacing these values\n * in downstream API responses is preferable to emitting a token with no\n * `ohi_*` claims (which `openHiContextMiddleware` rejects with a silent 403).\n */\nfunction placeholderClaims(): ResolvedClaims {\n return {\n ohi_tid: \"placeholder-tenant-id\",\n ohi_wid: \"placeholder-workspace-id\",\n ohi_uid: \"placeholder-user-id\",\n ohi_uname: \"placeholder\",\n };\n}\n\nfunction stampClaims(\n event: PreTokenGenerationTriggerEvent,\n claims: ResolvedClaims,\n): void {\n if (!event.response) {\n (event as { response: Record<string, unknown> }).response = {};\n }\n const response = event.response as Record<string, unknown>;\n response.claimsAndScopeOverrideDetails = {\n accessTokenGeneration: {\n claimsToAddOrOverride: { ...claims },\n },\n idTokenGeneration: {\n claimsToAddOrOverride: { ...claims },\n },\n };\n}\n\nexport const handler: PreTokenGenerationTriggerHandler = async (\n event: PreTokenGenerationTriggerEvent,\n _context: Context,\n): Promise<PreTokenGenerationTriggerEvent> => {\n try {\n const cognitoSub = event.request?.userAttributes?.sub;\n if (!cognitoSub) {\n console.warn(\n \"PreTokenGeneration: event has no Cognito sub; returning event unchanged\",\n );\n return event;\n }\n\n const resolved = await resolveClaims(cognitoSub);\n\n /**\n * temporarily provide safe fallback during transition period: when the\n * User cannot be resolved (or is missing currentTenant/currentWorkspace),\n * stamp placeholder claims so downstream API responses surface the\n * failure visibly instead of producing a silent 403.\n */\n stampClaims(event, resolved ?? placeholderClaims());\n } catch (err) {\n // Token issuance must never fail: log and stamp placeholder claims so the\n // failure surfaces in downstream API responses (visible \"placeholder-*\"\n // values) instead of producing a silent 403 from openHiContextMiddleware.\n console.warn(\n \"PreTokenGeneration: unexpected error; stamping placeholder claims\",\n err,\n );\n try {\n stampClaims(event, placeholderClaims());\n } catch (stampErr) {\n // If even stamping fails, return the event unchanged rather than\n // throwing — token issuance must still succeed.\n console.warn(\n \"PreTokenGeneration: failed to stamp placeholder claims after error; returning event unchanged\",\n stampErr,\n );\n }\n }\n return event;\n};\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createRoleAssignmentOperation,
|
|
4
4
|
createTenantOperation,
|
|
5
5
|
createWorkspaceOperation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Z4PZSLYY.mjs";
|
|
7
7
|
import "./chunk-BUAYVN3C.mjs";
|
|
8
8
|
import "./chunk-5S6VFBLT.mjs";
|
|
9
9
|
import "./chunk-I6LUPJUY.mjs";
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
findUserBySubOperation,
|
|
13
13
|
idFromReference,
|
|
14
14
|
parseUserResource
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-Y4RGUAM2.mjs";
|
|
16
|
+
import "./chunk-6HGSR3TG.mjs";
|
|
17
17
|
import "./chunk-6BB4CRSS.mjs";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-FDBBTNCI.mjs";
|
|
19
|
+
import "./chunk-APVVG7BO.mjs";
|
|
19
20
|
import "./chunk-FYHBHHWK.mjs";
|
|
20
21
|
import {
|
|
21
22
|
getDynamoControlService
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/workflows/control-plane/user-onboarding/provision-default-workspace.handler.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { extractSummary, type FhirResourceLike } from \"@openhi/types\";\nimport type { EventBridgeEvent } from \"aws-lambda\";\nimport {\n PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,\n type ProvisionDefaultWorkspaceRequestedDetail,\n} from \"./events\";\nimport { getDynamoControlService } from \"../../../data/dynamo/dynamo-control-service\";\nimport type { OpenHiContext } from \"../../../data/openhi-context\";\nimport { createMembershipOperation } from \"../../../data/operations/control/membership/membership-create-operation\";\nimport { createRoleAssignmentOperation } from \"../../../data/operations/control/roleassignment/roleassignment-create-operation\";\nimport { createTenantOperation } from \"../../../data/operations/control/tenant/tenant-create-operation\";\nimport {\n findUserBySubOperation,\n parseUserResource,\n} from \"../../../data/operations/control/user\";\nimport { createWorkspaceOperation } from \"../../../data/operations/control/workspace/workspace-create-operation\";\nimport { idFromReference } from \"../../../data/operations/fhir-reference\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/user-onboarding/provision-default-workspace.handler.md\n *\n * EventBridge workflow handler that provisions the default control-plane\n * records for a newly confirmed Cognito user.\n */\ntype ProvisionDefaultWorkspaceEvent = EventBridgeEvent<\n typeof PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,\n ProvisionDefaultWorkspaceRequestedDetail\n>;\n\nconst CURRENT_SK = \"CURRENT\";\nconst VID = \"1\";\n\n// Store the same compact summary shape used by control-plane entities.\nconst summaryFor = (resource: Record<string, unknown>): string => {\n return JSON.stringify(extractSummary(resource as FhirResourceLike));\n};\n\n// Make onboarding writes replay-safe by deriving deterministic record ids.\nconst stableOnboardingId = (kind: string, cognitoSub: string): string => {\n return createHash(\"sha256\")\n .update(kind)\n .update(\"\\0\")\n .update(cognitoSub)\n .digest(\"hex\")\n .slice(0, 26)\n .toUpperCase();\n};\n\nexport const handler = async (\n event: ProvisionDefaultWorkspaceEvent,\n): Promise<void> => {\n // Events without a Cognito subject cannot be tied to a stable User.\n const detail = event.detail;\n if (!detail?.cognitoSub) {\n console.warn(\n \"ProvisionDefaultWorkspace: event missing cognitoSub; skipping\",\n );\n return;\n }\n\n // If onboarding already completed, leave existing records untouched.\n // The lookup runs before tenant/workspace exist, so use a synthetic\n // placeholder context — findUserBySubOperation does not read its fields.\n const service = getDynamoControlService();\n const existingUser = await findUserBySubOperation({\n context: {\n tenantId: \"\",\n workspaceId: \"\",\n date: \"\",\n actorId: \"\",\n actorName: \"\",\n actorType: \"internal-system\",\n },\n cognitoSub: detail.cognitoSub,\n });\n const existingResource = existingUser\n ? parseUserResource(existingUser.resource)\n : undefined;\n const existingTenantId = idFromReference(\n existingResource?.currentTenant?.reference,\n \"Tenant/\",\n );\n const existingWorkspaceId = idFromReference(\n existingResource?.currentWorkspace?.reference,\n \"Workspace/\",\n );\n\n if (existingUser && existingTenantId && existingWorkspaceId) {\n return;\n }\n\n const displayName =\n detail.displayName ||\n detail.email ||\n event.resources?.[0] ||\n detail.cognitoSub;\n const userId =\n existingUser?.id ??\n detail.userId ??\n stableOnboardingId(\"user\", detail.cognitoSub);\n const tenantId = stableOnboardingId(\"tenant\", detail.cognitoSub);\n const workspaceId = stableOnboardingId(\"workspace\", detail.cognitoSub);\n const userTenantMembershipId = stableOnboardingId(\n \"tenant-membership\",\n detail.cognitoSub,\n );\n const userWorkspaceMembershipId = stableOnboardingId(\n \"workspace-membership\",\n detail.cognitoSub,\n );\n const roleAssignmentId = stableOnboardingId(\n \"tenant-user-role-assignment\",\n detail.cognitoSub,\n );\n\n const lastUpdated = new Date().toISOString();\n\n // Synthesized OpenHI context for internal-system writes during onboarding.\n const context: OpenHiContext = {\n tenantId,\n workspaceId,\n date: lastUpdated,\n actorId: userId,\n actorName: displayName,\n actorType: \"internal-system\",\n };\n\n const tenantResource = {\n id: tenantId,\n name: `${displayName}'s Practice`,\n active: true,\n };\n const workspaceResource = {\n id: workspaceId,\n name: \"Default Workspace\",\n active: true,\n tenant: { reference: `Tenant/${tenantId}` },\n };\n const userResource = {\n ...(existingResource ?? {}),\n resourceType: \"User\",\n id: userId,\n name: existingResource?.name ?? [{ text: displayName }],\n status: \"active\",\n currentTenant: { reference: `Tenant/${tenantId}` },\n currentWorkspace: { reference: `Workspace/${workspaceId}` },\n };\n const userTenantMembershipResource = {\n id: userTenantMembershipId,\n status: \"active\",\n user: { reference: `User/${userId}` },\n tenant: { reference: `Tenant/${tenantId}` },\n };\n const userWorkspaceMembershipResource = {\n id: userWorkspaceMembershipId,\n status: \"active\",\n user: { reference: `User/${userId}` },\n tenant: { reference: `Tenant/${tenantId}` },\n workspace: { reference: `Workspace/${workspaceId}` },\n };\n const roleAssignmentResource = {\n id: roleAssignmentId,\n status: \"active\",\n user: { reference: `User/${userId}` },\n tenant: { reference: `Tenant/${tenantId}` },\n role: \"tenant-user\",\n };\n\n await createTenantOperation({\n context,\n body: { id: tenantId, resource: tenantResource },\n });\n\n await createWorkspaceOperation({\n context,\n body: { id: workspaceId, resource: workspaceResource },\n });\n\n // Direct User put/patch: no User operation supports the cognitoSub set or\n // partial-repair flow yet, so onboarding writes the User record inline.\n if (existingUser) {\n await service.entities.user\n .patch({ id: userId, sk: CURRENT_SK })\n .set({\n resource: JSON.stringify(userResource),\n summary: summaryFor(userResource),\n cognitoSub: detail.cognitoSub,\n vid: VID,\n lastUpdated,\n })\n .go();\n } else {\n await service.entities.user\n .put({\n id: userId,\n cognitoSub: detail.cognitoSub,\n resource: JSON.stringify(userResource),\n summary: summaryFor(userResource),\n vid: VID,\n lastUpdated,\n })\n .go();\n }\n\n await createMembershipOperation({\n context,\n body: {\n id: userTenantMembershipId,\n resource: userTenantMembershipResource,\n },\n });\n\n await createMembershipOperation({\n context,\n body: {\n id: userWorkspaceMembershipId,\n resource: userWorkspaceMembershipResource,\n },\n });\n\n await createRoleAssignmentOperation({\n context,\n body: { id: roleAssignmentId, resource: roleAssignmentResource },\n });\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/workflows/control-plane/user-onboarding/provision-default-workspace.handler.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { extractSummary, type FhirResourceLike } from \"@openhi/types\";\nimport type { EventBridgeEvent } from \"aws-lambda\";\nimport {\n PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,\n type ProvisionDefaultWorkspaceRequestedDetail,\n} from \"./events\";\nimport { getDynamoControlService } from \"../../../data/dynamo/dynamo-control-service\";\nimport type { OpenHiContext } from \"../../../data/openhi-context\";\nimport { createMembershipOperation } from \"../../../data/operations/control/membership/membership-create-operation\";\nimport { createRoleAssignmentOperation } from \"../../../data/operations/control/roleassignment/roleassignment-create-operation\";\nimport { createTenantOperation } from \"../../../data/operations/control/tenant/tenant-create-operation\";\nimport {\n findUserBySubOperation,\n parseUserResource,\n} from \"../../../data/operations/control/user\";\nimport { createWorkspaceOperation } from \"../../../data/operations/control/workspace/workspace-create-operation\";\nimport { idFromReference } from \"../../../data/operations/fhir-reference\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/user-onboarding/provision-default-workspace.handler.md\n *\n * EventBridge workflow handler that provisions the default control-plane\n * records for a newly confirmed Cognito user.\n */\ntype ProvisionDefaultWorkspaceEvent = EventBridgeEvent<\n typeof PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,\n ProvisionDefaultWorkspaceRequestedDetail\n>;\n\nconst CURRENT_SK = \"CURRENT\";\nconst VID = \"1\";\n\n// Store the same compact summary shape used by control-plane entities.\nconst summaryFor = (resource: Record<string, unknown>): string => {\n return JSON.stringify(extractSummary(resource as FhirResourceLike));\n};\n\n// Make onboarding writes replay-safe by deriving deterministic record ids.\nconst stableOnboardingId = (kind: string, cognitoSub: string): string => {\n return createHash(\"sha256\")\n .update(kind)\n .update(\"\\0\")\n .update(cognitoSub)\n .digest(\"hex\")\n .slice(0, 26)\n .toUpperCase();\n};\n\nexport const handler = async (\n event: ProvisionDefaultWorkspaceEvent,\n): Promise<void> => {\n // Events without a Cognito subject cannot be tied to a stable User.\n const detail = event.detail;\n if (!detail?.cognitoSub) {\n console.warn(\n \"ProvisionDefaultWorkspace: event missing cognitoSub; skipping\",\n );\n return;\n }\n\n // If onboarding already completed, leave existing records untouched.\n // The lookup runs before tenant/workspace exist, so use a synthetic\n // placeholder context — findUserBySubOperation does not read its fields.\n const service = getDynamoControlService();\n const existingUser = await findUserBySubOperation({\n context: {\n tenantId: \"\",\n workspaceId: \"\",\n date: \"\",\n actorId: \"\",\n actorName: \"\",\n actorType: \"internal-system\",\n },\n cognitoSub: detail.cognitoSub,\n });\n const existingResource = existingUser\n ? parseUserResource(existingUser.resource)\n : undefined;\n const existingTenantId = idFromReference(\n existingResource?.currentTenant?.reference,\n \"Tenant/\",\n );\n const existingWorkspaceId = idFromReference(\n existingResource?.currentWorkspace?.reference,\n \"Workspace/\",\n );\n\n if (existingUser && existingTenantId && existingWorkspaceId) {\n return;\n }\n\n const displayName =\n detail.displayName ||\n detail.email ||\n event.resources?.[0] ||\n detail.cognitoSub;\n const userId =\n existingUser?.id ??\n detail.userId ??\n stableOnboardingId(\"user\", detail.cognitoSub);\n const tenantId = stableOnboardingId(\"tenant\", detail.cognitoSub);\n const workspaceId = stableOnboardingId(\"workspace\", detail.cognitoSub);\n const userTenantMembershipId = stableOnboardingId(\n \"tenant-membership\",\n detail.cognitoSub,\n );\n const userWorkspaceMembershipId = stableOnboardingId(\n \"workspace-membership\",\n detail.cognitoSub,\n );\n const roleAssignmentId = stableOnboardingId(\n \"tenant-user-role-assignment\",\n detail.cognitoSub,\n );\n\n const lastUpdated = new Date().toISOString();\n\n // Synthesized OpenHI context for internal-system writes during onboarding.\n const context: OpenHiContext = {\n tenantId,\n workspaceId,\n date: lastUpdated,\n actorId: userId,\n actorName: displayName,\n actorType: \"internal-system\",\n };\n\n const tenantResource = {\n id: tenantId,\n name: `${displayName}'s Practice`,\n active: true,\n };\n const workspaceResource = {\n id: workspaceId,\n name: \"Default Workspace\",\n active: true,\n tenant: { reference: `Tenant/${tenantId}` },\n };\n const userResource = {\n ...(existingResource ?? {}),\n resourceType: \"User\",\n id: userId,\n name: existingResource?.name ?? [{ text: displayName }],\n status: \"active\",\n currentTenant: { reference: `Tenant/${tenantId}` },\n currentWorkspace: { reference: `Workspace/${workspaceId}` },\n };\n const userTenantMembershipResource = {\n id: userTenantMembershipId,\n status: \"active\",\n user: { reference: `User/${userId}` },\n tenant: { reference: `Tenant/${tenantId}` },\n };\n const userWorkspaceMembershipResource = {\n id: userWorkspaceMembershipId,\n status: \"active\",\n user: { reference: `User/${userId}` },\n tenant: { reference: `Tenant/${tenantId}` },\n workspace: { reference: `Workspace/${workspaceId}` },\n };\n const roleAssignmentResource = {\n id: roleAssignmentId,\n status: \"active\",\n user: { reference: `User/${userId}` },\n tenant: { reference: `Tenant/${tenantId}` },\n role: \"tenant-user\",\n };\n\n await createTenantOperation({\n context,\n body: { id: tenantId, resource: tenantResource },\n });\n\n await createWorkspaceOperation({\n context,\n body: { id: workspaceId, resource: workspaceResource },\n });\n\n // Direct User put/patch: no User operation supports the cognitoSub set or\n // partial-repair flow yet, so onboarding writes the User record inline.\n if (existingUser) {\n await service.entities.user\n .patch({ id: userId, sk: CURRENT_SK })\n .set({\n resource: JSON.stringify(userResource),\n summary: summaryFor(userResource),\n cognitoSub: detail.cognitoSub,\n vid: VID,\n lastUpdated,\n })\n .go();\n } else {\n await service.entities.user\n .put({\n id: userId,\n cognitoSub: detail.cognitoSub,\n resource: JSON.stringify(userResource),\n summary: summaryFor(userResource),\n vid: VID,\n lastUpdated,\n })\n .go();\n }\n\n await createMembershipOperation({\n context,\n body: {\n id: userTenantMembershipId,\n resource: userTenantMembershipResource,\n },\n });\n\n await createMembershipOperation({\n context,\n body: {\n id: userWorkspaceMembershipId,\n resource: userWorkspaceMembershipResource,\n },\n });\n\n await createRoleAssignmentOperation({\n context,\n body: { id: roleAssignmentId, resource: roleAssignmentResource },\n });\n};\n"],"mappings":"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","names":[]}
|
|
@@ -11235,7 +11235,7 @@ function buildGenericSearchSql(opts) {
|
|
|
11235
11235
|
"FROM resources",
|
|
11236
11236
|
"WHERE tenant_id = :tenantId",
|
|
11237
11237
|
" AND workspace_id = :workspaceId",
|
|
11238
|
-
" AND resource_type = :resourceType",
|
|
11238
|
+
" AND LOWER(resource_type) = LOWER(:resourceType)",
|
|
11239
11239
|
" AND deleted_at IS NULL"
|
|
11240
11240
|
];
|
|
11241
11241
|
if (opts.combinedSql.length > 0) {
|