@openhi/constructs 0.0.178 → 0.0.179
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-Z4PZSLYY.mjs → chunk-3M4QTQH6.mjs} +2 -2
- package/lib/{chunk-JUSVETWK.mjs → chunk-4LQR32D2.mjs} +38 -40
- package/lib/{chunk-JUSVETWK.mjs.map → chunk-4LQR32D2.mjs.map} +1 -1
- package/lib/{chunk-XNUCKVSE.mjs → chunk-7GMTHOYF.mjs} +2 -2
- package/lib/{chunk-E2OWEBBH.mjs → chunk-DIVYB6GD.mjs} +18 -4
- package/lib/chunk-DIVYB6GD.mjs.map +1 -0
- package/lib/chunk-F2LY4TEI.mjs +272 -0
- package/lib/chunk-F2LY4TEI.mjs.map +1 -0
- package/lib/{chunk-GG2WD6TA.mjs → chunk-JJ3AQ6G5.mjs} +9 -3
- package/lib/{chunk-GG2WD6TA.mjs.map → chunk-JJ3AQ6G5.mjs.map} +1 -1
- package/lib/{chunk-EBB4RNUG.mjs → chunk-PIQISEGW.mjs} +2 -2
- package/lib/{chunk-FDBBTNCI.mjs → chunk-Q4KQD2NB.mjs} +117 -5
- package/lib/chunk-Q4KQD2NB.mjs.map +1 -0
- package/lib/{chunk-Y4RGUAM2.mjs → chunk-V6KLFEHC.mjs} +105 -34
- package/lib/chunk-V6KLFEHC.mjs.map +1 -0
- package/lib/chunk-VQY57NOV.mjs +60 -0
- package/lib/chunk-VQY57NOV.mjs.map +1 -0
- package/lib/counter-maintenance.handler.mjs +4 -4
- package/lib/counter-reconciliation.handler.js +2 -2
- package/lib/counter-reconciliation.handler.js.map +1 -1
- package/lib/counter-reconciliation.handler.mjs +9 -267
- package/lib/counter-reconciliation.handler.mjs.map +1 -1
- package/lib/index.d.mts +117 -2
- package/lib/index.d.ts +117 -2
- package/lib/index.js +6454 -6243
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +106 -4
- package/lib/index.mjs.map +1 -1
- package/lib/pre-token-generation.handler.js +28 -19
- package/lib/pre-token-generation.handler.js.map +1 -1
- package/lib/pre-token-generation.handler.mjs +4 -5
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.js +22 -19
- package/lib/provision-default-workspace.handler.js.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +3 -4
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rest-api-lambda.handler.js +365 -207
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +208 -164
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.d.mts +19 -0
- package/lib/seed-demo-data.handler.d.ts +19 -0
- package/lib/seed-demo-data.handler.js +805 -159
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +8 -4
- package/package.json +1 -1
- package/lib/chunk-6HGSR3TG.mjs +0 -123
- package/lib/chunk-6HGSR3TG.mjs.map +0 -1
- package/lib/chunk-E2OWEBBH.mjs.map +0 -1
- package/lib/chunk-FDBBTNCI.mjs.map +0 -1
- package/lib/chunk-Y4RGUAM2.mjs.map +0 -1
- /package/lib/{chunk-Z4PZSLYY.mjs.map → chunk-3M4QTQH6.mjs.map} +0 -0
- /package/lib/{chunk-XNUCKVSE.mjs.map → chunk-7GMTHOYF.mjs.map} +0 -0
- /package/lib/{chunk-EBB4RNUG.mjs.map → chunk-PIQISEGW.mjs.map} +0 -0
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listPractitionerRolesOperation,
|
|
3
3
|
listRoleAssignmentsOperation
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JJ3AQ6G5.mjs";
|
|
5
5
|
import {
|
|
6
6
|
listMembershipsOperation
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PIQISEGW.mjs";
|
|
8
8
|
import {
|
|
9
9
|
findUserBySubOperation,
|
|
10
10
|
idFromReference,
|
|
11
11
|
parseUserResource
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-6HGSR3TG.mjs";
|
|
12
|
+
} from "./chunk-V6KLFEHC.mjs";
|
|
14
13
|
import "./chunk-6BB4CRSS.mjs";
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-Q4KQD2NB.mjs";
|
|
16
15
|
import "./chunk-APVVG7BO.mjs";
|
|
17
16
|
import "./chunk-FYHBHHWK.mjs";
|
|
18
17
|
import "./chunk-EUIP2U5F.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":[]}
|
|
@@ -758,7 +758,7 @@ __export(provision_default_workspace_handler_exports, {
|
|
|
758
758
|
});
|
|
759
759
|
module.exports = __toCommonJS(provision_default_workspace_handler_exports);
|
|
760
760
|
var import_node_crypto = require("crypto");
|
|
761
|
-
var
|
|
761
|
+
var import_types15 = require("@openhi/types");
|
|
762
762
|
|
|
763
763
|
// src/data/dynamo/dynamo-control-service.ts
|
|
764
764
|
var import_electrodb14 = require("electrodb");
|
|
@@ -3312,8 +3312,20 @@ async function createTenantOperation(params) {
|
|
|
3312
3312
|
return { id, resource, meta: { lastUpdated, versionId: vid } };
|
|
3313
3313
|
}
|
|
3314
3314
|
|
|
3315
|
-
// src/data/operations/control/user/user-
|
|
3315
|
+
// src/data/operations/control/user/user-admin-set-context-operation.ts
|
|
3316
3316
|
var import_types9 = require("@openhi/types");
|
|
3317
|
+
|
|
3318
|
+
// src/data/operations/fhir-reference.ts
|
|
3319
|
+
function idFromReference(reference, prefix) {
|
|
3320
|
+
if (!reference || !reference.startsWith(prefix)) {
|
|
3321
|
+
return void 0;
|
|
3322
|
+
}
|
|
3323
|
+
const id = reference.slice(prefix.length);
|
|
3324
|
+
return id.length > 0 ? id : void 0;
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
// src/data/operations/control/user/user-create-operation.ts
|
|
3328
|
+
var import_types10 = require("@openhi/types");
|
|
3317
3329
|
var import_ulid4 = require("ulid");
|
|
3318
3330
|
|
|
3319
3331
|
// src/data/operations/control/user/user-find-by-sub-operation.ts
|
|
@@ -3341,7 +3353,7 @@ async function findUserBySubOperation(params) {
|
|
|
3341
3353
|
}
|
|
3342
3354
|
|
|
3343
3355
|
// src/data/operations/data-operations-common.ts
|
|
3344
|
-
var
|
|
3356
|
+
var import_types11 = require("@openhi/types");
|
|
3345
3357
|
|
|
3346
3358
|
// src/lib/compression.ts
|
|
3347
3359
|
var import_node_zlib = require("zlib");
|
|
@@ -3378,8 +3390,8 @@ async function createDataEntityRecord(entity, tenantId, workspaceId, id, resourc
|
|
|
3378
3390
|
const lastUpdated = resourceWithAudit.meta?.lastUpdated ?? fallbackDate ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3379
3391
|
const vid = lastUpdated.replace(/[-:T.Z]/g, "").slice(0, 12) || Date.now().toString(36);
|
|
3380
3392
|
const resourceLike = resourceWithAudit;
|
|
3381
|
-
const summary = JSON.stringify((0,
|
|
3382
|
-
const gsi1sk = (0,
|
|
3393
|
+
const summary = JSON.stringify((0, import_types11.extractSummary)(resourceLike));
|
|
3394
|
+
const gsi1sk = (0, import_types11.extractSortKey)(resourceLike);
|
|
3383
3395
|
await entity.put({
|
|
3384
3396
|
sk: DATA_ENTITY_SK,
|
|
3385
3397
|
tenantId,
|
|
@@ -3398,7 +3410,7 @@ async function createDataEntityRecord(entity, tenantId, workspaceId, id, resourc
|
|
|
3398
3410
|
}
|
|
3399
3411
|
|
|
3400
3412
|
// src/data/operations/control/user/user-switch-tenant-workspace-operation.ts
|
|
3401
|
-
var
|
|
3413
|
+
var import_types12 = require("@openhi/types");
|
|
3402
3414
|
|
|
3403
3415
|
// src/data/operations/control/user/user-resource-helpers.ts
|
|
3404
3416
|
function parseUserResource(resource) {
|
|
@@ -3409,20 +3421,11 @@ function parseUserResource(resource) {
|
|
|
3409
3421
|
}
|
|
3410
3422
|
}
|
|
3411
3423
|
|
|
3412
|
-
// src/data/operations/fhir-reference.ts
|
|
3413
|
-
function idFromReference(reference, prefix) {
|
|
3414
|
-
if (!reference || !reference.startsWith(prefix)) {
|
|
3415
|
-
return void 0;
|
|
3416
|
-
}
|
|
3417
|
-
const id = reference.slice(prefix.length);
|
|
3418
|
-
return id.length > 0 ? id : void 0;
|
|
3419
|
-
}
|
|
3420
|
-
|
|
3421
3424
|
// src/data/operations/control/user/user-update-operation.ts
|
|
3422
|
-
var
|
|
3425
|
+
var import_types13 = require("@openhi/types");
|
|
3423
3426
|
|
|
3424
3427
|
// src/data/operations/control/workspace/workspace-create-operation.ts
|
|
3425
|
-
var
|
|
3428
|
+
var import_types14 = require("@openhi/types");
|
|
3426
3429
|
var import_ulid5 = require("ulid");
|
|
3427
3430
|
|
|
3428
3431
|
// src/data/dynamo/dynamo-data-service.ts
|
|
@@ -4507,7 +4510,7 @@ async function createWorkspaceOperation(params) {
|
|
|
4507
4510
|
const vid = lastUpdated.replace(/[-:T.Z]/g, "").slice(0, 12) || Date.now().toString(36);
|
|
4508
4511
|
const parsedResource = typeof body.resource === "string" ? JSON.parse(body.resource) : body.resource ?? {};
|
|
4509
4512
|
const resource = { resourceType: "Workspace", id, ...parsedResource };
|
|
4510
|
-
const summary = JSON.stringify((0,
|
|
4513
|
+
const summary = JSON.stringify((0, import_types14.extractSummary)(resource));
|
|
4511
4514
|
await service.entities.workspace.put({
|
|
4512
4515
|
tenantId,
|
|
4513
4516
|
id,
|
|
@@ -4534,7 +4537,7 @@ async function createWorkspaceOperation(params) {
|
|
|
4534
4537
|
var CURRENT_SK = "CURRENT";
|
|
4535
4538
|
var VID = "1";
|
|
4536
4539
|
var summaryFor = (resource) => {
|
|
4537
|
-
return JSON.stringify((0,
|
|
4540
|
+
return JSON.stringify((0, import_types15.extractSummary)(resource));
|
|
4538
4541
|
};
|
|
4539
4542
|
var stableOnboardingId = (kind, cognitoSub) => {
|
|
4540
4543
|
return (0, import_node_crypto.createHash)("sha256").update(kind).update("\0").update(cognitoSub).digest("hex").slice(0, 26).toUpperCase();
|