@openhi/constructs 0.0.111 → 0.0.112
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-23PUSHBV.mjs +24 -0
- package/lib/chunk-23PUSHBV.mjs.map +1 -0
- package/lib/{chunk-7FUAMZOF.mjs → chunk-53OHXLIL.mjs} +3 -3
- package/lib/chunk-6NBGYGFL.mjs +1803 -0
- package/lib/chunk-6NBGYGFL.mjs.map +1 -0
- package/lib/chunk-7RZHFI77.mjs +22 -0
- package/lib/chunk-7RZHFI77.mjs.map +1 -0
- package/lib/{chunk-7Q2IJ2J5.mjs → chunk-CUUKXDB2.mjs} +6 -6
- package/lib/chunk-FYHBHHWK.mjs +47 -0
- package/lib/chunk-FYHBHHWK.mjs.map +1 -0
- package/lib/{chunk-MULKGFIJ.mjs → chunk-GBDIGTNV.mjs} +165 -10
- package/lib/chunk-GBDIGTNV.mjs.map +1 -0
- package/lib/chunk-HQ67J7BP.mjs +199 -0
- package/lib/chunk-HQ67J7BP.mjs.map +1 -0
- package/lib/{chunk-AJ3G3THO.mjs → chunk-KO64HPWQ.mjs} +2 -2
- package/lib/{chunk-BB5MK4L3.mjs → chunk-KSFC72TT.mjs} +3 -3
- package/lib/{chunk-2TPJ6HOF.mjs → chunk-NZRW7ROK.mjs} +72 -54
- package/lib/chunk-NZRW7ROK.mjs.map +1 -0
- package/lib/chunk-QJDHVMKT.mjs +117 -0
- package/lib/chunk-QJDHVMKT.mjs.map +1 -0
- package/lib/{chunk-IS4VQRI4.mjs → chunk-QMBJ4VHC.mjs} +12 -47
- package/lib/chunk-QMBJ4VHC.mjs.map +1 -0
- package/lib/chunk-TRY7JGWO.mjs +16 -0
- package/lib/chunk-TRY7JGWO.mjs.map +1 -0
- package/lib/chunk-W4KR4CSL.mjs +236 -0
- package/lib/chunk-W4KR4CSL.mjs.map +1 -0
- package/lib/{chunk-AGF3RAAZ.mjs → chunk-WPCBVDFZ.mjs} +2 -2
- package/lib/chunk-WQWFVEVX.mjs +66 -0
- package/lib/chunk-WQWFVEVX.mjs.map +1 -0
- package/lib/{chunk-SYBADQXI.mjs → chunk-ZM4GDHHC.mjs} +77 -2
- package/lib/chunk-ZM4GDHHC.mjs.map +1 -0
- package/lib/delete-chunk.handler.d.mts +29 -0
- package/lib/delete-chunk.handler.d.ts +29 -0
- package/lib/delete-chunk.handler.js +2716 -0
- package/lib/delete-chunk.handler.js.map +1 -0
- package/lib/delete-chunk.handler.mjs +47 -0
- package/lib/delete-chunk.handler.mjs.map +1 -0
- package/lib/events-CjS-sm0W.d.mts +107 -0
- package/lib/events-CjS-sm0W.d.ts +107 -0
- package/lib/events-Da_cFgtc.d.mts +208 -0
- package/lib/events-Da_cFgtc.d.ts +208 -0
- package/lib/finalize.handler.d.mts +35 -0
- package/lib/finalize.handler.d.ts +35 -0
- package/lib/finalize.handler.js +875 -0
- package/lib/finalize.handler.js.map +1 -0
- package/lib/finalize.handler.mjs +166 -0
- package/lib/finalize.handler.mjs.map +1 -0
- package/lib/index.d.mts +189 -2
- package/lib/index.d.ts +500 -3
- package/lib/index.js +1753 -174
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +571 -17
- package/lib/index.mjs.map +1 -1
- package/lib/list-chunks.handler.d.mts +28 -0
- package/lib/list-chunks.handler.d.ts +28 -0
- package/lib/list-chunks.handler.js +2746 -0
- package/lib/list-chunks.handler.js.map +1 -0
- package/lib/list-chunks.handler.mjs +54 -0
- package/lib/list-chunks.handler.mjs.map +1 -0
- package/lib/platform-deploy-bridge.handler.js +76 -1
- package/lib/platform-deploy-bridge.handler.js.map +1 -1
- package/lib/platform-deploy-bridge.handler.mjs +1 -1
- package/lib/pre-token-generation.handler.js +1106 -155
- package/lib/pre-token-generation.handler.js.map +1 -1
- package/lib/pre-token-generation.handler.mjs +6 -4
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.js +1529 -142
- package/lib/provision-default-workspace.handler.js.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +8 -4
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rename-finalize.handler.d.mts +30 -0
- package/lib/rename-finalize.handler.d.ts +30 -0
- package/lib/rename-finalize.handler.js +795 -0
- package/lib/rename-finalize.handler.js.map +1 -0
- package/lib/rename-finalize.handler.mjs +90 -0
- package/lib/rename-finalize.handler.mjs.map +1 -0
- package/lib/rename-list-targets.handler.d.mts +26 -0
- package/lib/rename-list-targets.handler.d.ts +26 -0
- package/lib/rename-list-targets.handler.js +2985 -0
- package/lib/rename-list-targets.handler.js.map +1 -0
- package/lib/rename-list-targets.handler.mjs +431 -0
- package/lib/rename-list-targets.handler.mjs.map +1 -0
- package/lib/rename-rewrite-chunk.handler.d.mts +35 -0
- package/lib/rename-rewrite-chunk.handler.d.ts +35 -0
- package/lib/rename-rewrite-chunk.handler.js +2021 -0
- package/lib/rename-rewrite-chunk.handler.js.map +1 -0
- package/lib/rename-rewrite-chunk.handler.mjs +27 -0
- package/lib/rename-rewrite-chunk.handler.mjs.map +1 -0
- package/lib/rest-api-lambda.handler.js +4021 -932
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +1786 -80
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.js +1588 -124
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +10 -6
- package/lib/seed-system-data.handler.js +1179 -155
- package/lib/seed-system-data.handler.js.map +1 -1
- package/lib/seed-system-data.handler.mjs +5 -4
- package/lib/seed-system-data.handler.mjs.map +1 -1
- package/package.json +3 -3
- package/lib/chunk-2TPJ6HOF.mjs.map +0 -1
- package/lib/chunk-IS4VQRI4.mjs.map +0 -1
- package/lib/chunk-MULKGFIJ.mjs.map +0 -1
- package/lib/chunk-QR5JVSCF.mjs +0 -862
- package/lib/chunk-QR5JVSCF.mjs.map +0 -1
- package/lib/chunk-SYBADQXI.mjs.map +0 -1
- /package/lib/{chunk-7FUAMZOF.mjs.map → chunk-53OHXLIL.mjs.map} +0 -0
- /package/lib/{chunk-7Q2IJ2J5.mjs.map → chunk-CUUKXDB2.mjs.map} +0 -0
- /package/lib/{chunk-AJ3G3THO.mjs.map → chunk-KO64HPWQ.mjs.map} +0 -0
- /package/lib/{chunk-BB5MK4L3.mjs.map → chunk-KSFC72TT.mjs.map} +0 -0
- /package/lib/{chunk-AGF3RAAZ.mjs.map → chunk-WPCBVDFZ.mjs.map} +0 -0
package/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../config/src/open-hi-config.ts","../../config/src/index.ts","../src/app/open-hi-app.ts","../src/app/open-hi-environment.ts","../src/app/open-hi-stage.ts","../src/app/open-hi-service.ts","../src/components/acm/root-wildcard-certificate.ts","../src/components/api-gateway/root-http-api.ts","../src/components/app-sync/root-graphql-api.ts","../src/components/ssm/discoverable-string-parameter.ts","../src/components/cognito/cognito-fixture-seeder-client.ts","../src/components/cognito/cognito-user-pool.ts","../src/components/cognito/cognito-user-pool-client.ts","../src/components/cognito/cognito-user-pool-domain.ts","../src/components/cognito/cognito-user-pool-kms-key.ts","../src/components/cognito/post-authentication-lambda.ts","../src/components/cognito/post-confirmation-lambda.ts","../src/components/cognito/pre-token-generation-lambda.ts","../src/components/dynamodb/data-store-historical-archive.ts","../src/components/dynamodb/dynamo-db-data-store.ts","../src/components/dynamodb/workflow-dedup-table.ts","../src/components/event-bridge/data-event-bus.ts","../src/components/event-bridge/ops-event-bus.ts","../src/components/event-bridge/control-event-bus.ts","../src/components/postgres/data-store-postgres-replica.ts","../src/components/route-53/child-hosted-zone.ts","../src/components/route-53/root-hosted-zone.ts","../src/components/static-hosting/static-hosting.ts","../src/services/open-hi-auth-service.ts","../src/services/open-hi-data-service.ts","../src/services/open-hi-global-service.ts","../src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge.ts","../src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge-lambda.ts","../src/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.ts","../src/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.ts","../src/workflows/control-plane/seed-system-data/seed-system-data-lambda.ts","../src/workflows/control-plane/seed-system-data/seed-system-data-workflow.ts","../src/workflows/control-plane/user-onboarding/provision-default-workspace-lambda.ts","../src/workflows/control-plane/user-onboarding/user-onboarding-workflow.ts","../src/services/open-hi-rest-api-service.ts","../src/data/lambda/cors-options-lambda.ts","../src/data/lambda/rest-api-lambda.ts","../src/services/open-hi-graphql-service.ts"],"sourcesContent":["/*******************************************************************************\n *\n * OpenHi Config\n *\n * These types are kept in their own package to prevent dependency conflicts and\n * conditions between @openhi/constructs and @openhi/platform..\n *\n ******************************************************************************/\n\n/**\n * Stage Types\n *\n * What stage of deployment is this? Dev, staging, or prod?\n */\nexport const OPEN_HI_STAGE = {\n /**\n * Development environment, typically used for testing and development.\n */\n DEV: \"dev\",\n /**\n * Staging environment, used for pre-production testing.\n */\n STAGE: \"stage\",\n /**\n * Production environment, used for live deployments.\n */\n PROD: \"prod\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type OpenHiStageType =\n (typeof OPEN_HI_STAGE)[keyof typeof OPEN_HI_STAGE];\n\n/**\n * Deployment Target Role\n *\n * Is this (account, region) the primary or a secondary deployment target for the stage?\n * Works for both multi-region (different regions) and cellular (same region, different accounts).\n */\nexport const OPEN_HI_DEPLOYMENT_TARGET_ROLE = {\n /**\n * The primary deployment target for this stage (main account/region).\n * For example, the base DynamoDB region for global tables.\n */\n PRIMARY: \"primary\",\n\n /**\n * A secondary deployment target for this stage (additional account/region).\n * For example, a replica region for a global DynamoDB table, or another cell in the same region.\n */\n SECONDARY: \"secondary\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type OpenHiDeploymentTargetRoleType =\n (typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE)[keyof typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE];\n\nexport interface OpenHiEnvironmentConfig {\n account: string;\n region: string;\n /**\n * Route53 zone containing DNS for this service.\n */\n hostedZoneId?: string;\n zoneName?: string;\n}\n\n/**\n * Represents the configuration for OpenHi services across different stages and\n * deployment targets.\n */\nexport interface OpenHiConfig {\n versions?: {\n cdk?: {\n cdkLibVersion?: string;\n cdkCliVersion?: string;\n };\n };\n deploymentTargets?: {\n [OPEN_HI_STAGE.DEV]?: {\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]?: OpenHiEnvironmentConfig;\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]?: Array<OpenHiEnvironmentConfig>;\n };\n [OPEN_HI_STAGE.STAGE]?: {\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]?: OpenHiEnvironmentConfig;\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]?: Array<OpenHiEnvironmentConfig>;\n };\n [OPEN_HI_STAGE.PROD]?: {\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]?: OpenHiEnvironmentConfig;\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]?: Array<OpenHiEnvironmentConfig>;\n };\n };\n}\n","export * from \"./open-hi-config\";\n","import {\n OPEN_HI_DEPLOYMENT_TARGET_ROLE,\n OPEN_HI_STAGE,\n OpenHiConfig,\n OpenHiEnvironmentConfig,\n} from \"@openhi/config\";\nimport { App, AppProps } from \"aws-cdk-lib\";\nimport { IConstruct } from \"constructs\";\nimport { OpenHiEnvironment } from \"./open-hi-environment\";\nimport { OpenHiStage } from \"./open-hi-stage\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-app.md\n */\n\n/**\n * Symbol used for runtime type checking to identify OpenHiApp instances.\n *\n * @internal\n */\nconst OPEN_HI_APP_SYMBOL = Symbol.for(\"@openhi/constructs/core.OpenHiApp\");\n\n/**\n * Properties for creating an OpenHiApp instance.\n */\nexport interface OpenHiAppProps extends AppProps {\n /**\n * Optional name for the application.\n * ```\n */\n readonly appName?: string;\n\n /**\n * The OpenHi configuration object that defines stages, environments, and\n * their associated AWS account and region settings.\n */\n readonly config: OpenHiConfig;\n}\n\n/**\n * Root application construct for OpenHi CDK applications.\n */\nexport class OpenHiApp extends App {\n /**\n * Finds the OpenHiApp instance that contains the given construct in its\n * construct tree.\n */\n public static of(construct: IConstruct): OpenHiApp | undefined {\n return construct.node.scopes.reverse().find(OpenHiApp.isOpenHiApp);\n }\n\n /**\n * Type guard that checks if a value is an OpenHiApp instance.\n */\n public static isOpenHiApp(this: void, x: any): x is OpenHiApp {\n return x !== null && typeof x === \"object\" && OPEN_HI_APP_SYMBOL in x;\n }\n\n /**\n * Name for the application.\n */\n readonly appName: string;\n\n /**\n * The OpenHi configuration object for this application.\n */\n readonly config: OpenHiConfig;\n\n /**\n * Creates a new OpenHiApp instance.\n */\n constructor(props: OpenHiAppProps) {\n super(props);\n\n // Set runtime symbol for type checking\n Object.defineProperty(this, OPEN_HI_APP_SYMBOL, { value: true });\n\n // Store app name, defaulting to \"openhi\" if not provided\n this.appName = props.appName ?? \"openhi\";\n\n // Store configuration for use by child constructs\n this.config = props.config;\n\n // Create stages and environments based on configuration\n // Iterate through all possible stage types (dev, stage, prod)\n Object.values(OPEN_HI_STAGE).forEach((stageType) => {\n // Only create a stage if it's configured in the config\n if (this.config.deploymentTargets?.[stageType]) {\n const stage = new OpenHiStage(this, { stageType });\n\n // Create primary deployment target if configured\n // Each stage can have at most one primary deployment target\n if (\n this.config.deploymentTargets?.[stageType]?.[\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY\n ]\n ) {\n const envConfig =\n this.config.deploymentTargets[stageType][\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY\n ]!;\n new OpenHiEnvironment(stage, {\n deploymentTargetRole: OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY,\n config: envConfig,\n env: { account: envConfig.account, region: envConfig.region },\n });\n }\n\n // Create secondary deployment targets if configured\n // Each stage can have zero or more secondary deployment targets\n if (\n this.config.deploymentTargets?.[stageType]?.[\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY\n ]\n ) {\n this.config.deploymentTargets[stageType][\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY\n ]!.forEach((envConfig: OpenHiEnvironmentConfig) => {\n new OpenHiEnvironment(stage, {\n deploymentTargetRole: OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY,\n config: envConfig,\n env: { account: envConfig.account, region: envConfig.region },\n });\n });\n }\n }\n });\n }\n\n /*****************************************************************************\n *\n * Stages\n *\n ****************************************************************************/\n\n /**\n * Gets all OpenHiStage instances that are direct children of this app.\n\n */\n public get stages(): Array<OpenHiStage> {\n return this.node.children.filter(OpenHiStage.isOpenHiStage);\n }\n\n /**\n * Gets the development stage, if it exists.\n */\n public get devStage(): OpenHiStage | undefined {\n return this.stages.find((stage) => stage.stageType === OPEN_HI_STAGE.DEV);\n }\n\n /**\n * Gets the staging stage, if it exists.\n */\n public get stageStage(): OpenHiStage | undefined {\n return this.stages.find((stage) => stage.stageType === OPEN_HI_STAGE.STAGE);\n }\n\n /**\n * Gets the production stage, if it exists.\n */\n public get prodStage(): OpenHiStage | undefined {\n return this.stages.find((stage) => stage.stageType === OPEN_HI_STAGE.PROD);\n }\n\n /*****************************************************************************\n *\n * Environments\n *\n ****************************************************************************/\n\n /**\n * Gets all OpenHiEnvironment instances across all stages in this app.\n */\n public get environments(): Array<OpenHiEnvironment> {\n return this.stages.flatMap((stage) => stage.environments);\n }\n\n /**\n * Gets all primary environments across all stages in this app.\n */\n public get primaryEnvironments(): Array<OpenHiEnvironment> {\n return this.environments.filter(\n (env) => env.deploymentTargetRole === \"primary\",\n );\n }\n\n /**\n * Gets all secondary environments across all stages in this app.\n */\n public get secondaryEnvironments(): Array<OpenHiEnvironment> {\n return this.environments.filter(\n (env) => env.deploymentTargetRole === \"secondary\",\n );\n }\n}\n","import {\n OPEN_HI_DEPLOYMENT_TARGET_ROLE,\n OpenHiEnvironmentConfig,\n} from \"@openhi/config\";\nimport { Stage, StageProps } from \"aws-cdk-lib\";\nimport { IConstruct } from \"constructs\";\nimport { OpenHiStage } from \"./open-hi-stage\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-environment.md\n */\n\n/**\n * Symbol used to identify OpenHiEnvironment instances at runtime.\n */\nconst OPEN_HI_ENVIRONMENT_SYMBOL = Symbol.for(\n \"@openhi/constructs/core.OpenHiEnvironment\",\n);\n\n/**\n * Properties for creating an OpenHiEnvironment.\n */\nexport interface OpenHiEnvironmentProps extends StageProps {\n /**\n * The deployment target role for this (account, region).\n */\n readonly deploymentTargetRole: (typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE)[keyof typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE];\n\n /**\n * Configuration for this specific environment.\n */\n readonly config: OpenHiEnvironmentConfig;\n}\n\n/**\n * Represents an OpenHi environment within an AWS CDK stage.\n */\nexport class OpenHiEnvironment extends Stage {\n /**\n * Finds the OpenHiEnvironment that contains the given construct.\n * ```\n */\n public static of(construct: IConstruct): OpenHiEnvironment | undefined {\n return construct.node.scopes\n .reverse()\n .find(OpenHiEnvironment.isOpenHiEnvironment);\n }\n\n /**\n * Type guard to check if a value is an OpenHiEnvironment instance.\n */\n public static isOpenHiEnvironment(\n this: void,\n x: any,\n ): x is OpenHiEnvironment {\n return (\n x !== null && typeof x === \"object\" && OPEN_HI_ENVIRONMENT_SYMBOL in x\n );\n }\n\n /**\n * Configuration for this specific environment.\n */\n readonly config: OpenHiEnvironmentConfig;\n\n /**\n * The deployment target role for this (account, region).\n */\n public readonly deploymentTargetRole: (typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE)[keyof typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE];\n\n /**\n * Creates a new OpenHiEnvironment.\n */\n constructor(\n /**\n * The OpenHiStage that contains this environment.\n */\n public ohStage: OpenHiStage,\n /**\n * Properties for creating the environment.\n */\n public props: OpenHiEnvironmentProps,\n ) {\n // Copy account and region from config into env, if provided.\n // This allows all resources in this environment to default to the correct\n // account and region without having to specify it on each stack or resource.\n if (props.config.account && props.config.region) {\n props = {\n ...props,\n env: {\n account: props.config.account,\n region: props.config.region,\n },\n };\n }\n\n // Determine the stage name:\n // - Primary environments use the environment type as the name\n // - Secondary deployment targets use \"{deploymentTargetRole}-{index}\" format\n const stageName =\n props.deploymentTargetRole === OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY\n ? props.deploymentTargetRole\n : [props.deploymentTargetRole, ohStage.environments.length].join(\"-\");\n\n super(ohStage, stageName, {\n env: props.env ?? ohStage.props.env,\n ...props,\n });\n\n // Mark this instance as an OpenHiEnvironment for runtime type checking\n Object.defineProperty(this, OPEN_HI_ENVIRONMENT_SYMBOL, { value: true });\n\n this.deploymentTargetRole = props.deploymentTargetRole;\n this.config = props.config;\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport { Stage, StageProps } from \"aws-cdk-lib\";\nimport { IConstruct } from \"constructs\";\nimport { OpenHiApp } from \"./open-hi-app\";\nimport { OpenHiEnvironment } from \"./open-hi-environment\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-stage.md\n */\n\n/**\n * Symbol used to identify OpenHiStage instances at runtime.\n *\n * @internal\n */\nconst OPEN_HI_STAGE_SYMBOL = Symbol.for(\"@openhi/constructs/core.OpenHiStage\");\n\n/**\n * Properties for creating an OpenHiStage instance.\n */\nexport interface OpenHiStageProps extends StageProps {\n /**\n * The type of the OpenHi stage.\n */\n readonly stageType: (typeof OPEN_HI_STAGE)[keyof typeof OPEN_HI_STAGE];\n}\n\n/**\n * Represents a deployment stage in the OpenHi infrastructure hierarchy.\n */\nexport class OpenHiStage extends Stage {\n /**\n * Finds the OpenHiStage that contains the given construct.\n */\n public static of(construct: IConstruct): OpenHiStage | undefined {\n return construct.node.scopes.reverse().find(OpenHiStage.isOpenHiStage);\n }\n\n /**\n * Type guard to check if a value is an OpenHiStage instance.\n */\n public static isOpenHiStage(this: void, x: any): x is OpenHiStage {\n return x !== null && typeof x === \"object\" && OPEN_HI_STAGE_SYMBOL in x;\n }\n\n /**\n * The type of this OpenHi stage.\n */\n public readonly stageType: (typeof OPEN_HI_STAGE)[keyof typeof OPEN_HI_STAGE];\n\n /**\n * Creates a new OpenHiStage instance.\n */\n constructor(\n /**\n * The OpenHiApp that this stage belongs to.\n *\n * @public\n */\n public ohApp: OpenHiApp,\n\n /**\n * Properties for configuring the stage.\n *\n * @public\n */\n public props: OpenHiStageProps,\n ) {\n super(ohApp, props.stageType, props);\n\n Object.defineProperty(this, OPEN_HI_STAGE_SYMBOL, { value: true });\n\n this.stageType = props.stageType;\n }\n\n /**\n * Gets all OpenHiEnvironment instances contained within this stage.\n */\n public get environments(): Array<OpenHiEnvironment> {\n return this.node.children.filter(OpenHiEnvironment.isOpenHiEnvironment);\n }\n\n /**\n * Gets the primary OpenHiEnvironment for this stage, if one exists.\n */\n public get primaryEnvironment(): OpenHiEnvironment | undefined {\n return this.environments.find(\n (env) => env.deploymentTargetRole === \"primary\",\n );\n }\n\n /**\n * Gets all secondary OpenHiEnvironment instances for this stage.\n */\n public get secondaryEnvironments(): Array<OpenHiEnvironment> {\n return this.environments.filter(\n (env) => env.deploymentTargetRole === \"secondary\",\n );\n }\n}\n","import {\n findGitBranch,\n findGitRepoName,\n hashString,\n} from \"@codedrifters/utils\";\nimport { OPEN_HI_STAGE, OpenHiEnvironmentConfig } from \"@openhi/config\";\nimport { RemovalPolicy, Stack, StackProps, Tags } from \"aws-cdk-lib\";\nimport { paramCase } from \"change-case\";\nimport { OpenHiEnvironment } from \"./open-hi-environment\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-service.md\n */\n\n/**\n * Known OpenHI service type strings. Each service class defines its own\n * static SERVICE_TYPE (e.g. OpenHiAuthService.SERVICE_TYPE === \"auth\").\n *\n * @public\n */\nexport type OpenHiServiceType =\n | \"auth\"\n | \"rest-api\"\n | \"data\"\n | \"global\"\n | \"graphql-api\";\n\n/**\n * Tag-key suffixes applied by every OpenHiService stack via Tags.of().\n * Full keys are composed `${appName}:${suffix}` — see {@link openHiTagKey}.\n * Consumers that filter or project these tags (e.g. the platform-deploy\n * bridge) import these suffixes rather than redeclaring the strings.\n *\n * @public\n */\nexport const OPENHI_TAG_SUFFIX_REPO_NAME = \"repo-name\";\n/** @public */\nexport const OPENHI_TAG_SUFFIX_BRANCH_NAME = \"branch-name\";\n/** @public */\nexport const OPENHI_TAG_SUFFIX_SERVICE_TYPE = \"service-type\";\n/** @public */\nexport const OPENHI_TAG_SUFFIX_STAGE_TYPE = \"stage-type\";\n\n/**\n * Compose a full stack-tag key from an `appName` and a suffix from\n * {@link OPENHI_TAG_SUFFIX_REPO_NAME} et al.\n *\n * @public\n */\nexport const openHiTagKey = (appName: string, suffix: string): string =>\n `${appName}:${suffix}`;\n\n/**\n * Properties for creating an {@link OpenHiService} stack.\n *\n * @public\n */\nexport interface OpenHiServiceProps extends StackProps {\n /**\n * Optional branch name override.\n */\n readonly branchName?: string;\n\n /**\n * Optional repository name override.\n */\n readonly repoName?: string;\n\n /**\n * Optional application name override.\n */\n readonly appName?: string;\n\n /**\n * Default release branch name.\n */\n readonly defaultReleaseBranch?: string;\n\n /**\n * The removal policy for persistent stack resources.\n */\n readonly removalPolicy?: RemovalPolicy;\n\n /**\n * Environment configuration for this service.\n */\n readonly config?: OpenHiEnvironmentConfig;\n\n /**\n * A constant that identifies the service type.\n */\n readonly serviceType?: OpenHiServiceType;\n}\n\n/**\n * Represents an OpenHI service stack within the OpenHI platform.\n * Subclasses must override {@link serviceType} to return their static SERVICE_TYPE.\n */\nexport abstract class OpenHiService extends Stack {\n /**\n * The service/stack ID that was passed to the constructor.\n */\n public readonly serviceId: string;\n\n /**\n * The deployment target role identifier.\n */\n public readonly deploymentTargetRole: string;\n\n /**\n * Repository name used in resource tagging.\n */\n public readonly repoName: string;\n\n /**\n * Application name identifier.\n */\n public readonly appName: string;\n\n /**\n * Default release branch name.\n */\n public readonly defaultReleaseBranch: string;\n\n /**\n * Branch name used when calculating resource names and hashes.\n */\n public readonly branchName: string;\n\n /**\n * Short hash unique to the deployment target (app name, deployment target role, account, region).\n */\n public readonly environmentHash: string;\n\n /**\n * Short hash unique to the environment and branch combination.\n */\n public readonly branchHash: string;\n\n /**\n * Short hash unique to the specific stack/service.\n */\n public readonly stackHash: string;\n\n /**\n * The removal policy for persistent stack resources.\n */\n public readonly removalPolicy: RemovalPolicy;\n\n /**\n * Environment configuration for this service.\n * This is either the value passed in or the default config\n */\n public readonly config: OpenHiEnvironmentConfig;\n\n /**\n * Service type identifier. Override in subclasses to return the class's static SERVICE_TYPE.\n * Used for parameter names, tags, and service discovery.\n */\n abstract get serviceType(): OpenHiServiceType | string;\n\n /**\n * Creates a new OpenHI service stack.\n *\n * @param ohEnv - The OpenHI environment (stage) this service belongs to\n * @param id - Unique identifier for this service stack (e.g., \"user-service\")\n * @param props - Optional properties for configuring the service\n *\n * @throws {Error} If account and region are not defined in props or environment\n *\n */\n constructor(\n public ohEnv: OpenHiEnvironment,\n id: string,\n public props: OpenHiServiceProps = {},\n ) {\n // Determine the account and region based on environment or user passed props.\n // This must be done before calling super() as it's needed for stack naming.\n const { account, region } = props.env || ohEnv;\n if (!account || !region) {\n throw new Error(\n \"Account and region must be defined in OpenHiServiceProps or OpenHiEnvironment\",\n );\n }\n\n // Get app name from the app in the hierarchy (via environment -> stage -> app)\n const appName = props.appName ?? ohEnv.ohStage.ohApp.appName ?? \"openhi\";\n\n // Initialize deployment context properties\n // Repo name is used in tagging. This tag value is important for tracking\n // when tearing preview stacks back down. If not provided, detect from git.\n const repoName = props.repoName ?? findGitRepoName();\n\n // Default release branch is used when not in dev stage. Defaults to \"main\" if not provided.\n const defaultReleaseBranch = props.defaultReleaseBranch ?? \"main\";\n\n // Branch name is used to calculate hashes and names for resources.\n // Detection logic:\n // - If explicitly provided, use that value\n // - If Jest is running, use \"test-branch\" to avoid snapshot test issues\n // - If GIT_BRANCH_NAME env is set (e.g. by CI), use it\n // - If in dev stage, detect from git using findGitBranch()\n // - Otherwise (stage/prod), default to defaultReleaseBranch\n const branchName =\n props.branchName ??\n (process.env.JEST_WORKER_ID\n ? \"test-branch\"\n : process.env.GIT_BRANCH_NAME?.trim() ||\n (ohEnv.ohStage.stageType === OPEN_HI_STAGE.DEV\n ? findGitBranch()\n : defaultReleaseBranch));\n\n // Compute environment hash: unique to deployment target (app name, role, account, region)\n // Mainly used for DNS names and deployment-target-scoped resources\n const environmentHash = hashString(\n [appName, ohEnv.deploymentTargetRole, account, region].join(\"-\"),\n 6,\n );\n\n // Compute branch hash: unique to deployment target and branch combination\n // Useful for resources shared across stacks within the same branch\n const branchHash = hashString(\n [appName, ohEnv.deploymentTargetRole, account, region, branchName].join(\n \"-\",\n ),\n 6,\n );\n\n // Compute stack hash: unique to the specific stack/service\n // Useful for stack-specific resources like S3 buckets, KMS key aliases\n // This ensures two PR builds or different services don't collide\n const stackHash = hashString(\n [\n appName,\n ohEnv.deploymentTargetRole,\n account,\n region,\n branchName,\n id,\n ].join(\"-\"),\n 6,\n );\n\n // Set the removal policy for this stack based on the deployment target role.\n // Production stages retain resources, others destroy them on stack deletion.\n const removalPolicy =\n props.removalPolicy ??\n (ohEnv.ohStage.stageType === OPEN_HI_STAGE.PROD\n ? RemovalPolicy.RETAIN\n : RemovalPolicy.DESTROY);\n Object.assign(props, { removalPolicy });\n\n // Description to use for the stack and all resources within it.\n // Includes service ID, branch name, and hash for easy identification.\n const description = `OpenHi Service: ${id} [${branchName}] - ${branchHash}`;\n\n // Call the super constructor of Stack.\n // This initializes the AWS CDK Stack with:\n // - Scope: the OpenHI environment\n // - ID: unique stack name including branch hash\n // - Props: stack properties including description and removal policy\n super(ohEnv, [branchHash, id, account, region].join(\"-\"), {\n ...props,\n description,\n });\n\n // Store the service ID for use in deployment context and other operations.\n this.serviceId = id;\n\n // Set the removal policy for this stack based on the deployment target role.\n this.removalPolicy = removalPolicy;\n\n /**\n * Explicit config or use the environment config as a backup,\n */\n this.config = props.config ?? ohEnv.props.config;\n\n // Initialize deployment context properties directly on the service\n this.deploymentTargetRole = ohEnv.deploymentTargetRole;\n this.repoName = repoName;\n this.appName = appName;\n this.defaultReleaseBranch = defaultReleaseBranch;\n this.branchName = branchName;\n this.environmentHash = environmentHash;\n this.branchHash = branchHash;\n this.stackHash = stackHash;\n\n // Pre-populate the AZ context cache for this stack so any construct that\n // calls `stack.availabilityZones` (notably RDS DatabaseCluster, ELBs, and\n // anything else that fans out across AZs) gets concrete values without\n // triggering a CDK context lookup. Without this, CI synth records the\n // lookup as \"missing\" and deploy fails because the GitHubOpenHiDeployer\n // role can't assume `cdk-…-lookup-role-…` (only granted to dev machines\n // by default). AZ names follow the stable `<region>a/b/c…` pattern across\n // all current commercial AWS regions; if a deployment ever targets a\n // region where this assumption breaks, override here per region.\n this.node.setContext(\n `availability-zones:account=${account}:region=${region}`,\n [`${region}a`, `${region}b`, `${region}c`],\n );\n\n // Standard tagging across all resources in the stack.\n // Use id (the service type string passed to super) since abstract serviceType cannot be accessed in constructor.\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_REPO_NAME),\n repoName.slice(0, 255),\n );\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_BRANCH_NAME),\n branchName.slice(0, 255),\n );\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_SERVICE_TYPE),\n id.slice(0, 255),\n );\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_STAGE_TYPE),\n ohEnv.ohStage.stageType.slice(0, 255),\n );\n }\n\n /**\n * DNS prefix for this branche's child zone.\n */\n public get childZonePrefix(): string {\n return paramCase(this.branchName).slice(0, 200);\n }\n}\n","import {\n Certificate,\n CertificateProps,\n} from \"aws-cdk-lib/aws-certificatemanager\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/acm/root-wildcard-certificate.md\n */\n\nexport class RootWildcardCertificate extends Certificate {\n /**\n * Used when storing the Certificate ARN in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"ROOT_WILDCARD_CERT_ARN\";\n\n /**\n * Using a special name here since this will be shared and used among many\n * stacks and services. Use with OpenHiGlobalService.rootWildcardCertificateFromConstruct.\n */\n public static ssmParameterName(): string {\n return (\n \"/\" +\n [\"GLOBAL\", RootWildcardCertificate.SSM_PARAM_NAME].join(\"/\").toUpperCase()\n );\n }\n\n constructor(scope: Construct, props: CertificateProps) {\n super(scope, \"root-wildcard-certificate\", { ...props });\n\n /**\n * Generate the SSM Parameter used to store this Certificate's ARN.\n */\n new StringParameter(this, \"wildcard-cert-param\", {\n parameterName: RootWildcardCertificate.ssmParameterName(),\n stringValue: this.certificateArn,\n });\n }\n}\n","import { HttpApi, HttpApiProps } from \"aws-cdk-lib/aws-apigatewayv2\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/api-gateway/root-http-api.md\n */\n\nexport interface RootHttpApiProps extends HttpApiProps {}\n\nexport class RootHttpApi extends HttpApi {\n /**\n * Used when storing the API ID in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"ROOT_HTTP_API\";\n\n constructor(scope: Construct, props: RootHttpApiProps = {}) {\n const stack = OpenHiService.of(scope) as OpenHiService;\n\n const origins = props.corsPreflight?.allowOrigins;\n if (origins?.length) {\n const withTrailingSlash = origins.filter((o) => o.endsWith(\"/\"));\n if (withTrailingSlash.length > 0) {\n throw new Error(\n `CORS allowOrigins must not include a trailing slash. The browser Origin header is scheme + host + port only (no path), so API Gateway will not match origins like \"https://example.com/\" and CORS can fail. Invalid: ${withTrailingSlash.join(\", \")}. Use e.g. \"https://example.com\" instead.`,\n );\n }\n }\n\n super(scope, \"http-api\", {\n /**\n * User provided props\n */\n ...props,\n\n /**\n * Required\n */\n apiName: [\"root\", \"http\", \"api\", stack.branchHash].join(\"-\"),\n });\n }\n}\n","import {\n Definition,\n GraphqlApi,\n GraphqlApiProps,\n IGraphqlApi,\n} from \"aws-cdk-lib/aws-appsync\";\nimport { CodeFirstSchema, GraphqlType, ObjectType } from \"awscdk-appsync-utils\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\nimport { DiscoverableStringParameter } from \"../ssm\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/app-sync/root-graphql-api.md\n */\n\nexport interface RootGraphqlApiProps extends GraphqlApiProps {}\n\nexport class RootGraphqlApi extends GraphqlApi {\n /**\n * Used when storing the GraphQl API ID in SSM\n */\n public static readonly SSM_PARAM_NAME = \"ROOT_GRAPHQL_API\";\n\n public static fromConstruct(scope: Construct): IGraphqlApi {\n const graphqlApiId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: RootGraphqlApi.SSM_PARAM_NAME,\n serviceType: \"graphql-api\",\n });\n\n return GraphqlApi.fromGraphqlApiAttributes(scope, \"root-graphql-api\", {\n graphqlApiId,\n });\n }\n\n constructor(scope: Construct, props?: Omit<RootGraphqlApiProps, \"name\">) {\n const stack = OpenHiService.of(scope) as OpenHiService;\n\n const schema = new CodeFirstSchema();\n schema.addType(\n new ObjectType(\"Query\", {\n definition: { HelloWorld: GraphqlType.string() },\n }),\n );\n\n super(scope, \"root-graphql-api\", {\n /**\n * Defaults\n */\n queryDepthLimit: 2,\n resolverCountLimit: 50,\n definition: Definition.fromSchema(schema),\n\n /**\n * Overrideable props\n */\n ...props,\n\n /**\n * Required\n */\n name: [\"root\", \"graphql\", \"api\", stack.branchHash].join(\"-\"),\n });\n\n /**\n * Generate the SSM Parameter used to store this GraphQL API's ID.\n */\n new DiscoverableStringParameter(this, \"graphql-api-param\", {\n ssmParamName: RootGraphqlApi.SSM_PARAM_NAME,\n serviceType: \"graphql-api\",\n stringValue: this.apiId,\n });\n }\n}\n","import { Tags } from \"aws-cdk-lib\";\nimport {\n StringParameter,\n type StringParameterProps,\n} from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/ssm/discoverable-string-parameter.md\n */\n\n/*******************************************************************************\n *\n * DiscoverableStringParameterProps: props for creating or looking up SSM\n * parameters. Includes StringParameterProps (minus parameterName) plus\n * name-building fields used by buildParameterName.\n *\n ******************************************************************************/\n\nexport interface DiscoverableStringParameterProps extends Omit<\n StringParameterProps,\n \"parameterName\"\n> {\n /**\n * SSM param name used to build the SSM parameter name via buildParameterName\n * and stored as a tag on the parameter for discoverability.\n */\n readonly ssmParamName: string;\n\n /**\n * The environment hash the parameter belongs to.\n * @default - the current stack's environment hash\n */\n readonly branchHash?: string;\n\n /**\n * The service type the parameter belongs to.\n * @default - the current stack's service type\n */\n readonly serviceType?: string;\n\n /**\n * The AWS account the parameter belongs to.\n * @default - the current stack's account\n */\n readonly account?: string;\n\n /**\n * The AWS region the parameter belongs to.\n * @default - the current stack's region\n */\n readonly region?: string;\n}\n\n/**\n * Props for buildParameterName and valueForLookupName.\n * Includes ssmParamName (required) and optional overrides (branchHash, serviceType, account, region).\n */\nexport type BuildParameterNameProps = Pick<\n DiscoverableStringParameterProps,\n \"ssmParamName\" | \"branchHash\" | \"serviceType\" | \"account\" | \"region\"\n>;\n\n/**\n * Discoverable SSM string parameter construct. Extends CDK StringParameter:\n * builds parameterName from the given name via buildParameterName and tags\n * the parameter with the name constant.\n */\nexport class DiscoverableStringParameter extends StringParameter {\n /**\n * Version of the parameter name format / discoverability schema.\n * Bump when buildParameterName or tagging semantics change.\n * Also used to drive replacement of parameters during CloudFormation deploys.\n */\n public static readonly version = \"v1\";\n\n /**\n * Build a param name based on predictable attributes found in services and\n * constructs. Used for storage and retrieval of SSM values across services.\n */\n public static buildParameterName(\n scope: Construct,\n props: BuildParameterNameProps,\n ): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return (\n \"/\" +\n [\n DiscoverableStringParameter.version,\n props.branchHash ?? stack.branchHash,\n props.serviceType ?? stack.serviceType,\n props.account ?? stack.account,\n props.region ?? stack.region,\n props.ssmParamName,\n ]\n .join(\"/\")\n .toUpperCase()\n );\n }\n\n /**\n * Read the string value of an SSM parameter created with DiscoverableStringParameter,\n * using props that include ssmParamName and optional overrides (e.g. serviceType).\n */\n public static valueForLookupName(\n scope: Construct,\n props: BuildParameterNameProps,\n ): string {\n const paramName = DiscoverableStringParameter.buildParameterName(\n scope,\n props,\n );\n return StringParameter.valueForStringParameter(scope, paramName);\n }\n\n constructor(\n scope: Construct,\n id: string,\n props: DiscoverableStringParameterProps,\n ) {\n const { ssmParamName, branchHash, serviceType, account, region, ...rest } =\n props;\n\n const parameterName = DiscoverableStringParameter.buildParameterName(\n scope,\n props,\n );\n\n super(scope, id + \"-\" + DiscoverableStringParameter.version, {\n ...rest,\n parameterName,\n });\n\n const { appName } = OpenHiService.of(scope) as OpenHiService;\n Tags.of(this).add(`${appName}:param-name`, ssmParamName);\n }\n}\n","import { Duration } from \"aws-cdk-lib\";\nimport {\n IUserPool,\n UserPoolClient,\n UserPoolClientProps,\n} from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\n\nexport interface CognitoFixtureSeederClientProps extends Partial<\n Omit<UserPoolClientProps, \"userPool\" | \"generateSecret\">\n> {\n readonly userPool: IUserPool;\n}\n\n/**\n * Dedicated Cognito app client for the OpenHI fixture-seeder CLI\n * (`@openhi/seed-fixtures`).\n *\n * Why a dedicated client (vs reusing the SPA client):\n * - Tightly scoped: only the seeder consumes tokens issued here, so an\n * audit trail of seeder activity is cleanly separable.\n * - Decoupled from the SPA client's OAuth flows — no risk of breaking\n * web-app sign-in by tweaking auth-flow settings here.\n * - Stage-conditional creation upstream (only provisioned in non-prod\n * environments) means prod stacks never carry a code path that could\n * issue a fixture-seeder token in the first place.\n *\n * Why USER_PASSWORD_AUTH (vs M2M client-credentials):\n * - Cognito's M2M tier has a per-app-client monthly fee plus per-token\n * activity charges. For sporadic non-prod fixture runs the per-client\n * fee dominates the bill, especially if every dev branch spins up\n * its own auth stack.\n * - USER_PASSWORD_AUTH against a service `fixture-seeder` user keeps\n * the cost in MAU territory (free under the 50K MAU tier).\n * - Tradeoff: passwords need rotation and the service user must be\n * provisioned per non-prod environment (manual or scripted post-deploy).\n *\n * No client secret (`generateSecret: false`): USER_PASSWORD_AUTH\n * authenticates with the password directly; a secret would just add\n * another credential to manage without strengthening anything.\n */\nexport class CognitoFixtureSeederClient extends UserPoolClient {\n /**\n * SSM parameter name suffix used to publish this client's ID for\n * cross-stack lookups. Built into a full parameter name via\n * `buildParameterName` with `serviceType` AUTH (since the auth stack\n * owns this resource).\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_FIXTURE_SEEDER_CLIENT\";\n\n constructor(scope: Construct, props: CognitoFixtureSeederClientProps) {\n const { userPool, ...rest } = props;\n super(scope, \"fixture-seeder-client\", {\n userPool,\n generateSecret: false,\n authFlows: {\n userPassword: true,\n },\n // No OAuth flows — the seeder calls Cognito's `InitiateAuth`\n // directly with USER_PASSWORD_AUTH, not through the hosted-UI\n // OAuth grant flows the SPA client uses. `disableOAuth: true`\n // causes CDK to omit `AllowedOAuthFlowsUserPoolClient` entirely;\n // passing an empty `oAuth` block instead still flips that flag on\n // and Cognito rejects the create call for missing flows/scopes.\n disableOAuth: true,\n // Short-lived tokens: a seeder run takes seconds, not hours.\n // 1h access-token validity is the minimum Cognito permits and is\n // plenty for a fixture run.\n accessTokenValidity: Duration.hours(1),\n idTokenValidity: Duration.hours(1),\n refreshTokenValidity: Duration.days(1),\n preventUserExistenceErrors: true,\n ...rest,\n });\n }\n}\n","import {\n FeaturePlan,\n UserPool,\n UserPoolProps,\n VerificationEmailStyle,\n} from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool.md\n */\n\nexport class CognitoUserPool extends UserPool {\n /**\n * Used when storing the User Pool ID in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL\";\n\n constructor(scope: Construct, props: UserPoolProps = {}) {\n const service = OpenHiService.of(scope) as OpenHiService;\n\n super(scope, \"user-pool\", {\n /**\n * Defaults\n */\n selfSignUpEnabled: true,\n signInAliases: {\n email: true,\n },\n userVerification: {\n emailSubject: \"Verify your email!\",\n emailBody: \"Your verification code is {####}.\",\n emailStyle: VerificationEmailStyle.CODE,\n },\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n // Plus is required for access-token V2 claim customization in the\n // pre-token-generation Lambda. Essentials silently drops\n // claimsAndScopeOverrideDetails.accessTokenGeneration.claimsToAddOrOverride.\n featurePlan: FeaturePlan.PLUS,\n\n /**\n * Over-rideable props\n */\n ...props,\n\n /**\n * Required\n */\n userPoolName: [\"cognito\", \"user\", \"pool\", service.branchHash].join(\"-\"),\n });\n }\n}\n","import { UserPoolClient, UserPoolClientProps } from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool-client.md\n */\n\nexport class CognitoUserPoolClient extends UserPoolClient {\n /**\n * Used when storing the User Pool Client ID in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL_CLIENT\";\n\n constructor(scope: Construct, props: UserPoolClientProps) {\n super(scope, \"user-pool-client\", {\n /**\n * Defaults\n */\n generateSecret: false,\n oAuth: {\n flows: {\n authorizationCodeGrant: true,\n implicitCodeGrant: true,\n },\n callbackUrls: [`https://localhost:3000/oauth/callback`],\n },\n\n /**\n * Overrideable props\n */\n ...props,\n });\n }\n}\n","import { UserPoolDomain, UserPoolDomainProps } from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool-domain.md\n */\n\nexport class CognitoUserPoolDomain extends UserPoolDomain {\n /**\n * Used when storing the User Pool Domain in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL_DOMAIN\";\n\n constructor(scope: Construct, props: UserPoolDomainProps) {\n /**\n * This supports both custom and native Cognito domains, but we need to\n * name them uniquely so that swap outs work and don't cause conflicts\n * when cloudformation does it's deploy.\n */\n const id = props.cognitoDomain?.domainPrefix\n ? \"cognito-domain\"\n : \"custom-domain\";\n\n super(scope, id, {\n ...props,\n });\n }\n}\n","import { Key, KeyProps } from \"aws-cdk-lib/aws-kms\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool-kms-key.md\n */\n\nexport class CognitoUserPoolKmsKey extends Key {\n /**\n * Used when storing the KMS Key in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL_KMS_KEY\";\n\n constructor(scope: Construct, props: KeyProps = {}) {\n const service = OpenHiService.of(scope) as OpenHiService;\n\n super(scope, \"kms-key\", {\n ...props,\n // alias: [\"alias\", \"cognito\", service.branchHash].join(\"/\"),\n description: `KMS Key for Cognito User Pool - ${service.branchHash}`,\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/post-authentication-lambda.md\n */\n\nconst HANDLER_NAME = \"post-authentication.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\n/**\n * Lambda used as Cognito Post Authentication trigger.\n */\nexport class PostAuthenticationLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct) {\n super(scope, \"post-authentication-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/post-confirmation-lambda.md\n */\n\nconst HANDLER_NAME = \"post-confirmation.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nconst resolveHandlerEntry = (dirname: string): string => {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n};\n\nexport interface PostConfirmationLambdaProps {\n /**\n * Control-plane EventBridge bus name. Passed to the Lambda as\n * CONTROL_EVENT_BUS_NAME so it can publish onboarding workflow events.\n */\n readonly controlEventBusName: string;\n}\n\n/**\n * Lambda used as Cognito Post Confirmation trigger. It publishes a control\n * event and returns quickly; workflow Lambdas own provisioning.\n */\nexport class PostConfirmationLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, props: PostConfirmationLambdaProps) {\n super(scope, \"post-confirmation-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n CONTROL_EVENT_BUS_NAME: props.controlEventBusName,\n },\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/pre-token-generation-lambda.md\n */\n\nconst HANDLER_NAME = \"pre-token-generation.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\nexport interface PreTokenGenerationLambdaProps {\n /**\n * DynamoDB data store table name. Passed to the Lambda as DYNAMO_TABLE_NAME\n * so the control-plane ElectroDB service reads the User by Cognito `sub`\n * (GSI2) and the user's first active Membership (fallback path).\n */\n readonly dynamoTableName: string;\n}\n\n/**\n * Lambda used as Cognito Pre Token Generation trigger. Resolves the OpenHI\n * User from the request's Cognito `sub` and injects `ohi_tid`, `ohi_wid`,\n * `ohi_uid`, `ohi_uname` into both the ID token and the access token\n * (ADR 2026-03-17-01).\n */\nexport class PreTokenGenerationLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, props: PreTokenGenerationLambdaProps) {\n super(scope, \"pre-token-generation-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n DYNAMO_TABLE_NAME: props.dynamoTableName,\n },\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration, RemovalPolicy, Size } from \"aws-cdk-lib\";\nimport * as events from \"aws-cdk-lib/aws-events\";\nimport * as kinesis from \"aws-cdk-lib/aws-kinesis\";\nimport * as kinesisfirehose from \"aws-cdk-lib/aws-kinesisfirehose\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport * as s3 from \"aws-cdk-lib/aws-s3\";\nimport { Construct } from \"constructs\";\n\nconst HANDLER_NAME = \"firehose-archive-transform.handler.js\";\n\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n return path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface DataStoreHistoricalArchiveProps {\n /**\n * Kinesis stream that receives DynamoDB item-level changes (table Kinesis destination).\n */\n readonly kinesisStream: kinesis.IStream;\n /**\n * Removal policy for the archive bucket and related resources.\n */\n readonly removalPolicy: RemovalPolicy;\n /**\n * Short hash for unique stream/bucket naming within the deployment.\n */\n readonly stackHash: string;\n /**\n * When set, the Firehose transform Lambda publishes qualifying changes to\n * this bus via PutEvents (ADR 2026-03-02-01).\n */\n readonly dataEventBus?: events.IEventBus;\n}\n\n/**\n * DynamoDB change stream → Kinesis → Firehose → S3 with a transform Lambda for\n * scope filtering and dynamic partitioning (ADR 2026-03-11-02). The same Lambda\n * publishes qualifying current-resource changes to the data event bus (ADR 2026-03-02-01)\n * when {@link DataStoreHistoricalArchiveProps.dataEventBus} is set.\n */\nexport class DataStoreHistoricalArchive extends Construct {\n public readonly archiveBucket: s3.Bucket;\n /**\n * Receives PutEvents payloads that still fail after in-Lambda retries when\n * {@link DataStoreHistoricalArchiveProps.dataEventBus} is configured.\n */\n public readonly putEventsFailureDlqBucket?: s3.Bucket;\n public readonly deliveryStream: kinesisfirehose.IDeliveryStream;\n public readonly transformFunction: NodejsFunction;\n\n constructor(\n scope: Construct,\n id: string,\n props: DataStoreHistoricalArchiveProps,\n ) {\n super(scope, id);\n\n this.archiveBucket = new s3.Bucket(this, \"ArchiveBucket\", {\n blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,\n encryption: s3.BucketEncryption.S3_MANAGED,\n enforceSSL: true,\n removalPolicy: props.removalPolicy,\n autoDeleteObjects: props.removalPolicy === RemovalPolicy.DESTROY,\n versioned: true,\n });\n\n const putEventsFailureDlqBucket = props.dataEventBus\n ? new s3.Bucket(this, \"PutEventsFailureDlq\", {\n blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,\n encryption: s3.BucketEncryption.S3_MANAGED,\n enforceSSL: true,\n removalPolicy: props.removalPolicy,\n autoDeleteObjects: props.removalPolicy === RemovalPolicy.DESTROY,\n versioned: false,\n })\n : undefined;\n this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;\n\n this.transformFunction = new NodejsFunction(this, \"FirehoseTransform\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n description:\n \"Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents\",\n environment:\n props.dataEventBus && putEventsFailureDlqBucket\n ? {\n DATA_EVENT_BUS_NAME: props.dataEventBus.eventBusName,\n DATA_STORE_PUT_EVENTS_DLQ_BUCKET:\n putEventsFailureDlqBucket.bucketName,\n }\n : undefined,\n bundling: {\n minify: true,\n sourceMap: false,\n },\n });\n\n props.dataEventBus?.grantPutEventsTo(this.transformFunction);\n putEventsFailureDlqBucket?.grantPut(this.transformFunction);\n\n const processor = new kinesisfirehose.LambdaFunctionProcessor(\n this.transformFunction,\n {\n bufferInterval: Duration.seconds(60),\n bufferSize: Size.mebibytes(3),\n retries: 3,\n },\n );\n\n const destination = new kinesisfirehose.S3Bucket(this.archiveBucket, {\n compression: kinesisfirehose.Compression.GZIP,\n bufferingInterval: Duration.seconds(300),\n // Firehose requires SizeInMBs ≥ 64 when dynamic partitioning is enabled.\n bufferingSize: Size.mebibytes(64),\n processors: [processor],\n errorOutputPrefix:\n \"errors/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd/HH}/\",\n loggingConfig: new kinesisfirehose.EnableLogging(),\n });\n\n this.deliveryStream = new kinesisfirehose.DeliveryStream(\n this,\n \"ArchiveDeliveryStream\",\n {\n deliveryStreamName: `openhi-dstore-arch-${props.stackHash}`,\n source: new kinesisfirehose.KinesisStreamSource(props.kinesisStream),\n destination,\n },\n );\n\n const cfn = this.deliveryStream.node\n .defaultChild as kinesisfirehose.CfnDeliveryStream;\n cfn.addPropertyOverride(\n \"ExtendedS3DestinationConfiguration.DynamicPartitioningConfiguration\",\n {\n Enabled: true,\n RetryOptions: { DurationInSeconds: 300 },\n },\n );\n cfn.addPropertyOverride(\n \"ExtendedS3DestinationConfiguration.Prefix\",\n \"!{partitionKeyFromLambda:tenantId}/!{partitionKeyFromLambda:workspaceId}/!{partitionKeyFromLambda:resourceType}/!{partitionKeyFromLambda:resourceId}/!{partitionKeyFromLambda:version}/\",\n );\n }\n}\n","import { RemovalPolicy } from \"aws-cdk-lib\";\nimport {\n AttributeType,\n BillingMode,\n ProjectionType,\n Table,\n TableProps,\n} from \"aws-cdk-lib/aws-dynamodb\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/dynamodb/dynamo-db-data-store.md\n */\n\n/**\n * DynamoDB table name for the data store. Used for cross-stack reference and\n * deterministic naming per branch. The table backs the app data store.\n */\nexport function getDynamoDbDataStoreTableName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `data-store-${stack.branchHash}`;\n}\n\nexport interface DynamoDbDataStoreProps extends Omit<\n TableProps,\n \"tableName\" | \"removalPolicy\"\n> {\n /**\n * Optional removal policy override. If not set, uses the service's default\n * removal policy (RETAIN for prod, DESTROY otherwise).\n */\n readonly removalPolicy?: RemovalPolicy;\n}\n\n/**\n * DynamoDB table implementing the single-table design for app data (FHIR\n * resources data plane and platform control plane), per planning ADR-011 and\n * DR-004.\n *\n * @see {@link https://github.com/codedrifters/openhi/blob/main/sites/www-docs/content/architecture/dynamodb-single-table-design.md | DynamoDB Single-Table Design}\n *\n * Primary key: PK (String), SK (String).\n *\n * GSIs:\n * - **GSI1 — Unified Sharded List** (`GSI1PK`/`GSI1SK`, INCLUDE projection per\n * DR-004). Primary list/lookup index for both data-plane FHIR resources and\n * control-plane entities (User, Tenant, Workspace, Membership, Role,\n * RoleAssignment, Configuration). PK shape:\n * `TID#<tid>#WID#<wid>#RT#<Type>#SHARD#<n>` with 4 shards\n * (`n = hash(id) mod 4`). SK shape per `extractSortKey`: labeled types use\n * `<normalizedLabel>#<id>`; unlabeled use `<ISO-8601 lastUpdated>#<id>`.\n * - **GSI2 — Sub-Lookup** (`GSI2PK`/`GSI2SK`, INCLUDE projection). Resolves\n * `UserEntity` from a Cognito `sub` for the Pre Token Generation Lambda.\n * PK shape: `USER#SUB#<cognitoSub>`. SK shape: `CURRENT`.\n *\n * For historical archive to S3, pass `kinesisStream` and `stream` (e.g.\n * `StreamViewType.NEW_AND_OLD_IMAGES`) on the table props per ADR 2026-03-11-02.\n */\nexport class DynamoDbDataStore extends Table {\n constructor(\n scope: Construct,\n id: string,\n props: DynamoDbDataStoreProps = {},\n ) {\n const service = OpenHiService.of(scope) as OpenHiService;\n\n super(scope, id, {\n ...props,\n tableName: getDynamoDbDataStoreTableName(scope),\n partitionKey: {\n name: \"PK\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"SK\",\n type: AttributeType.STRING,\n },\n billingMode: BillingMode.PAY_PER_REQUEST,\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n });\n\n // GSI1 — Unified Sharded List (data plane + control plane) per ADR-011 and DR-004.\n this.addGlobalSecondaryIndex({\n indexName: \"GSI1\",\n partitionKey: {\n name: \"GSI1PK\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"GSI1SK\",\n type: AttributeType.STRING,\n },\n projectionType: ProjectionType.INCLUDE,\n nonKeyAttributes: [\n \"id\",\n \"summary\",\n \"vid\",\n \"lastUpdated\",\n \"createdDate\",\n \"modifiedDate\",\n \"createdById\",\n \"modifiedById\",\n // ElectroDB filters every query result through `ownsItem`, which\n // verifies `__edb_e__` (entity name) and `__edb_v__` (version) match\n // the entity. Without these projected, every GSI1 query returns 0\n // results — list endpoints silently return empty bundles.\n \"__edb_e__\",\n \"__edb_v__\",\n ],\n });\n\n // GSI2 — Sub-Lookup: Cognito sub → UserEntity (Pre Token Generation Lambda).\n this.addGlobalSecondaryIndex({\n indexName: \"GSI2\",\n partitionKey: {\n name: \"GSI2PK\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"GSI2SK\",\n type: AttributeType.STRING,\n },\n projectionType: ProjectionType.INCLUDE,\n nonKeyAttributes: [\n \"id\",\n \"currentTenant\",\n \"currentWorkspace\",\n \"displayName\",\n // See GSI1 above: ElectroDB's `ownsItem` filter rejects items\n // without these, so any query against GSI2 returns 0 results\n // unless they're projected.\n \"__edb_e__\",\n \"__edb_v__\",\n ],\n });\n }\n}\n","import {\n WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH,\n WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR,\n} from \"@openhi/workflows\";\nimport { Annotations, RemovalPolicy } from \"aws-cdk-lib\";\nimport { AttributeType, BillingMode, Table } from \"aws-cdk-lib/aws-dynamodb\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Function } from \"aws-cdk-lib/aws-lambda\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService, type OpenHiServiceType } from \"../../app\";\nimport { DiscoverableStringParameter } from \"../ssm\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/dynamodb/workflow-dedup-table.md\n */\n\n/**\n * Deterministic table name for the shared workflow dedup table.\n * Mirrors `getDynamoDbDataStoreTableName` naming: `workflow-dedup-${branchHash}`.\n */\nexport function getWorkflowDedupTableName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `workflow-dedup-${stack.branchHash}`;\n}\n\n/** Props for `WorkflowDedupTable`. */\nexport interface WorkflowDedupTableProps {\n /**\n * Optional removal policy override. Defaults to the service's default\n * (RETAIN for prod, DESTROY otherwise).\n */\n readonly removalPolicy?: RemovalPolicy;\n}\n\n/** Options for `WorkflowDedupTable.grantConsumer`. */\nexport interface GrantConsumerOptions {\n /**\n * Override the default TTL applied by the runtime client. The 14-day\n * default lives in `@openhi/workflows`; per-consumer overrides clamp\n * shorter per TR-015. Stored in the consumer's environment so the\n * `WorkflowDedupClient` factory can pick it up.\n */\n readonly defaultTtlSeconds?: number;\n}\n\n/**\n * Shared platform-level dedup table every retryable workflow consumer\n * dedupes against. Provisioned exactly once at the platform stack.\n *\n * Schema (per TR-015):\n * - Partition key `consumerName` (S)\n * - Sort key `sk` (S) — encodes `<eventId>#<attempt>`\n * - TTL attribute `expiresAt` (N, Unix epoch seconds)\n * - On-demand billing\n *\n * @see https://github.com/codedrifters/openhi-planning/blob/main/docs/src/content/docs/requirements/technical-requirements/TR-015-workflow-dedup-table.md\n */\nexport class WorkflowDedupTable extends Construct {\n /** SSM param name (short) used by `DiscoverableStringParameter` for the table name lookup. */\n public static readonly TABLE_NAME_SSM_PARAM_NAME =\n \"workflow-dedup-table-name\";\n /** SSM param name (short) used by `DiscoverableStringParameter` for the table ARN lookup. */\n public static readonly TABLE_ARN_SSM_PARAM_NAME = \"workflow-dedup-table-arn\";\n\n /** Cross-stack lookup for the table name. */\n public static tableNameFromLookup(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME,\n serviceType: WorkflowDedupTable.PUBLISHER_SERVICE_TYPE,\n });\n }\n\n /** Cross-stack lookup for the table ARN. */\n public static tableArnFromLookup(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME,\n serviceType: WorkflowDedupTable.PUBLISHER_SERVICE_TYPE,\n });\n }\n\n /**\n * Cross-stack equivalent of {@link grantConsumer}. Use when the dedup\n * table is on a different stack than the consumer Lambda — the\n * grant resolves the table name + ARN via SSM at synth time, so the\n * consumer stack does not pick up a CloudFormation export dependency\n * on the global stack.\n *\n * Inverts the singleton-guard semantics of `grantConsumer`: there is\n * no synth-time check that the same `consumerName` was registered\n * twice across stacks. Consumer names are agreed by convention\n * (see TR-015); double-registration is operator error caught at\n * design time, not synth time.\n */\n public static grantConsumerFromLookup(\n scope: Construct,\n fn: Function,\n consumerName: string,\n options: GrantConsumerOptions = {},\n ): void {\n WorkflowDedupTable.assertConsumerNameStatic(consumerName);\n const tableName = WorkflowDedupTable.tableNameFromLookup(scope);\n const tableArn = WorkflowDedupTable.tableArnFromLookup(scope);\n\n fn.addEnvironment(WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR, tableName);\n if (options.defaultTtlSeconds !== undefined) {\n fn.addEnvironment(\n \"OPENHI_WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS\",\n String(options.defaultTtlSeconds),\n );\n }\n\n fn.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n ],\n resources: [tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": [consumerName],\n },\n },\n }),\n );\n }\n\n /**\n * Service-type the publishing stack runs under. The cross-stack lookups\n * pin to this value so consumer stacks on a different service-type\n * (e.g. `data`, `auth`) resolve the parameter at the publisher's SSM\n * path instead of their own. Typed against `OpenHiServiceType` so a\n * future rename of the literal triggers a compile error; not pulled\n * from `OpenHiGlobalService.SERVICE_TYPE` because\n * `OpenHiGlobalService` already imports `WorkflowDedupTable` — a\n * back-import would create a circular dependency.\n */\n private static readonly PUBLISHER_SERVICE_TYPE: OpenHiServiceType = \"global\";\n\n /**\n * Standalone consumer-name validator shared by the instance method\n * and `grantConsumerFromLookup` so the two grants enforce identical\n * invariants.\n */\n private static assertConsumerNameStatic(consumerName: string): void {\n if (consumerName.length === 0) {\n throw new WorkflowDedupConsumerNameInvalidError(\n \"consumerName must be non-empty.\",\n );\n }\n if (consumerName.length > WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH) {\n throw new WorkflowDedupConsumerNameInvalidError(\n `consumerName must be at most ${WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH} chars; got ${consumerName.length}.`,\n );\n }\n if (/\\s/.test(consumerName)) {\n throw new WorkflowDedupConsumerNameInvalidError(\n \"consumerName must not contain whitespace.\",\n );\n }\n }\n\n /** The underlying DynamoDB table. */\n public readonly table: Table;\n\n private readonly registeredConsumers = new Set<string>();\n\n constructor(\n scope: Construct,\n id: string,\n props: WorkflowDedupTableProps = {},\n ) {\n super(scope, id);\n\n const service = OpenHiService.of(scope) as OpenHiService;\n\n // Synth-time singleton guard: refuse a second WorkflowDedupTable in\n // the same owning service (one stack per deploy target). The check is\n // intentionally scoped to the host service rather than to the CDK\n // app root: openhi/global/src/app.ts maps over `app.environments` and\n // instantiates one `OpenHiGlobalService` per environment, and each of\n // those is a separate deployment target that owns its own dedup\n // table per TR-015.\n const others = service.node\n .findAll()\n .filter(\n (c): c is WorkflowDedupTable =>\n c instanceof WorkflowDedupTable && c !== this,\n );\n if (others.length > 0) {\n throw new WorkflowDedupTableDuplicateError(\n `WorkflowDedupTable already exists at ${others[0].node.path}; ` +\n \"only one shared dedup table is allowed per service stack (TR-015).\",\n );\n }\n\n this.table = new Table(this, \"Table\", {\n tableName: getWorkflowDedupTableName(scope),\n partitionKey: {\n name: \"consumerName\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"sk\",\n type: AttributeType.STRING,\n },\n billingMode: BillingMode.PAY_PER_REQUEST,\n timeToLiveAttribute: \"expiresAt\",\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n });\n\n // Publish the table name and ARN so consumer stacks can discover\n // them without a cross-stack prop dependency.\n new DiscoverableStringParameter(this, \"table-name-param\", {\n ssmParamName: WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME,\n stringValue: this.table.tableName,\n });\n new DiscoverableStringParameter(this, \"table-arn-param\", {\n ssmParamName: WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME,\n stringValue: this.table.tableArn,\n });\n }\n\n /**\n * Wire a Lambda consumer to this table. Injects the table-name env var\n * so the runtime `WorkflowDedupClient` can resolve it, then attaches a\n * per-consumer IAM grant scoped by `dynamodb:LeadingKeys` so the\n * consumer can only read/write its own partition.\n */\n public grantConsumer(\n fn: Function,\n consumerName: string,\n options: GrantConsumerOptions = {},\n ): void {\n this.assertConsumerName(consumerName);\n\n if (this.registeredConsumers.has(consumerName)) {\n Annotations.of(this).addWarning(\n `WorkflowDedupTable: consumerName \"${consumerName}\" registered more than once; ` +\n \"subsequent grantConsumer calls add policy statements but do not re-inject the env var.\",\n );\n }\n this.registeredConsumers.add(consumerName);\n\n fn.addEnvironment(WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR, this.table.tableName);\n if (options.defaultTtlSeconds !== undefined) {\n fn.addEnvironment(\n \"OPENHI_WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS\",\n String(options.defaultTtlSeconds),\n );\n }\n\n fn.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n ],\n resources: [this.table.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": [consumerName],\n },\n },\n }),\n );\n }\n\n private assertConsumerName(consumerName: string): void {\n WorkflowDedupTable.assertConsumerNameStatic(consumerName);\n }\n}\n\n/** Thrown when a second `WorkflowDedupTable` is instantiated in the same app. */\nexport class WorkflowDedupTableDuplicateError extends Error {\n /** @param message - human-readable description of the duplicate. */\n constructor(message: string) {\n super(message);\n this.name = \"WorkflowDedupTableDuplicateError\";\n }\n}\n\n/** Thrown when a consumerName violates the TR-015 invariants. */\nexport class WorkflowDedupConsumerNameInvalidError extends Error {\n /** @param message - human-readable description of the invariant violation. */\n constructor(message: string) {\n super(message);\n this.name = \"WorkflowDedupConsumerNameInvalidError\";\n }\n}\n","import { EventBus, EventBusProps } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/event-bridge/data-event-bus.md\n */\n\nexport class DataEventBus extends EventBus {\n /*****************************************************************************\n *\n * Return a name for this EventBus based on the stack environment hash. This\n * name is common across all stacks since it's using the environment hash in\n * it's name.\n *\n ****************************************************************************/\n\n public static getEventBusName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `datav1${stack.branchHash}`;\n }\n\n constructor(scope: Construct, props?: EventBusProps) {\n super(scope, \"data-event-bus-v1\", {\n ...props,\n eventBusName: DataEventBus.getEventBusName(scope),\n });\n }\n}\n","import { EventBus, EventBusProps } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/event-bridge/ops-event-bus.md\n */\n\nexport class OpsEventBus extends EventBus {\n /*****************************************************************************\n *\n * Return a name for this EventBus based on the stack environment hash. This\n * name is common across all stacks since it's using the environment hash in\n * it's name.\n *\n ****************************************************************************/\n\n public static getEventBusName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `opsv1${stack.branchHash}`;\n }\n\n constructor(scope: Construct, props?: EventBusProps) {\n super(scope, \"ops-event-bus-v1\", {\n ...props,\n eventBusName: OpsEventBus.getEventBusName(scope),\n });\n }\n}\n","import { EventBus, EventBusProps } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/event-bridge/control-event-bus.md\n */\n\nexport class ControlEventBus extends EventBus {\n /*****************************************************************************\n *\n * Return a name for this EventBus based on the stack environment hash. This\n * name is common across all stacks since it's using the environment hash in\n * its name.\n *\n ****************************************************************************/\n\n public static getEventBusName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `controlv1${stack.branchHash}`;\n }\n\n constructor(scope: Construct, props?: EventBusProps) {\n super(scope, \"control-event-bus-v1\", {\n ...props,\n eventBusName: ControlEventBus.getEventBusName(scope),\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration, RemovalPolicy, Stack } from \"aws-cdk-lib\";\nimport * as ec2 from \"aws-cdk-lib/aws-ec2\";\nimport * as kinesis from \"aws-cdk-lib/aws-kinesis\";\nimport { Runtime, StartingPosition } from \"aws-cdk-lib/aws-lambda\";\nimport { KinesisEventSource } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport * as rds from \"aws-cdk-lib/aws-rds\";\nimport { Construct } from \"constructs\";\nimport { DiscoverableStringParameter } from \"../ssm/discoverable-string-parameter\";\n\nconst HANDLER_NAME = \"data-store-postgres-replication.handler.js\";\nconst DEFAULT_DATABASE_NAME = \"openhi\";\nconst SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;\n\n/**\n * SSM parameter names that publish the Postgres replica's coordinates so other\n * stacks (notably the REST API stack) can discover them without a direct CDK\n * cross-stack reference. The schema name is intentionally NOT published — it\n * is a deterministic function of `branchHash` and consumers compute it locally\n * via {@link getPostgresReplicaSchemaName}.\n */\nexport const POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME =\n \"POSTGRES_REPLICA_CLUSTER_ARN\";\nexport const POSTGRES_REPLICA_SECRET_ARN_SSM_NAME =\n \"POSTGRES_REPLICA_SECRET_ARN\";\nexport const POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME =\n \"POSTGRES_REPLICA_DATABASE_NAME\";\n\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n return path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\n/**\n * Derive the per-branch Postgres schema name from a branch hash. The `b_`\n * prefix guarantees a leading letter (Postgres identifier rule). Branch hashes\n * are 6 hex chars from {@link OpenHiService.branchHash} so the resulting\n * `b_xxxxxx` is well within the 63-byte identifier limit.\n */\nexport function getPostgresReplicaSchemaName(branchHash: string): string {\n const candidate = `b_${branchHash.toLowerCase()}`;\n if (!SCHEMA_NAME_PATTERN.test(candidate)) {\n throw new Error(\n `Branch hash ${JSON.stringify(branchHash)} produces an invalid Postgres ` +\n `schema name ${JSON.stringify(candidate)}; expected /[a-z_][a-z0-9_]{0,62}/.`,\n );\n }\n return candidate;\n}\n\nexport interface DataStorePostgresReplicaProps {\n /**\n * Kinesis stream that receives DynamoDB item-level changes (the same stream\n * that backs {@link DataStoreHistoricalArchive}). The replication Lambda is\n * registered as a parallel consumer.\n */\n readonly kinesisStream: kinesis.IStream;\n /**\n * Removal policy for the cluster, secret, and dependent resources.\n */\n readonly removalPolicy: RemovalPolicy;\n /**\n * Short hash unique to the stack — used in the cluster identifier.\n */\n readonly stackHash: string;\n /**\n * Short hash unique to the branch — used to derive the per-branch schema\n * name (`b_<branchHash>`) inside the Postgres database.\n */\n readonly branchHash: string;\n /**\n * Optional VPC override. If absent, the construct creates a minimal isolated\n * VPC (2 AZs, no NAT gateways) just for the cluster and replication Lambda.\n */\n readonly vpc?: ec2.IVpc;\n /**\n * Optional database name override.\n * @default \"openhi\"\n */\n readonly databaseName?: string;\n /**\n * Aurora Serverless v2 minimum capacity in ACUs. Defaults to 1 so the\n * writer stays warm — avoids the ~10–20s scale-up wait that a cold\n * (0 ACU) cluster imposes on the next request. Set explicitly to 0 to\n * opt back into scale-to-zero if idle cost becomes the dominant concern.\n */\n readonly minCapacity?: number;\n /**\n * Aurora Serverless v2 maximum capacity in ACUs. Defaults to 2 — adequate\n * for the PoC's replication-only workload.\n */\n readonly maxCapacity?: number;\n}\n\n/**\n * DynamoDB change stream → Postgres replication tier (ADR 2026-04-17-01,\n * phase 1). Provisions an Aurora Serverless v2 PostgreSQL cluster and a\n * Lambda consumer on the existing change-stream that projects each current\n * FHIR resource into a JSONB `resources` table under a per-branch schema.\n *\n * Phase 1 is replication-only; query routing and SearchParameter-specific\n * indexes are intentionally deferred. Per-branch *clusters* (rather than the\n * shared cluster suggested by the ADR) are an explicit PoC simplification —\n * see the ADR's \"Operational notes\" section for the long-term direction.\n *\n * @see sites/www-docs/content/architecture/adr/2026-04-17-01-ad-hoc-query-support-fhir-api.md\n */\nexport class DataStorePostgresReplica extends Construct {\n /**\n * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.\n * Use from any stack that needs to grant `rds-data:ExecuteStatement` against\n * the cluster.\n */\n public static clusterArnFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,\n serviceType: \"data\",\n });\n }\n\n /**\n * Resolve the credentials secret ARN published by an upstream\n * {@link DataStorePostgresReplica}. Use from any stack that needs to grant\n * `secretsmanager:GetSecretValue` against the secret.\n */\n public static secretArnFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,\n serviceType: \"data\",\n });\n }\n\n /**\n * Resolve the database name published by an upstream\n * {@link DataStorePostgresReplica}.\n */\n public static databaseNameFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,\n serviceType: \"data\",\n });\n }\n\n public readonly vpc: ec2.IVpc;\n public readonly cluster: rds.DatabaseCluster;\n public readonly replicationFunction: NodejsFunction;\n public readonly databaseName: string;\n public readonly schemaName: string;\n\n constructor(\n scope: Construct,\n id: string,\n props: DataStorePostgresReplicaProps,\n ) {\n super(scope, id);\n\n this.databaseName = props.databaseName ?? DEFAULT_DATABASE_NAME;\n this.schemaName = getPostgresReplicaSchemaName(props.branchHash);\n\n // Pass explicit AZ names (derived from the stack region) instead of using\n // `maxAzs`, which triggers a CDK availability-zones context lookup. CI's\n // synth step doesn't have full deploy-account creds, so an unresolved AZ\n // lookup gets recorded as \"missing\" in the cdk.out manifest and the deploy\n // step then refuses to proceed. AWS region AZ names follow a stable\n // `<region>a/b/c…` pattern across all current commercial regions.\n const region = Stack.of(this).region;\n this.vpc =\n props.vpc ??\n new ec2.Vpc(this, \"Vpc\", {\n availabilityZones: [`${region}a`, `${region}b`],\n natGateways: 0,\n subnetConfiguration: [\n {\n name: \"isolated\",\n subnetType: ec2.SubnetType.PRIVATE_ISOLATED,\n cidrMask: 24,\n },\n ],\n });\n\n this.cluster = new rds.DatabaseCluster(this, \"Cluster\", {\n clusterIdentifier: `openhi-dstore-pg-${props.stackHash}`,\n engine: rds.DatabaseClusterEngine.auroraPostgres({\n version: rds.AuroraPostgresEngineVersion.VER_16_4,\n }),\n vpc: this.vpc,\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },\n writer: rds.ClusterInstance.serverlessV2(\"writer\"),\n serverlessV2MinCapacity: props.minCapacity ?? 1,\n serverlessV2MaxCapacity: props.maxCapacity ?? 2,\n defaultDatabaseName: this.databaseName,\n credentials: rds.Credentials.fromGeneratedSecret(\"openhi_admin\"),\n storageEncrypted: true,\n removalPolicy: props.removalPolicy,\n // Phase 2 of ADR 2026-04-17-01: the REST API Lambda queries Postgres\n // via the RDS Data API (HTTPS) so it can stay out of the cluster's VPC.\n // Direct `pg` from the replication Lambda continues to work in parallel.\n enableDataApi: true,\n });\n\n this.publishCoordinatesToSsm();\n\n this.replicationFunction = new NodejsFunction(this, \"ReplicationFunction\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n vpc: this.vpc,\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },\n description:\n \"Replicates DynamoDB current-resource changes into the Postgres `resources` JSONB table (ADR 2026-04-17-01).\",\n environment: {\n OPENHI_PG_HOST: this.cluster.clusterEndpoint.hostname,\n OPENHI_PG_PORT: this.cluster.clusterEndpoint.port.toString(),\n OPENHI_PG_DATABASE: this.databaseName,\n OPENHI_PG_SCHEMA: this.schemaName,\n OPENHI_PG_SECRET_ARN: this.cluster.secret!.secretArn,\n OPENHI_PG_SSL: \"true\",\n },\n bundling: {\n minify: true,\n sourceMap: false,\n // pg has conditional/optional deps (pg-native, pg-cloudflare) that\n // historically misbehave when bundled by esbuild; keep it as a real\n // node_module in the Lambda zip instead.\n nodeModules: [\"pg\"],\n },\n });\n\n this.cluster.secret!.grantRead(this.replicationFunction);\n this.cluster.connections.allowDefaultPortFrom(this.replicationFunction);\n\n this.replicationFunction.addEventSource(\n new KinesisEventSource(props.kinesisStream, {\n startingPosition: StartingPosition.LATEST,\n batchSize: 100,\n maxBatchingWindow: Duration.seconds(5),\n retryAttempts: 10,\n bisectBatchOnError: true,\n parallelizationFactor: 2,\n reportBatchItemFailures: true,\n }),\n );\n }\n\n /**\n * Publishes the cluster ARN, secret ARN, and database name as discoverable\n * SSM parameters so the REST API stack (and any future read-side consumer)\n * can wire RDS Data API access without a direct CDK cross-stack reference.\n */\n private publishCoordinatesToSsm(): void {\n new DiscoverableStringParameter(this, \"cluster-arn-param\", {\n ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,\n stringValue: this.cluster.clusterArn,\n description:\n \"ARN of the Aurora Serverless v2 cluster backing the Postgres replication tier (ADR 2026-04-17-01).\",\n });\n new DiscoverableStringParameter(this, \"secret-arn-param\", {\n ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,\n stringValue: this.cluster.secret!.secretArn,\n description:\n \"ARN of the Secrets Manager secret with credentials for the Postgres replication tier.\",\n });\n new DiscoverableStringParameter(this, \"database-name-param\", {\n ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,\n stringValue: this.databaseName,\n description: \"Database name within the Postgres replication cluster.\",\n });\n }\n}\n","import { Duration } from \"aws-cdk-lib\";\nimport {\n HostedZone,\n HostedZoneProps,\n IHostedZone,\n NsRecord,\n} from \"aws-cdk-lib/aws-route53\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/route-53/child-hosted-zone.md\n */\n\nexport interface ChildHostedZoneProps extends HostedZoneProps {\n /**\n * The root zone we will attach this sub-zone to.\n */\n readonly parentHostedZone: IHostedZone;\n}\n\nexport class ChildHostedZone extends HostedZone {\n /**\n * Used when storing the child zone ID in SSM. Use {@link OpenHiGlobalService.childHostedZoneFromConstruct} to look up.\n */\n public static readonly SSM_PARAM_NAME = \"CHILDHOSTEDZONE\";\n\n constructor(scope: Construct, id: string, props: ChildHostedZoneProps) {\n super(scope, id, { ...props });\n\n /**\n * Chain the child zone to the parent zone using NS record.\n */\n new NsRecord(this, \"child-ns-record\", {\n zone: props.parentHostedZone,\n recordName: this.zoneName,\n values: this.hostedZoneNameServers || [],\n ttl: Duration.minutes(5),\n });\n }\n}\n","import { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/route-53/root-hosted-zone.md\n */\n\n/**\n * Placeholder for root hosted zone. Use {@link OpenHiGlobalService.rootHostedZoneFromConstruct}\n * to obtain an IHostedZone from attributes (e.g. from config). The root zone is always\n * created manually and imported via config.\n */\nexport class RootHostedZone extends Construct {}\n","import {\n CachePolicy,\n Distribution,\n type DistributionProps,\n} from \"aws-cdk-lib/aws-cloudfront\";\nimport { S3BucketOrigin } from \"aws-cdk-lib/aws-cloudfront-origins\";\nimport { Bucket, type BucketProps, type IBucket } from \"aws-cdk-lib/aws-s3\";\nimport { Duration } from \"aws-cdk-lib/core\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\nimport { DiscoverableStringParameter } from \"../ssm\";\n\n/**\n * Service type for the website service. Used in SSM parameter paths and by\n * OpenHiWebsiteService for fromConstruct() lookups.\n */\nexport const STATIC_HOSTING_SERVICE_TYPE = \"website\";\n\n/**\n * Props for the StaticHosting construct.\n */\nexport interface StaticHostingProps {\n /**\n * Optional S3 bucket props. Bucket name must not be set statically.\n */\n readonly bucketProps?: Omit<BucketProps, \"bucketName\">;\n\n /**\n * Optional CloudFront distribution props. Do not enable invalidation.\n * Default TTL is 10 seconds via a custom cache policy.\n */\n readonly distributionProps?: Omit<\n DistributionProps,\n \"defaultBehavior\" | \"defaultRootObject\"\n >;\n\n /**\n * Service type for SSM parameter paths.\n * @default STATIC_HOSTING_SERVICE_TYPE (\"website\")\n */\n readonly serviceType?: string;\n}\n\n/**\n * Static hosting: S3 bucket (private) + CloudFront distribution with Origin\n * Access Control (OAC). Stores bucket ARN and distribution ARN in SSM via\n * DiscoverableStringParameter for cross-stack lookup. No cache invalidation;\n * default TTL 10 seconds.\n */\nexport class StaticHosting extends Construct {\n /**\n * SSM parameter name for the S3 bucket ARN.\n */\n public static readonly SSM_PARAM_NAME_BUCKET_ARN =\n \"STATIC_HOSTING_BUCKET_ARN\";\n\n /**\n * SSM parameter name for the CloudFront distribution ARN.\n */\n public static readonly SSM_PARAM_NAME_DISTRIBUTION_ARN =\n \"STATIC_HOSTING_DISTRIBUTION_ARN\";\n\n public readonly bucket: IBucket;\n public readonly distribution: Distribution;\n\n constructor(scope: Construct, id: string, props: StaticHostingProps = {}) {\n super(scope, id);\n\n const stack = OpenHiService.of(scope) as OpenHiService;\n const serviceType = props.serviceType ?? STATIC_HOSTING_SERVICE_TYPE;\n\n this.bucket = new Bucket(this, \"bucket\", {\n blockPublicAccess: {\n blockPublicAcls: true,\n blockPublicPolicy: true,\n ignorePublicAcls: true,\n restrictPublicBuckets: true,\n },\n ...props.bucketProps,\n });\n\n const origin = S3BucketOrigin.withOriginAccessControl(this.bucket);\n\n const cachePolicy = new CachePolicy(this, \"cache-policy\", {\n cachePolicyName: `static-hosting-10s-${stack.branchHash}`,\n comment: \"Low TTL (10s) for static hosting; no invalidation\",\n defaultTtl: Duration.seconds(10),\n minTtl: Duration.seconds(0),\n maxTtl: Duration.seconds(10),\n });\n\n this.distribution = new Distribution(this, \"distribution\", {\n defaultBehavior: {\n origin,\n cachePolicy,\n },\n ...props.distributionProps,\n });\n\n new DiscoverableStringParameter(this, \"bucket-arn-param\", {\n ssmParamName: StaticHosting.SSM_PARAM_NAME_BUCKET_ARN,\n serviceType,\n stringValue: this.bucket.bucketArn,\n });\n\n new DiscoverableStringParameter(this, \"distribution-arn-param\", {\n ssmParamName: StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN,\n serviceType,\n stringValue: this.distribution.distributionArn,\n });\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport {\n IUserPool,\n IUserPoolClient,\n IUserPoolDomain,\n LambdaVersion,\n UserPool,\n UserPoolClient,\n UserPoolDomain,\n UserPoolOperation,\n UserPoolProps,\n} from \"aws-cdk-lib/aws-cognito\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { IKey, Key } from \"aws-cdk-lib/aws-kms\";\nimport { IFunction } from \"aws-cdk-lib/aws-lambda\";\nimport { Stack } from \"aws-cdk-lib/core\";\nimport { Construct } from \"constructs\";\nimport { OpenHiDataService } from \"./open-hi-data-service\";\nimport { OpenHiGlobalService } from \"./open-hi-global-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { CognitoFixtureSeederClient } from \"../components/cognito/cognito-fixture-seeder-client\";\nimport { CognitoUserPool } from \"../components/cognito/cognito-user-pool\";\nimport { CognitoUserPoolClient } from \"../components/cognito/cognito-user-pool-client\";\nimport { CognitoUserPoolDomain } from \"../components/cognito/cognito-user-pool-domain\";\nimport { CognitoUserPoolKmsKey } from \"../components/cognito/cognito-user-pool-kms-key\";\nimport { PostAuthenticationLambda } from \"../components/cognito/post-authentication-lambda\";\nimport { PostConfirmationLambda } from \"../components/cognito/post-confirmation-lambda\";\nimport { PreTokenGenerationLambda } from \"../components/cognito/pre-token-generation-lambda\";\nimport { DiscoverableStringParameter } from \"../components/ssm\";\nimport { UserOnboardingWorkflow } from \"../workflows/control-plane/user-onboarding\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-auth-service.md\n */\n\nexport interface OpenHiAuthServiceProps extends OpenHiServiceProps {\n /**\n * Optional props for the Cognito User Pool.\n */\n readonly userPoolProps?: UserPoolProps;\n}\n\n/**\n * OpenHI Auth Service stack.\n *\n * @remarks\n * The Auth service manages authentication infrastructure including:\n * - Cognito User Pool for user management and authentication\n * - User Pool Client for application integration\n * - User Pool Domain for hosting the Cognito hosted UI\n * - KMS Key for Cognito User Pool encryption\n *\n * Resources are created in protected methods; subclasses may override to customize.\n * Other stacks obtain auth by calling **OpenHiAuthService.userPoolFromConstruct(scope)**,\n * **OpenHiAuthService.userPoolClientFromConstruct(scope)**,\n * **OpenHiAuthService.userPoolDomainFromConstruct(scope)**,\n * and **OpenHiAuthService.userPoolKmsKeyFromConstruct(scope)** for each resource needed.\n *\n * Only one instance of the auth service should exist per environment.\n *\n * @public\n */\nexport class OpenHiAuthService extends OpenHiService {\n static readonly SERVICE_TYPE = \"auth\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.\n */\n static userPoolFromConstruct(scope: Construct): IUserPool {\n const userPoolId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoUserPool.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return UserPool.fromUserPoolId(scope, \"user-pool\", userPoolId);\n }\n\n /**\n * Returns an IUserPoolClient by looking up the Auth stack's User Pool Client ID from SSM.\n */\n static userPoolClientFromConstruct(scope: Construct): IUserPoolClient {\n const userPoolClientId = DiscoverableStringParameter.valueForLookupName(\n scope,\n {\n ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n },\n );\n return UserPoolClient.fromUserPoolClientId(\n scope,\n \"user-pool-client\",\n userPoolClientId,\n );\n }\n\n /**\n * Returns the dedicated fixture-seeder IUserPoolClient by looking up\n * its ID from SSM. Only non-prod auth stacks publish this parameter\n * (per the conditional in {@link createFixtureSeederClient}); calling\n * this against a prod-deployed stack will fail at lookup time.\n *\n * Consumed by `OpenHiRestApiService` (in non-prod) so the authorizer\n * accepts tokens issued by this client, and by the seed-fixtures CLI\n * to drive USER_PASSWORD_AUTH against this client's ID.\n */\n static fixtureSeederClientFromConstruct(scope: Construct): IUserPoolClient {\n const clientId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return UserPoolClient.fromUserPoolClientId(\n scope,\n \"fixture-seeder-client\",\n clientId,\n );\n }\n\n /**\n * Returns an IUserPoolDomain by looking up the Auth stack's User Pool Domain from SSM.\n */\n static userPoolDomainFromConstruct(scope: Construct): IUserPoolDomain {\n const domainName = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return UserPoolDomain.fromDomainName(scope, \"user-pool-domain\", domainName);\n }\n\n /**\n * Returns an IKey (KMS) by looking up the Auth stack's User Pool KMS Key ARN from SSM.\n */\n static userPoolKmsKeyFromConstruct(scope: Construct): IKey {\n const keyArn = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return Key.fromKeyArn(scope, \"kms-key\", keyArn);\n }\n\n get serviceType(): string {\n return OpenHiAuthService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options (e.g. userPoolProps). */\n public override props: OpenHiAuthServiceProps;\n\n public readonly userPoolKmsKey: IKey;\n public readonly preTokenGenerationLambda: IFunction;\n public readonly postAuthenticationLambda: IFunction;\n public readonly postConfirmationLambda: IFunction;\n public readonly userOnboardingWorkflow: UserOnboardingWorkflow;\n public readonly userPool: IUserPool;\n public readonly userPoolClient: IUserPoolClient;\n public readonly userPoolDomain: IUserPoolDomain;\n /**\n * Dedicated USER_PASSWORD_AUTH client for the seed-fixtures CLI.\n * Only created in non-prod environments (see\n * {@link createFixtureSeederClient}). `undefined` in prod.\n */\n public readonly fixtureSeederClient?: IUserPoolClient;\n\n /**\n * Cross-stack reference to the data store table. Cached so repeated\n * lookups share a single CDK construct id (\"dynamo-db-data-store\") in\n * this stack — a second `Table.fromTableName` call under the same scope\n * would collide.\n */\n private _dataStoreTable: ReturnType<\n typeof OpenHiDataService.dynamoDbDataStoreFromConstruct\n > | null = null;\n private _controlEventBus: IEventBus | null = null;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiAuthServiceProps = {}) {\n super(ohEnv, OpenHiAuthService.SERVICE_TYPE, props);\n this.props = props;\n\n this.userPoolKmsKey = this.createUserPoolKmsKey();\n this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();\n this.postAuthenticationLambda = this.createPostAuthenticationLambda();\n this.postConfirmationLambda = this.createPostConfirmationLambda();\n this.userOnboardingWorkflow = this.createUserOnboardingWorkflow();\n this.userPool = this.createUserPool();\n this.grantPreTokenGenerationPermissions();\n this.grantPostAuthenticationPermissions();\n this.grantPostConfirmationPermissions();\n this.userPoolClient = this.createUserPoolClient();\n this.userPoolDomain = this.createUserPoolDomain();\n this.fixtureSeederClient = this.createFixtureSeederClient();\n }\n\n /**\n * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.\n * Look up via {@link OpenHiAuthService.userPoolKmsKeyFromConstruct}.\n * Override to customize.\n */\n protected createUserPoolKmsKey(): IKey {\n const key = new CognitoUserPoolKmsKey(this);\n new DiscoverableStringParameter(this, \"kms-key-param\", {\n ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,\n stringValue: key.keyArn,\n description:\n \"KMS key ARN for Cognito User Pool (e.g. custom sender); cross-stack reference\",\n });\n return key;\n }\n\n /**\n * Creates the Pre Token Generation Lambda (Cognito trigger). On every\n * sign-in and token refresh the Lambda resolves the User by Cognito `sub`\n * (GSI2) and injects `ohi_tid`, `ohi_wid`, `ohi_uid`, `ohi_uname` into\n * both the ID token and the access token (ADR 2026-03-17-01).\n */\n protected createPreTokenGenerationLambda(): IFunction {\n const construct = new PreTokenGenerationLambda(this, {\n dynamoTableName: this.dataStoreTable().tableName,\n });\n return construct.lambda;\n }\n\n /**\n * Creates the Post Authentication Lambda (Cognito trigger). Calls\n * AdminUserGlobalSignOut on every sign-in to enforce single-device-per-user\n * sessions per ADR 2026-03-17-01.\n */\n protected createPostAuthenticationLambda(): IFunction {\n const construct = new PostAuthenticationLambda(this);\n return construct.lambda;\n }\n\n /**\n * Creates the Post Confirmation Lambda (Cognito trigger). On sign-up\n * confirmation, publishes a control-plane workflow event; provisioning lives\n * behind EventBridge.\n */\n protected createPostConfirmationLambda(): IFunction {\n const construct = new PostConfirmationLambda(this, {\n controlEventBusName: this.controlEventBus().eventBusName,\n });\n return construct.lambda;\n }\n\n protected createUserOnboardingWorkflow(): UserOnboardingWorkflow {\n return new UserOnboardingWorkflow(this, {\n controlEventBus: this.controlEventBus(),\n dataStoreTable: this.dataStoreTable(),\n });\n }\n\n private dataStoreTable() {\n if (this._dataStoreTable === null) {\n this._dataStoreTable =\n OpenHiDataService.dynamoDbDataStoreFromConstruct(this);\n }\n return this._dataStoreTable;\n }\n\n private controlEventBus() {\n if (this._controlEventBus === null) {\n this._controlEventBus =\n OpenHiGlobalService.controlEventBusFromConstruct(this);\n }\n return this._controlEventBus;\n }\n\n /**\n * Creates the Cognito User Pool and exports its ID to SSM.\n * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.\n * Override to customize.\n */\n protected createUserPool(): IUserPool {\n const userPool = new CognitoUserPool(this, {\n ...this.props.userPoolProps,\n customSenderKmsKey: this.userPoolKmsKey,\n });\n // Access-token-only claims require Pre Token Generation V2_0.\n userPool.addTrigger(\n UserPoolOperation.PRE_TOKEN_GENERATION_CONFIG,\n this.preTokenGenerationLambda,\n LambdaVersion.V2_0,\n );\n userPool.addTrigger(\n UserPoolOperation.POST_AUTHENTICATION,\n this.postAuthenticationLambda,\n );\n userPool.addTrigger(\n UserPoolOperation.POST_CONFIRMATION,\n this.postConfirmationLambda,\n );\n new DiscoverableStringParameter(this, \"user-pool-param\", {\n ssmParamName: CognitoUserPool.SSM_PARAM_NAME,\n stringValue: userPool.userPoolId,\n description:\n \"Cognito User Pool ID for this Auth stack; cross-stack reference\",\n });\n return userPool;\n }\n\n /**\n * Grants the Pre Token Generation Lambda read-only access on the data\n * store table and its GSIs. The Lambda only needs:\n * - `Query` on GSI2 to resolve a User by Cognito `sub`\n * - `GetItem` on the base table for direct User reads\n *\n * No write or scan access: a User missing `currentTenant`/`currentWorkspace`\n * falls into the absent-claims path; repair belongs in a separate backfill.\n */\n protected grantPreTokenGenerationPermissions(): void {\n const dataStoreTable = this.dataStoreTable();\n const dynamoActions = [\"dynamodb:GetItem\", \"dynamodb:Query\"] as const;\n dataStoreTable.grant(this.preTokenGenerationLambda, ...dynamoActions);\n this.preTokenGenerationLambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [...dynamoActions],\n resources: [`${dataStoreTable.tableArn}/index/*`],\n }),\n );\n }\n\n /**\n * Grants the Post Authentication Lambda permission to call\n * `cognito-idp:AdminUserGlobalSignOut`.\n *\n * Scoped via `Stack.of(this).formatArn` rather than `userPool.userPoolArn`\n * because the User Pool registers this Lambda as a Post Authentication\n * trigger, creating the cycle:\n * userPool → lambda (trigger ARN) → role policy → userPool ARN.\n * Using `formatArn` avoids referencing the User Pool resource directly\n * while still scoping to user pools in this account+region. The Lambda\n * is invoked only by Cognito with a Cognito-provided `event.userPoolId`,\n * so the runtime target is constrained by the trigger contract.\n */\n protected grantPostAuthenticationPermissions(): void {\n this.postAuthenticationLambda.addToRolePolicy(\n new PolicyStatement({\n actions: [\"cognito-idp:AdminUserGlobalSignOut\"],\n resources: [\n Stack.of(this).formatArn({\n service: \"cognito-idp\",\n resource: \"userpool\",\n resourceName: \"*\",\n }),\n ],\n }),\n );\n }\n\n /**\n * Grants the Post Confirmation Lambda publish-only access to the\n * control-plane event bus. Workflow Lambdas own DynamoDB writes.\n */\n protected grantPostConfirmationPermissions(): void {\n this.controlEventBus().grantPutEventsTo(this.postConfirmationLambda);\n }\n\n /**\n * Creates the User Pool Client and exports its ID to SSM (AUTH service type).\n * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.\n * Override to customize.\n */\n protected createUserPoolClient(): IUserPoolClient {\n const client = new CognitoUserPoolClient(this, {\n userPool: this.userPool,\n });\n new DiscoverableStringParameter(this, \"user-pool-client-param\", {\n ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,\n stringValue: client.userPoolClientId,\n description:\n \"Cognito User Pool Client ID for this Auth stack; cross-stack reference\",\n });\n return client;\n }\n\n /**\n * Creates the dedicated USER_PASSWORD_AUTH app client for the\n * `@openhi/seed-fixtures` CLI, **only** in non-prod environments.\n * Returns `undefined` when this stack is being deployed to a prod\n * stage so the prod auth stack carries no fixture-seeder code path.\n *\n * Operator post-deploy: create a `fixture-seeder` Cognito user with\n * a service password (manually via console or scripted with\n * `aws cognito-idp admin-create-user`); the CLI consumes those creds\n * via env vars to drive `InitiateAuth`.\n */\n protected createFixtureSeederClient(): IUserPoolClient | undefined {\n if (this.ohEnv.ohStage.stageType === OPEN_HI_STAGE.PROD) {\n return undefined;\n }\n const client = new CognitoFixtureSeederClient(this, {\n userPool: this.userPool,\n });\n new DiscoverableStringParameter(this, \"fixture-seeder-client-param\", {\n ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,\n stringValue: client.userPoolClientId,\n description:\n \"Cognito User Pool Client ID for the OpenHI fixture-seeder CLI \" +\n \"(USER_PASSWORD_AUTH; non-prod only); cross-stack reference\",\n });\n return client;\n }\n\n /**\n * Creates the User Pool Domain (Cognito hosted UI) and exports domain name to SSM.\n * Look up via {@link OpenHiAuthService.userPoolDomainFromConstruct}.\n * Override to customize.\n */\n protected createUserPoolDomain(): IUserPoolDomain {\n const domain = new CognitoUserPoolDomain(this, {\n userPool: this.userPool,\n cognitoDomain: {\n domainPrefix: `auth-${this.branchHash}`,\n },\n });\n new DiscoverableStringParameter(this, \"user-pool-domain-param\", {\n ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,\n stringValue: domain.domainName,\n description:\n \"Cognito User Pool Domain (hosted UI) for this Auth stack; cross-stack reference\",\n });\n return domain;\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport { StreamViewType, ITable, Table } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport * as kinesis from \"aws-cdk-lib/aws-kinesis\";\nimport { Construct } from \"constructs\";\nimport { OpenHiAuthService } from \"./open-hi-auth-service\";\nimport { OpenHiGlobalService } from \"./open-hi-global-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { DataStoreHistoricalArchive } from \"../components/dynamodb/data-store-historical-archive\";\nimport {\n DynamoDbDataStore,\n getDynamoDbDataStoreTableName,\n} from \"../components/dynamodb/dynamo-db-data-store\";\nimport { DataStorePostgresReplica } from \"../components/postgres/data-store-postgres-replica\";\nimport { SeedDemoDataWorkflow } from \"../workflows/control-plane/seed-demo-data\";\nimport { SeedSystemDataWorkflow } from \"../workflows/control-plane/seed-system-data\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-data-service.md\n */\n\nexport type OpenHiDataServiceProps = OpenHiServiceProps;\n\n/**\n * Data storage service stack: centralizes DynamoDB, S3, and other persistence\n * resources for OpenHI. Creates the single-table data store in a protected\n * method; subclasses may override to customize. EventBridge event buses\n * (data, ops, control) are owned by {@link OpenHiGlobalService} so they deploy\n * ahead of regional services.\n */\nexport class OpenHiDataService extends OpenHiService {\n static readonly SERVICE_TYPE = \"data\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.\n */\n static dynamoDbDataStoreFromConstruct(\n scope: Construct,\n id = \"dynamo-db-data-store\",\n ): ITable {\n return Table.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));\n }\n\n get serviceType(): string {\n return OpenHiDataService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options. */\n public override props: OpenHiDataServiceProps;\n\n /**\n * The single-table DynamoDB data store. Use {@link OpenHiDataService.dynamoDbDataStoreFromConstruct}\n * from other stacks to obtain an ITable reference by name.\n */\n public readonly dataStore: ITable;\n\n /**\n * Kinesis stream receiving DynamoDB item-level changes for the data store table.\n */\n public readonly dataStoreChangeStream: kinesis.IStream;\n\n /**\n * Historical archive pipeline (Kinesis → Firehose → S3) and data-event-bus\n * notifications for current FHIR resources (ADRs 2026-03-11-02, 2026-03-02-01).\n */\n public readonly dataStoreHistoricalArchive: DataStoreHistoricalArchive;\n\n /**\n * Postgres replication tier (ADR 2026-04-17-01, phase 1). A second consumer\n * on the change stream that projects current FHIR resources into a JSONB\n * `resources` table on Aurora Serverless v2. Phase 1 is replication-only;\n * the read path is not wired up yet.\n */\n public readonly dataStorePostgresReplica: DataStorePostgresReplica;\n\n /**\n * Deploy-triggered workflow that idempotently re-asserts the\n * platform-singleton control-plane records (today: the three canonical\n * Roles via `PLATFORM_ROLE_CONCEPTS`; future: additional system\n * data). Subscribes to `platform.deployment-completed.v1` on the\n * control event bus and dedups via the shared `WorkflowDedupTable`.\n */\n public readonly seedSystemDataWorkflow: SeedSystemDataWorkflow;\n\n /**\n * Deploy-triggered workflow that idempotently re-asserts the demo\n * data graph (placeholder + 3 demo Tenants + 5 Workspaces; per\n * dev-user Cognito users with their DynamoDB User records,\n * Memberships, and RoleAssignments). **Non-prod only** —\n * `undefined` on prod stages. The synth-time stage gate in\n * {@link createSeedDemoDataWorkflow} is the only guarantee\n * separating prod stacks from the workflow's IAM grants and rule\n * target; the construct itself never checks the stage.\n */\n public readonly seedDemoDataWorkflow?: SeedDemoDataWorkflow;\n\n /**\n * Cached control-event-bus lookup. `OpenHiGlobalService.controlEventBusFromConstruct`\n * registers a child `EventBus.fromEventBusName` construct with a\n * fixed id under the scope it is passed, so calling it twice on the\n * same `OpenHiDataService` instance collides. The cache mirrors the\n * `private controlEventBus()` pattern already used in\n * `OpenHiAuthService`. Use {@link controlEventBus} from this class\n * — never call the static lookup from inside `OpenHiDataService`.\n */\n private _controlEventBus: IEventBus | null = null;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiDataServiceProps = {}) {\n super(ohEnv, OpenHiDataService.SERVICE_TYPE, props);\n this.props = props;\n\n this.dataStoreChangeStream = new kinesis.Stream(\n this,\n \"data-store-change-stream\",\n {\n streamName: `openhi-dstore-cdc-${this.branchHash}`,\n streamMode: kinesis.StreamMode.ON_DEMAND,\n // CDK default for kinesis.Stream is RETAIN, which strands the stream\n // when a non-prod stack is destroyed. Use the service's policy so\n // non-prod tears down cleanly while prod retains.\n removalPolicy: this.removalPolicy,\n },\n );\n\n this.dataStore = this.createDataStore();\n\n this.dataStoreHistoricalArchive = new DataStoreHistoricalArchive(\n this,\n \"data-store-historical-archive\",\n {\n kinesisStream: this.dataStoreChangeStream,\n removalPolicy: this.removalPolicy,\n stackHash: this.stackHash,\n dataEventBus: OpenHiGlobalService.dataEventBusFromConstruct(this),\n },\n );\n\n this.dataStorePostgresReplica = new DataStorePostgresReplica(\n this,\n \"data-store-postgres-replica\",\n {\n kinesisStream: this.dataStoreChangeStream,\n removalPolicy: this.removalPolicy,\n stackHash: this.stackHash,\n branchHash: this.branchHash,\n },\n );\n\n this.seedSystemDataWorkflow = this.createSeedSystemDataWorkflow();\n this.seedDemoDataWorkflow = this.createSeedDemoDataWorkflow();\n }\n\n /**\n * Lazily looks up the control event bus exactly once per\n * `OpenHiDataService` instance and caches the reference. Every\n * workflow that consumes the bus must read it through this method\n * — see {@link _controlEventBus} for the underlying collision risk.\n */\n private controlEventBus(): IEventBus {\n if (this._controlEventBus === null) {\n this._controlEventBus =\n OpenHiGlobalService.controlEventBusFromConstruct(this);\n }\n return this._controlEventBus;\n }\n\n /**\n * Creates the seed-system-data workflow. Override to customize.\n */\n protected createSeedSystemDataWorkflow(): SeedSystemDataWorkflow {\n return new SeedSystemDataWorkflow(this, {\n controlEventBus: this.controlEventBus(),\n dataStoreTable: this.dataStore,\n });\n }\n\n /**\n * Creates the seed-demo-data workflow — but only on non-prod\n * stages. Returns `undefined` on prod so the workflow literally\n * does not exist in prod stacks. Override to customize.\n */\n protected createSeedDemoDataWorkflow(): SeedDemoDataWorkflow | undefined {\n if (this.ohEnv.ohStage.stageType === OPEN_HI_STAGE.PROD) {\n return undefined;\n }\n return new SeedDemoDataWorkflow(this, {\n controlEventBus: this.controlEventBus(),\n dataStoreTable: this.dataStore,\n userPool: OpenHiAuthService.userPoolFromConstruct(this),\n });\n }\n\n /**\n * Creates the single-table DynamoDB data store.\n * Override to customize.\n */\n protected createDataStore(): ITable {\n return new DynamoDbDataStore(this, \"dynamo-db-data-store\", {\n kinesisStream: this.dataStoreChangeStream,\n stream: StreamViewType.NEW_AND_OLD_IMAGES,\n });\n }\n}\n","import {\n Certificate,\n CertificateValidation,\n ICertificate,\n} from \"aws-cdk-lib/aws-certificatemanager\";\nimport { EventBus, IEventBus } from \"aws-cdk-lib/aws-events\";\nimport {\n HostedZone,\n HostedZoneAttributes,\n IHostedZone,\n} from \"aws-cdk-lib/aws-route53\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { RootWildcardCertificate } from \"../components/acm/root-wildcard-certificate\";\nimport { WorkflowDedupTable } from \"../components/dynamodb/workflow-dedup-table\";\nimport { ControlEventBus } from \"../components/event-bridge/control-event-bus\";\nimport { DataEventBus } from \"../components/event-bridge/data-event-bus\";\nimport { OpsEventBus } from \"../components/event-bridge/ops-event-bus\";\nimport { ChildHostedZone } from \"../components/route-53/child-hosted-zone\";\nimport { DiscoverableStringParameter } from \"../components/ssm\";\nimport { PlatformDeployBridge } from \"../workflows/control-plane/platform-deploy-bridge\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-global-service.md\n */\n\nexport interface OpenHiGlobalServiceProps extends OpenHiServiceProps {}\n\n/**\n * Global Infrastructure stack: owns global DNS, certificates, and the\n * cross-region EventBridge buses (data, ops, control). Resources (root zone,\n * optional child zone, wildcard cert, data/ops/control buses) are created in\n * protected methods; subclasses may override to customize.\n */\nexport class OpenHiGlobalService extends OpenHiService {\n static readonly SERVICE_TYPE = \"global\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns an IHostedZone from the given attributes (no SSM). Use when the zone is imported from config.\n */\n static rootHostedZoneFromConstruct(\n scope: Construct,\n props: HostedZoneAttributes,\n ): IHostedZone {\n return HostedZone.fromHostedZoneAttributes(scope, \"root-zone\", props);\n }\n\n /**\n * Returns an ICertificate by looking up the Global stack's wildcard cert ARN from SSM.\n */\n static rootWildcardCertificateFromConstruct(scope: Construct): ICertificate {\n const certificateArn = StringParameter.valueForStringParameter(\n scope,\n RootWildcardCertificate.ssmParameterName(),\n );\n return Certificate.fromCertificateArn(\n scope,\n \"wildcard-certificate\",\n certificateArn,\n );\n }\n\n /**\n * Returns an IHostedZone by looking up the child hosted zone ID from SSM. Defaults to GLOBAL service type.\n */\n static childHostedZoneFromConstruct(\n scope: Construct,\n props: { zoneName: string; serviceType?: OpenHiServiceType },\n ): IHostedZone {\n const hostedZoneId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: ChildHostedZone.SSM_PARAM_NAME,\n serviceType: props.serviceType ?? OpenHiGlobalService.SERVICE_TYPE,\n });\n return HostedZone.fromHostedZoneAttributes(scope, \"child-zone\", {\n hostedZoneId,\n zoneName: props.zoneName,\n });\n }\n\n /**\n * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.\n */\n static dataEventBusFromConstruct(scope: Construct): IEventBus {\n return EventBus.fromEventBusName(\n scope,\n \"data-event-bus\",\n DataEventBus.getEventBusName(scope),\n );\n }\n\n /**\n * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.\n */\n static opsEventBusFromConstruct(scope: Construct): IEventBus {\n return EventBus.fromEventBusName(\n scope,\n \"ops-event-bus\",\n OpsEventBus.getEventBusName(scope),\n );\n }\n\n /**\n * Returns the control-plane event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.\n */\n static controlEventBusFromConstruct(scope: Construct): IEventBus {\n return EventBus.fromEventBusName(\n scope,\n \"control-event-bus\",\n ControlEventBus.getEventBusName(scope),\n );\n }\n\n /**\n * Returns the workflow dedup table by name (deterministic per branch).\n * Use from other stacks to obtain an ITable reference. Consumer Lambdas\n * are typically wired via `WorkflowDedupTable.grantConsumer(fn, name)`\n * on the owning service's `workflowDedupTable` reference; the\n * `tableNameFromLookup` / `tableArnFromLookup` SSM helpers on the\n * construct cover cross-stack consumers that need only the name/ARN.\n */\n static workflowDedupTableNameFromLookup(scope: Construct): string {\n return WorkflowDedupTable.tableNameFromLookup(scope);\n }\n\n get serviceType(): string {\n return OpenHiGlobalService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options. */\n public override props: OpenHiGlobalServiceProps;\n\n public readonly rootHostedZone: IHostedZone;\n public readonly childHostedZone?: IHostedZone;\n public readonly rootWildcardCertificate: ICertificate;\n\n /**\n * Event bus for data-related events (ingestion, transformation, storage).\n * Other stacks obtain it via {@link OpenHiGlobalService.dataEventBusFromConstruct}.\n */\n public readonly dataEventBus: IEventBus;\n\n /**\n * Event bus for operational events (monitoring, alerting, system health).\n * Other stacks obtain it via {@link OpenHiGlobalService.opsEventBusFromConstruct}.\n */\n public readonly opsEventBus: IEventBus;\n\n /**\n * Event bus for control-plane lifecycle and command events.\n * Other stacks obtain it via {@link OpenHiGlobalService.controlEventBusFromConstruct}.\n */\n public readonly controlEventBus: IEventBus;\n\n /**\n * Bridge that watches CloudFormation Stack Status Change events on the\n * default AWS bus and republishes terminal-success events for OpenHi-tagged\n * stacks onto {@link controlEventBus} as `platform.deployment-completed.v1`.\n */\n public readonly platformDeployBridge: PlatformDeployBridge;\n\n /**\n * Shared dedup table every retryable workflow consumer dedupes against\n * (TR-015). Singleton per deployment — provisioned here on the global\n * stack so consumer stacks reach it via SSM lookups, not props.\n */\n public readonly workflowDedupTable: WorkflowDedupTable;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiGlobalServiceProps = {}) {\n super(ohEnv, OpenHiGlobalService.SERVICE_TYPE, props);\n this.props = props;\n\n this.validateConfig(props);\n\n this.rootHostedZone = this.createRootHostedZone();\n this.childHostedZone = this.createChildHostedZone();\n this.rootWildcardCertificate = this.createRootWildcardCertificate();\n this.dataEventBus = this.createDataEventBus();\n this.opsEventBus = this.createOpsEventBus();\n this.controlEventBus = this.createControlEventBus();\n this.workflowDedupTable = this.createWorkflowDedupTable();\n this.platformDeployBridge = this.createPlatformDeployBridge();\n }\n\n /**\n * Validates that config required for the Global stack is present.\n */\n protected validateConfig(props: OpenHiGlobalServiceProps): void {\n const { config } = props;\n if (!config) {\n throw new Error(\"Config is required\");\n }\n if (!config.zoneName) {\n throw new Error(\"Zone name is required to import the root zone\");\n }\n if (!config.hostedZoneId) {\n throw new Error(\"Hosted zone ID is required to import the root zone\");\n }\n }\n\n /**\n * Creates the root hosted zone (imported via attributes from config).\n * Override to customize or create the zone.\n */\n protected createRootHostedZone(): IHostedZone {\n return OpenHiGlobalService.rootHostedZoneFromConstruct(this, {\n zoneName: this.config.zoneName!,\n hostedZoneId: this.config.hostedZoneId!,\n });\n }\n\n /**\n * Creates the optional child hosted zone (e.g. branch subdomain).\n * Override to create a child zone when config provides childHostedZoneAttributes.\n * If you create a ChildHostedZone, also create a DiscoverableStringParameter\n * with ChildHostedZone.SSM_PARAM_NAME and the zone's hostedZoneId.\n */\n protected createChildHostedZone(): IHostedZone | undefined {\n return undefined;\n }\n\n /**\n * Creates the root wildcard certificate. On main branch, creates a new cert\n * with DNS validation; otherwise imports from SSM.\n * Override to customize certificate creation.\n */\n protected createRootWildcardCertificate(): ICertificate {\n if (this.branchName === \"main\") {\n return new RootWildcardCertificate(this, {\n domainName: `*.${this.rootHostedZone.zoneName}`,\n subjectAlternativeNames: [this.rootHostedZone.zoneName],\n validation: CertificateValidation.fromDns(this.rootHostedZone),\n });\n }\n return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);\n }\n\n /**\n * Creates the data event bus.\n * Override to customize.\n */\n protected createDataEventBus(): IEventBus {\n return new DataEventBus(this);\n }\n\n /**\n * Creates the ops event bus.\n * Override to customize.\n */\n protected createOpsEventBus(): IEventBus {\n return new OpsEventBus(this);\n }\n\n /**\n * Creates the control-plane event bus.\n * Override to customize.\n */\n protected createControlEventBus(): IEventBus {\n return new ControlEventBus(this);\n }\n\n /**\n * Creates the platform deploy bridge that republishes CloudFormation\n * Stack Status Change events onto the control event bus.\n * Override to customize.\n */\n protected createPlatformDeployBridge(): PlatformDeployBridge {\n return new PlatformDeployBridge(this, {\n controlEventBus: this.controlEventBus,\n });\n }\n\n /**\n * Creates the shared workflow dedup table (TR-015 singleton).\n * Override to customize.\n */\n protected createWorkflowDedupTable(): WorkflowDedupTable {\n return new WorkflowDedupTable(this, \"workflow-dedup-table\");\n }\n}\n","import { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { PlatformDeployBridgeLambda } from \"./platform-deploy-bridge-lambda\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/platform-deploy-bridge/index.md\n */\n\nexport interface PlatformDeployBridgeProps {\n /** Destination control event bus the bridge republishes onto. */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Source-side reactor that watches CloudFormation Stack Status Change\n * events on the default AWS bus and republishes terminal-success events\n * (`CREATE_COMPLETE` / `UPDATE_COMPLETE`) for OpenHi-tagged stacks onto\n * the control event bus as `platform.deployment-completed.v1`.\n *\n * Implements row 4 of the workflow placement matrix\n * (codedrifters/openhi#953): ops-plane reactor → republishes to\n * control event bus.\n */\nexport class PlatformDeployBridge extends Construct {\n public readonly bridgeLambda: PlatformDeployBridgeLambda;\n\n constructor(scope: Construct, props: PlatformDeployBridgeProps) {\n super(scope, \"platform-deploy-bridge\");\n\n this.bridgeLambda = new PlatformDeployBridgeLambda(this, {\n controlEventBus: props.controlEventBus,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration, Stack } from \"aws-cdk-lib\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n BRIDGED_STATUSES,\n CLOUDFORMATION_EVENT_SOURCE,\n CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE,\n CONTROL_EVENT_BUS_NAME_ENV_VAR,\n OPENHI_REPO_TAG_KEY_ENV_VAR,\n OPENHI_TAG_KEY_PREFIX_ENV_VAR,\n} from \"./events\";\nimport {\n OPENHI_TAG_SUFFIX_REPO_NAME,\n OpenHiService,\n openHiTagKey,\n} from \"../../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/platform-deploy-bridge/index.md\n */\n\nconst HANDLER_NAME = \"platform-deploy-bridge.handler.js\";\n\n/**\n * Resolve handler entry so it works from src/ (tests) or lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface PlatformDeployBridgeLambdaProps {\n /** Destination control event bus the bridge republishes onto. */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Lambda that bridges CloudFormation Stack Status Change events from the\n * default AWS bus into typed `platform.deployment-completed.v1` envelopes on\n * the OpenHI control event bus.\n *\n * Owns its EventBridge Rule (on the default AWS bus) and the IAM\n * permissions it needs — colocating routing + permissions with the\n * function they target.\n *\n * The EventBridge rule pre-filters by stack-id prefix so the rule (and\n * therefore the Lambda) only fires on the host stack's own branch deploys.\n * This prevents cross-branch leak when multiple branches are deployed into\n * the same account.\n */\nexport class PlatformDeployBridgeLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: PlatformDeployBridgeLambdaProps) {\n super(scope, \"platform-deploy-bridge-lambda\");\n\n // Resolve the host OpenHiService so we can pin the rule to this\n // branch's stacks and project the appName-aware tag key.\n const service = OpenHiService.of(this) as OpenHiService;\n const repoTagKey = openHiTagKey(\n service.appName,\n OPENHI_TAG_SUFFIX_REPO_NAME,\n );\n const tagKeyPrefix = `${service.appName}:`;\n\n // Derive the shared sibling-stack prefix from this stack's own\n // synthesized name. `service.branchHash` alone (e.g. `4e4512-`)\n // is wrong because CDK prepends the Stage hierarchy\n // (`<stage>-<environment>-…`) to every stack name, so the\n // CloudFormation events carry stack-ids like\n // `dev-primary-4e4512-data-…`. Stripping the known\n // `-<serviceId>-<account>-<region>` suffix off the bridge's own\n // stack name yields the prefix every sibling stack shares.\n const ownStackName = Stack.of(this).stackName;\n const ownSuffix = `-${service.serviceId}-${Stack.of(this).account}-${\n Stack.of(this).region\n }`;\n const sharedPrefix = ownStackName.endsWith(ownSuffix)\n ? ownStackName.slice(0, -ownSuffix.length)\n : service.branchHash;\n const stackIdPrefix = `arn:aws:cloudformation:${Stack.of(this).region}:${\n Stack.of(this).account\n }:stack/${sharedPrefix}-`;\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 256,\n timeout: Duration.seconds(30),\n environment: {\n [CONTROL_EVENT_BUS_NAME_ENV_VAR]: props.controlEventBus.eventBusName,\n [OPENHI_REPO_TAG_KEY_ENV_VAR]: repoTagKey,\n [OPENHI_TAG_KEY_PREFIX_ENV_VAR]: tagKeyPrefix,\n },\n });\n\n // Fetch stack tags so the handler can project them into the envelope.\n // Scope to stacks in the deploying account/region.\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"cloudformation:DescribeStacks\"],\n resources: [\n `arn:aws:cloudformation:${Stack.of(this).region}:${\n Stack.of(this).account\n }:stack/*`,\n ],\n }),\n );\n\n // Republish the projected envelope onto the control event bus.\n props.controlEventBus.grantPutEventsTo(this.lambda);\n\n // Rule lives on the default AWS bus — that is where AWS publishes\n // its own CloudFormation Stack Status Change events. Omitting\n // `eventBus` defaults to the account's default bus.\n //\n // The `stack-id` prefix scopes the rule to this branch's own stacks\n // only (OpenHi stack names start with the deterministic per-branch\n // hash), so other branches' deploys never trigger this Lambda even\n // though every branch deploys its own bridge into the same account.\n this.rule = new Rule(this, \"rule\", {\n eventPattern: {\n source: [CLOUDFORMATION_EVENT_SOURCE],\n detailType: [CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE],\n detail: {\n \"stack-id\": [{ prefix: stackIdPrefix }],\n \"status-details\": {\n status: [...BRIDGED_STATUSES],\n },\n },\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { PLATFORM_ROLE_IDS } from \"@openhi/types\";\nimport { Duration, Stack } from \"aws-cdk-lib\";\nimport { IUserPool } from \"aws-cdk-lib/aws-cognito\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n DEV_USERS,\n PlatformSystemDataSeededV1,\n demoBasePartitionKeys,\n demoDevUserPartitionKeys,\n rolePartitionKey,\n} from \"./events\";\nimport { SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR } from \"./seed-demo-data.handler\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.md\n */\n\nconst HANDLER_NAME = \"seed-demo-data.handler.js\";\n\n/**\n * Resolve the bundled handler entry. Same dual-path lookup the\n * seed-system-data Lambda uses: src/ for tests (the file lives next\n * to this one) or lib/ for the compiled bundle.\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface SeedDemoDataLambdaProps {\n /**\n * Data-store table the workflow upserts demo-data records into.\n * Wired via `DYNAMO_TABLE_NAME` env var; granted scoped read on the\n * Role PKs (pre-flight check) and scoped write on the enumerated\n * demo Tenant / Workspace / Membership / RoleAssignment / User PKs.\n */\n readonly dataStoreTable: ITable;\n\n /**\n * Control event bus that re-publishes\n * `platform.deployment-completed.v1` from the platform-deploy bridge.\n * The Rule mounts here.\n */\n readonly controlEventBus: IEventBus;\n\n /**\n * Cognito User Pool the workflow provisions dev users into. The\n * Lambda's IAM grant is scoped to this exact user-pool ARN — the\n * grant uses the user-pool ARN, **not** the wildcard formatArn\n * pattern used by `post-authentication-lambda` (that Lambda's\n * trigger-driven dependency cycle does not apply here, so the\n * tighter scope is safe).\n */\n readonly userPool: IUserPool;\n}\n\n/**\n * Lambda + EventBridge Rule pair for the seed-demo-data workflow.\n * Owns the routing (`source` / `detail-type` pattern), the scoped\n * DynamoDB grants, and the scoped Cognito Admin grant — co-locating\n * routing + permissions with the function they target. Wiring to the\n * workflow dedup table is the parent construct's job (it has the\n * singleton reference) and happens via `WorkflowDedupTable.grantConsumer`.\n *\n * Stage-gating is the parent's job too — this construct itself never\n * checks the stage. The CDK stage-router (`OpenHiDataService`)\n * decides whether to instantiate it at all on each stage.\n */\nexport class SeedDemoDataLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: SeedDemoDataLambdaProps) {\n super(scope, \"seed-demo-data-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(2),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n [SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR]: props.userPool.userPoolId,\n },\n });\n\n // Pre-flight Role check: read the three platform-singleton Role\n // PKs only. A regression that tried to read other records would\n // be rejected by IAM, not by application code.\n const roleReadKeys = Object.values(PLATFORM_ROLE_IDS).map(rolePartitionKey);\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:GetItem\"],\n resources: [props.dataStoreTable.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": roleReadKeys,\n },\n },\n }),\n );\n\n // Write grant: the deterministic set of demo Tenant / Workspace /\n // Membership / RoleAssignment / User PKs the workflow writes.\n // {@link DEV_USERS} is a compile-time constant so the set is\n // fully enumerable at synth time.\n const writeKeys: string[] = [\n ...demoBasePartitionKeys(),\n ...demoDevUserPartitionKeys(DEV_USERS),\n ];\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:PutItem\", \"dynamodb:UpdateItem\"],\n resources: [props.dataStoreTable.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": writeKeys,\n },\n },\n }),\n );\n\n // Cognito grant. The User Pool is imported by ARN from the auth\n // stack via SSM lookup, so reconstructing the ARN with\n // `Stack.of(this).formatArn` scopes the grant to this exact\n // account+region+pool without depending on the auth stack's\n // exported ARN.\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"cognito-idp:AdminCreateUser\",\n \"cognito-idp:AdminGetUser\",\n \"cognito-idp:AdminSetUserPassword\",\n ],\n resources: [\n Stack.of(this).formatArn({\n service: \"cognito-idp\",\n resource: \"userpool\",\n resourceName: props.userPool.userPoolId,\n }),\n ],\n }),\n );\n\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.controlEventBus,\n eventPattern: {\n source: [PlatformSystemDataSeededV1.source],\n detailType: [PlatformSystemDataSeededV1.detailType],\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import { IUserPool } from \"aws-cdk-lib/aws-cognito\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { SEED_DEMO_DATA_CONSUMER_NAME } from \"./events\";\nimport { SeedDemoDataLambda } from \"./seed-demo-data-lambda\";\nimport { WorkflowDedupTable } from \"../../../components/dynamodb/workflow-dedup-table\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.md\n */\n\nexport interface SeedDemoDataWorkflowProps {\n /** Control event bus carrying `platform.system-data-seeded.v1`. */\n readonly controlEventBus: IEventBus;\n /** Data-store table the workflow upserts demo-data records into. */\n readonly dataStoreTable: ITable;\n /** Cognito User Pool the workflow provisions dev users into. */\n readonly userPool: IUserPool;\n}\n\n/**\n * Control-plane workflow that fires on every platform deploy and\n * idempotently re-asserts the demo-data graph: placeholder tenant +\n * workspace, 3 demo tenants + 4 workspaces, and per-dev-user Cognito\n * users with their DynamoDB User records, Memberships, and\n * RoleAssignments.\n *\n * Mounted on the data-service stack so the IAM grants against the\n * data-store table stay local. The control event bus and the workflow\n * dedup table reach in cross-stack via the SSM lookups\n * `OpenHiGlobalService.controlEventBusFromConstruct` and\n * `WorkflowDedupTable.grantConsumerFromLookup` respectively. The\n * Cognito User Pool similarly reaches in via\n * `OpenHiAuthService.userPoolFromConstruct`.\n *\n * Non-prod-only: the CDK stage-router (`OpenHiDataService`)\n * conditionally constructs this workflow only on non-prod stages.\n * The construct itself never checks the stage — its absence in prod\n * stacks is the gate.\n */\nexport class SeedDemoDataWorkflow extends Construct {\n public readonly seedDemoData: SeedDemoDataLambda;\n\n constructor(scope: Construct, props: SeedDemoDataWorkflowProps) {\n super(scope, \"seed-demo-data-workflow\");\n\n this.seedDemoData = new SeedDemoDataLambda(this, {\n controlEventBus: props.controlEventBus,\n dataStoreTable: props.dataStoreTable,\n userPool: props.userPool,\n });\n\n // Cross-stack grant resolves the dedup table's name + ARN via SSM\n // at synth time, so the data-service stack does not pick up a\n // CloudFormation export dependency on the global stack that owns\n // the dedup table.\n WorkflowDedupTable.grantConsumerFromLookup(\n this,\n this.seedDemoData.lambda,\n SEED_DEMO_DATA_CONSUMER_NAME,\n );\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { PLATFORM_ROLE_IDS } from \"@openhi/types\";\nimport { Duration, Stack } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n PlatformDeploymentCompletedV1,\n SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR,\n} from \"./events\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-system-data/seed-system-data-lambda.md\n */\n\nconst HANDLER_NAME = \"seed-system-data.handler.js\";\n\n/**\n * Resolve the bundled handler entry. Same dual-path lookup the user-onboarding\n * Lambda uses: src/ for tests (the file lives next to this one) or lib/ for\n * the compiled bundle.\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface SeedSystemDataLambdaProps {\n /**\n * Data-store table the workflow upserts platform-singleton control-plane\n * records into. Wired via `DYNAMO_TABLE_NAME` env var; granted scoped\n * write permission to the role records' partition keys only.\n */\n readonly dataStoreTable: ITable;\n\n /**\n * Control event bus that re-publishes\n * `platform.deployment-completed.v1` from the platform-deploy bridge.\n * The Rule mounts here.\n */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Lambda + EventBridge Rule pair for the seed-system-data workflow. Owns\n * the routing (`source` / `detail-type` pattern) and the scoped data-store\n * grants — co-locating routing + permissions with the function they\n * target. Wiring to the workflow dedup table is the parent construct's\n * job (it has the singleton reference) and happens via\n * `WorkflowDedupTable.grantConsumer`.\n */\nexport class SeedSystemDataLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: SeedSystemDataLambdaProps) {\n super(scope, \"seed-system-data-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n [SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR]:\n props.controlEventBus.eventBusName,\n },\n });\n\n // Least-privilege grant: only the three known role PKs are\n // writable. A regression that tried to write a non-Role record\n // (or a Role with an unrecognized id) would be rejected by IAM,\n // not by application code. Updating the role-id set means\n // amending the generator's `ID_PREFIX_BY_VALUE_SET_URL` table\n // and regenerating — the role-id values flow through.\n //\n // The leading-keys values must match what ElectroDB *actually\n // writes*, not the entity definition's pretty template. The\n // base-table PK template `ROLE#ID#${id}` has no\n // `casing: \"none\"`, so ElectroDB applies its default casing\n // (lowercase) at runtime and the on-the-wire PK is\n // `role#id#<id>`. Authoring the policy in the uppercase\n // template form silently produces an IAM denial on every\n // PutItem the seeder attempts.\n const roleArns = Object.values(PLATFORM_ROLE_IDS).map(\n (id) => `role#id#${id}`,\n );\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:PutItem\", \"dynamodb:UpdateItem\"],\n resources: [props.dataStoreTable.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": roleArns,\n },\n },\n }),\n );\n\n // Allow the handler to publish `platform.system-data-seeded.v1`\n // onto the control event bus after a successful seed. Downstream\n // consumers (`seed-demo-data`) subscribe to that event instead\n // of the raw deploy-completion event so the dependency is\n // enforced by a happens-before edge rather than by EventBridge\n // retry timing.\n props.controlEventBus.grantPutEventsTo(this.lambda);\n\n // Gate the rule on the host (data) stack's own completion event.\n // The data-store table is created by this stack, so seeding only\n // becomes safe once this stack reaches CREATE/UPDATE_COMPLETE.\n // Without this filter, sibling stacks (global, auth, rest-api,\n // graphql) completing before the data stack would trigger the\n // seeder against a not-yet-created table.\n //\n // The filter targets `detail.payload.stackName`: the outer\n // `detail` is EventBridge's envelope (which holds the whole\n // workflow envelope), and `payload` is the per-workflow payload\n // field on `WorkflowEvent` — i.e. the projection the bridge\n // produced from the CloudFormation Stack Status Change event.\n const hostStackName = Stack.of(this).stackName;\n\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.controlEventBus,\n eventPattern: {\n source: [PlatformDeploymentCompletedV1.source],\n detailType: [PlatformDeploymentCompletedV1.detailType],\n detail: {\n payload: {\n stackName: [hostStackName],\n },\n },\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { SEED_SYSTEM_DATA_CONSUMER_NAME } from \"./events\";\nimport { SeedSystemDataLambda } from \"./seed-system-data-lambda\";\nimport { WorkflowDedupTable } from \"../../../components/dynamodb/workflow-dedup-table\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-system-data/seed-system-data-workflow.md\n */\n\nexport interface SeedSystemDataWorkflowProps {\n /** Control event bus carrying `platform.deployment-completed.v1`. */\n readonly controlEventBus: IEventBus;\n /** Data-store table the workflow upserts platform-singleton records into. */\n readonly dataStoreTable: ITable;\n}\n\n/**\n * Control-plane workflow that fires on every platform deploy and\n * idempotently re-asserts the platform-singleton control-plane records\n * (today: the three canonical Roles; future: additional system data\n * slotted in as sibling steps under the same dedup record).\n *\n * Mounted on the data-service stack so the IAM grants against the\n * data-store table stay local. The control event bus and the\n * workflow dedup table reach in cross-stack via the SSM lookups\n * `OpenHiGlobalService.controlEventBusFromConstruct` and\n * `WorkflowDedupTable.grantConsumerFromLookup` respectively.\n */\nexport class SeedSystemDataWorkflow extends Construct {\n public readonly seedSystemData: SeedSystemDataLambda;\n\n constructor(scope: Construct, props: SeedSystemDataWorkflowProps) {\n super(scope, \"seed-system-data-workflow\");\n\n this.seedSystemData = new SeedSystemDataLambda(this, {\n controlEventBus: props.controlEventBus,\n dataStoreTable: props.dataStoreTable,\n });\n\n // Cross-stack grant resolves the dedup table's name + ARN via SSM\n // at synth time, so the data-service stack does not pick up a\n // CloudFormation export dependency on the global stack that owns\n // the dedup table.\n WorkflowDedupTable.grantConsumerFromLookup(\n this,\n this.seedSystemData.lambda,\n SEED_SYSTEM_DATA_CONSUMER_NAME,\n );\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,\n USER_ONBOARDING_EVENT_SOURCE,\n} from \"./events\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/user-onboarding/provision-default-workspace-lambda.md\n */\n\nconst HANDLER_NAME = \"provision-default-workspace.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface ProvisionDefaultWorkspaceLambdaProps {\n /**\n * DynamoDB data store table. Used for the Lambda's `DYNAMO_TABLE_NAME`\n * env var and for granting the Lambda the writes + GSI queries it needs\n * to provision default control-plane resources.\n */\n readonly dataStoreTable: ITable;\n\n /**\n * Control-plane event bus that the EventBridge Rule listens on.\n */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Lambda used by the user-onboarding workflow to create a user's default\n * Tenant, Workspace, Memberships, and RoleAssignment.\n *\n * Owns the EventBridge Rule that routes the default-workspace onboarding\n * event to itself, and the IAM permissions it needs on the data store\n * table — colocating routing + permissions with the function they target.\n */\nexport class ProvisionDefaultWorkspaceLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: ProvisionDefaultWorkspaceLambdaProps) {\n super(scope, \"provision-default-workspace-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n },\n });\n\n // Grant table writes for default resources and User repair.\n props.dataStoreTable.grant(\n this.lambda,\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n );\n\n // Table.grant(\"dynamodb:Query\") only covers the table itself, not its\n // GSIs, so an explicit policy is required to query GSI2 by cognitoSub.\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:Query\"],\n resources: [`${props.dataStoreTable.tableArn}/index/*`],\n }),\n );\n\n // Route only the default-workspace onboarding event to this worker.\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.controlEventBus,\n eventPattern: {\n source: [USER_ONBOARDING_EVENT_SOURCE],\n detailType: [PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE],\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { ProvisionDefaultWorkspaceLambda } from \"./provision-default-workspace-lambda\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/user-onboarding/user-onboarding-workflow.md\n */\n\nexport interface UserOnboardingWorkflowProps {\n readonly controlEventBus: IEventBus;\n readonly dataStoreTable: ITable;\n}\n\n/**\n * Control-plane workflow for onboarding users after Cognito confirmation.\n */\nexport class UserOnboardingWorkflow extends Construct {\n public readonly provisionDefaultWorkspace: ProvisionDefaultWorkspaceLambda;\n\n constructor(scope: Construct, props: UserOnboardingWorkflowProps) {\n super(scope, \"user-onboarding-workflow\");\n\n this.provisionDefaultWorkspace = new ProvisionDefaultWorkspaceLambda(this, {\n dataStoreTable: props.dataStoreTable,\n controlEventBus: props.controlEventBus,\n });\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport {\n CorsHttpMethod,\n DomainName,\n HttpApi,\n HttpMethod,\n HttpNoneAuthorizer,\n HttpRoute,\n HttpRouteKey,\n IHttpApi,\n} from \"aws-cdk-lib/aws-apigatewayv2\";\nimport { HttpUserPoolAuthorizer } from \"aws-cdk-lib/aws-apigatewayv2-authorizers\";\nimport { HttpLambdaIntegration } from \"aws-cdk-lib/aws-apigatewayv2-integrations\";\nimport { ICertificate } from \"aws-cdk-lib/aws-certificatemanager\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport {\n ARecord,\n HostedZone,\n IHostedZone,\n RecordTarget,\n} from \"aws-cdk-lib/aws-route53\";\nimport { ApiGatewayv2DomainProperties } from \"aws-cdk-lib/aws-route53-targets\";\nimport { Duration } from \"aws-cdk-lib/core\";\nimport { Construct } from \"constructs\";\nimport { OpenHiAuthService } from \"./open-hi-auth-service\";\nimport { OpenHiDataService } from \"./open-hi-data-service\";\nimport { OpenHiGlobalService } from \"./open-hi-global-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport {\n RootHttpApi,\n RootHttpApiProps,\n} from \"../components/api-gateway/root-http-api\";\nimport {\n DataStorePostgresReplica,\n getPostgresReplicaSchemaName,\n} from \"../components/postgres/data-store-postgres-replica\";\nimport { DiscoverableStringParameter } from \"../components/ssm\";\nimport { CorsOptionsLambda } from \"../data/lambda/cors-options-lambda\";\nimport { RestApiLambda } from \"../data/lambda/rest-api-lambda\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-rest-api-service.md\n */\n\nexport interface OpenHiRestApiServiceProps extends OpenHiServiceProps {\n /**\n * Optional props passed through to the RootHttpApi (API Gateway HTTP API) construct.\n * Use corsPreflight (CDK CorsPreflightOptions) for CORS; other HttpApiProps (e.g. description, disableExecuteApiEndpoint) apply as well.\n */\n readonly rootHttpApiProps?: RootHttpApiProps;\n}\n\n/**\n * SSM parameter name suffix for the REST API base URL.\n * Full parameter name is built via buildParameterName with serviceType REST_API.\n */\nexport const REST_API_BASE_URL_SSM_NAME = \"REST_API_BASE_URL\";\n\n/**\n * REST API service stack: HTTP API, custom domain, and Lambda; exports base URL via SSM.\n * Resources are created in protected methods; subclasses may override to customize.\n */\nexport class OpenHiRestApiService extends OpenHiService {\n static readonly SERVICE_TYPE =\n \"rest-api\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns an IHttpApi by looking up the REST API stack's HTTP API ID from SSM.\n */\n static rootHttpApiFromConstruct(scope: Construct): IHttpApi {\n const httpApiId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: RootHttpApi.SSM_PARAM_NAME,\n serviceType: OpenHiRestApiService.SERVICE_TYPE,\n });\n return HttpApi.fromHttpApiAttributes(scope, \"http-api\", { httpApiId });\n }\n\n /**\n * Returns the REST API base URL (e.g. https://api.example.com) by looking it up from SSM.\n * Use in other stacks for E2E, scripts, or config.\n */\n static restApiBaseUrlFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: REST_API_BASE_URL_SSM_NAME,\n serviceType: OpenHiRestApiService.SERVICE_TYPE,\n });\n }\n\n get serviceType(): string {\n return OpenHiRestApiService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options (e.g. rootHttpApiProps). */\n public override props: OpenHiRestApiServiceProps;\n\n public readonly rootHttpApi: RootHttpApi;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiRestApiServiceProps = {}) {\n super(ohEnv, OpenHiRestApiService.SERVICE_TYPE, props);\n this.props = props;\n\n this.validateConfig(props);\n\n const hostedZone = this.createHostedZone();\n const certificate = this.createCertificate();\n const apiDomainName = this.createApiDomainNameString(hostedZone);\n this.createRestApiBaseUrlParameter(apiDomainName);\n const domainName = this.createDomainName(hostedZone, certificate);\n this.rootHttpApi = this.createRootHttpApi(domainName);\n this.createRestApiLambdaAndRoutes(hostedZone, domainName);\n }\n\n /**\n * Validates that config required for the REST API stack is present.\n */\n protected validateConfig(props: OpenHiRestApiServiceProps): void {\n const { config } = props;\n if (!config) {\n throw new Error(\"Config is required\");\n }\n if (!config.hostedZoneId) {\n throw new Error(\"Hosted zone ID is required\");\n }\n if (!config.zoneName) {\n throw new Error(\"Zone name is required\");\n }\n }\n\n /**\n * Creates the hosted zone reference (imported from config).\n * Override to customize.\n */\n protected createHostedZone(): IHostedZone {\n const { config } = this.props;\n return HostedZone.fromHostedZoneAttributes(this, \"root-zone\", {\n hostedZoneId: config!.hostedZoneId!,\n zoneName: config!.zoneName!,\n });\n }\n\n /**\n * Creates the wildcard certificate (imported from Global stack via SSM).\n * Override to customize.\n */\n protected createCertificate() {\n return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);\n }\n\n /**\n * Returns the API domain name string (e.g. api.example.com or api-{prefix}.example.com).\n * Override to customize.\n */\n protected createApiDomainNameString(hostedZone: IHostedZone): string {\n const apiPrefix =\n this.branchName === \"main\" ? `api` : `api-${this.childZonePrefix}`;\n return [apiPrefix, hostedZone.zoneName].join(\".\");\n }\n\n /**\n * Creates the SSM parameter for the REST API base URL.\n * Look up via {@link OpenHiRestApiService.restApiBaseUrlFromConstruct}.\n * Override to customize.\n */\n protected createRestApiBaseUrlParameter(apiDomainName: string): void {\n const restApiBaseUrl = `https://${apiDomainName}`;\n new DiscoverableStringParameter(this, \"rest-api-base-url-param\", {\n ssmParamName: REST_API_BASE_URL_SSM_NAME,\n stringValue: restApiBaseUrl,\n description: \"REST API base URL for this deployment (E2E, scripts)\",\n });\n }\n\n /**\n * Creates the API Gateway custom domain name resource.\n * Override to customize.\n */\n protected createDomainName(\n _hostedZone: IHostedZone,\n certificate: ICertificate,\n ): DomainName {\n const apiDomainName = this.createApiDomainNameString(_hostedZone);\n return new DomainName(this, \"domain\", {\n domainName: apiDomainName,\n certificate,\n });\n }\n\n /**\n * Creates the Lambda integration, HTTP routes, and API DNS record.\n * Override to customize. Uses {@link rootHttpApi} set by the constructor.\n */\n protected createRestApiLambdaAndRoutes(\n hostedZone: IHostedZone,\n domainName: DomainName,\n ): void {\n const dataStoreTable =\n OpenHiDataService.dynamoDbDataStoreFromConstruct(this);\n\n // Phase 2 of ADR 2026-04-17-01: REST API Lambda queries Postgres via the\n // RDS Data API. Cluster ARN, secret ARN, and database name come from SSM\n // (cross-stack discovery); the per-branch schema name is deterministic\n // from `branchHash` and computed locally to avoid an extra SSM lookup.\n const postgresClusterArn =\n DataStorePostgresReplica.clusterArnFromConstruct(this);\n const postgresSecretArn =\n DataStorePostgresReplica.secretArnFromConstruct(this);\n const postgresDatabase =\n DataStorePostgresReplica.databaseNameFromConstruct(this);\n const postgresSchema = getPostgresReplicaSchemaName(this.branchHash);\n\n const { lambda } = new RestApiLambda(this, {\n dynamoTableName: dataStoreTable.tableName,\n branchTagValue: this.branchName,\n httpApiTagValue: RootHttpApi.SSM_PARAM_NAME,\n postgresClusterArn,\n postgresSecretArn,\n postgresDatabase,\n postgresSchema,\n });\n\n // Allow the Lambda to issue Data API statements against this cluster and\n // read the cluster credentials secret. These are scoped to the specific\n // ARNs published by the data stack — no wildcards.\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"rds-data:ExecuteStatement\",\n \"rds-data:BatchExecuteStatement\",\n ],\n resources: [postgresClusterArn],\n }),\n );\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"secretsmanager:GetSecretValue\"],\n resources: [postgresSecretArn],\n }),\n );\n const dynamoActions = [\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:ConditionCheckItem\",\n \"dynamodb:DescribeTable\",\n \"dynamodb:BatchWriteItem\",\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:DeleteItem\",\n ] as const;\n dataStoreTable.grant(lambda, ...dynamoActions);\n // Query (and other operations) on GSIs require the index resource ARN\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [...dynamoActions],\n resources: [`${dataStoreTable.tableArn}/index/*`],\n }),\n );\n // Temporary: broad SSM read for dynamic config (test only)\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"ssm:GetParameter\",\n \"ssm:GetParameters\",\n \"ssm:DescribeParameters\",\n ],\n resources: [\"*\"],\n }),\n );\n const integration = new HttpLambdaIntegration(\"lambda-integration\", lambda);\n const { lambda: optionsLambda } = new CorsOptionsLambda(this);\n const optionsIntegration = new HttpLambdaIntegration(\n \"options-integration\",\n optionsLambda,\n );\n const noAuth = new HttpNoneAuthorizer();\n // OPTIONS routes use dedicated low-memory Lambda so main REST API Lambda is not invoked for preflight (#694).\n new HttpRoute(this, \"options-route-root\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/\", HttpMethod.OPTIONS),\n integration: optionsIntegration,\n authorizer: noAuth,\n });\n new HttpRoute(this, \"options-route-proxy\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/{proxy+}\", HttpMethod.OPTIONS),\n integration: optionsIntegration,\n authorizer: noAuth,\n });\n new HttpRoute(this, \"proxy-route-root\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/\", HttpMethod.ANY),\n integration,\n });\n new HttpRoute(this, \"proxy-route\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/{proxy+}\", HttpMethod.ANY),\n integration,\n });\n const apiPrefix =\n this.branchName === \"main\" ? `api` : `api-${this.childZonePrefix}`;\n new ARecord(this, \"api-a-record\", {\n zone: hostedZone,\n recordName: apiPrefix,\n target: RecordTarget.fromAlias(\n new ApiGatewayv2DomainProperties(\n domainName.regionalDomainName,\n domainName.regionalHostedZoneId,\n ),\n ),\n });\n }\n\n /**\n * Creates the Root HTTP API with default domain mapping, Cognito JWT authorizer, and exports API ID to SSM.\n * Look up via {@link OpenHiRestApiService.rootHttpApiFromConstruct}.\n * Override to customize.\n */\n protected createRootHttpApi(domainName: DomainName): RootHttpApi {\n const userPool = OpenHiAuthService.userPoolFromConstruct(this);\n const userPoolClient = OpenHiAuthService.userPoolClientFromConstruct(this);\n // In non-prod, also accept tokens issued by the dedicated\n // fixture-seeder client (provisioned in the auth stack only when\n // stage !== prod). Adding it to the authorizer's accepted-clients\n // list lets the seed-fixtures CLI authenticate against the same\n // API the SPA uses, without weakening prod which never sees this\n // client at all.\n const userPoolClients = [userPoolClient];\n if (this.ohEnv.ohStage.stageType !== OPEN_HI_STAGE.PROD) {\n userPoolClients.push(\n OpenHiAuthService.fixtureSeederClientFromConstruct(this),\n );\n }\n const cognitoAuthorizer = new HttpUserPoolAuthorizer(\n \"cognito-authorizer\",\n userPool,\n { userPoolClients },\n );\n const { corsPreflight: cors, ...restRootHttpApiProps } =\n this.props.rootHttpApiProps ?? {};\n const corsPreflight =\n cors !== undefined\n ? {\n allowOrigins: cors.allowOrigins,\n allowMethods: cors.allowMethods ?? [\n CorsHttpMethod.GET,\n CorsHttpMethod.HEAD,\n CorsHttpMethod.POST,\n CorsHttpMethod.PUT,\n CorsHttpMethod.PATCH,\n CorsHttpMethod.DELETE,\n CorsHttpMethod.OPTIONS,\n ],\n allowHeaders: cors.allowHeaders ?? [\n \"Content-Type\",\n \"Authorization\",\n ],\n allowCredentials: cors.allowCredentials ?? true,\n maxAge: cors.maxAge ?? Duration.days(1),\n ...(cors.exposeHeaders !== undefined && {\n exposeHeaders: cors.exposeHeaders,\n }),\n }\n : undefined;\n const rootHttpApi = new RootHttpApi(this, {\n ...restRootHttpApiProps,\n ...(corsPreflight !== undefined && { corsPreflight }),\n defaultDomainMapping: {\n domainName,\n mappingKey: undefined,\n },\n defaultAuthorizer: cognitoAuthorizer,\n });\n new DiscoverableStringParameter(this, \"http-api-url-param\", {\n ssmParamName: RootHttpApi.SSM_PARAM_NAME,\n stringValue: rootHttpApi.httpApiId,\n description:\n \"API Gateway HTTP API ID for this REST API stack (cross-stack reference)\",\n });\n return rootHttpApi;\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * Dedicated Lambda for CORS preflight (OPTIONS) requests. Returns 204 so API Gateway\n * can add CORS headers from the API's corsPreflight config. Low memory footprint.\n * @see #694\n */\n\nconst HANDLER_NAME = \"cors-options-lambda.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\nexport class CorsOptionsLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, id: string = \"cors-options-lambda\") {\n super(scope, id);\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 128,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/data/lambda/rest-api-lambda.md\n */\n\nconst HANDLER_NAME = \"rest-api-lambda.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\nexport interface RestApiLambdaProps {\n /**\n * DynamoDB table name for the data store. The Lambda receives it as the\n * environment variable DYNAMO_TABLE_NAME at runtime.\n */\n readonly dynamoTableName: string;\n\n /**\n * Branch name from the service. Passed as BRANCH_TAG_VALUE at runtime.\n */\n readonly branchTagValue: string;\n\n /**\n * SSM parameter name for the HTTP API (e.g. RootHttpApi.SSM_PARAM_NAME).\n * Passed as HTTP_API_TAG_VALUE at runtime.\n */\n readonly httpApiTagValue: string;\n\n /**\n * Aurora cluster ARN published by `DataStorePostgresReplica`. Passed as\n * `OPENHI_PG_CLUSTER_ARN` at runtime so the Lambda can target the cluster\n * via the RDS Data API (ADR 2026-04-17-01, phase 2).\n */\n readonly postgresClusterArn: string;\n\n /**\n * Secrets Manager ARN with the cluster credentials. Passed as\n * `OPENHI_PG_SECRET_ARN` at runtime; consumed by the RDS Data API client.\n */\n readonly postgresSecretArn: string;\n\n /**\n * Database name on the cluster. Passed as `OPENHI_PG_DATABASE` at runtime.\n */\n readonly postgresDatabase: string;\n\n /**\n * Per-branch schema name on the cluster (e.g. `b_<branchHash>`). Passed as\n * `OPENHI_PG_SCHEMA` at runtime.\n */\n readonly postgresSchema: string;\n}\n\nexport class RestApiLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, props: RestApiLambdaProps) {\n super(scope, \"rest-api-lambda\");\n\n /**\n * Create a Lambda function\n */\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n DYNAMO_TABLE_NAME: props.dynamoTableName,\n BRANCH_TAG_VALUE: props.branchTagValue,\n HTTP_API_TAG_VALUE: props.httpApiTagValue,\n OPENHI_PG_CLUSTER_ARN: props.postgresClusterArn,\n OPENHI_PG_SECRET_ARN: props.postgresSecretArn,\n OPENHI_PG_DATABASE: props.postgresDatabase,\n OPENHI_PG_SCHEMA: props.postgresSchema,\n },\n bundling: {\n minify: true,\n sourceMap: false,\n },\n });\n }\n}\n","import {\n AuthorizationType,\n IGraphqlApi,\n UserPoolDefaultAction,\n} from \"aws-cdk-lib/aws-appsync\";\nimport { Construct } from \"constructs\";\nimport { OpenHiAuthService } from \"./open-hi-auth-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { RootGraphqlApi } from \"../components/app-sync/root-graphql-api\";\n\nexport interface OpenHiGraphqlServiceProps extends OpenHiServiceProps {}\n\n/**\n * GraphQL API service stack: creates the AppSync API via {@link RootGraphqlApi}\n * and exports its ID via SSM. Look up from other stacks via\n * {@link OpenHiGraphqlService.graphqlApiFromConstruct}.\n */\nexport class OpenHiGraphqlService extends OpenHiService {\n static readonly SERVICE_TYPE =\n \"graphql-api\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns the GraphQL API by looking up the GraphQL stack's API ID from SSM.\n * Use from other stacks to obtain an IGraphqlApi reference.\n */\n static graphqlApiFromConstruct(scope: Construct): IGraphqlApi {\n return RootGraphqlApi.fromConstruct(scope);\n }\n\n get serviceType(): string {\n return OpenHiGraphqlService.SERVICE_TYPE;\n }\n\n /* Override so this.props is typed with this service's options */\n public override props: OpenHiGraphqlServiceProps;\n\n public readonly rootGraphqlApi: RootGraphqlApi;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiGraphqlServiceProps = {}) {\n super(ohEnv, OpenHiGraphqlService.SERVICE_TYPE, props);\n this.props = props;\n this.rootGraphqlApi = this.createRootGraphqlApi();\n }\n\n /** Creates the root GraphQL API with Cognito user pool. */\n protected createRootGraphqlApi(): RootGraphqlApi {\n const userPool = OpenHiAuthService.userPoolFromConstruct(this);\n return new RootGraphqlApi(this, {\n authorizationConfig: {\n defaultAuthorization: {\n authorizationType: AuthorizationType.USER_POOL,\n userPoolConfig: {\n userPool,\n defaultAction: UserPoolDefaultAction.ALLOW,\n },\n },\n },\n });\n }\n}\n"],"mappings":"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","names":["import_config","Stage","Stage","import_config","Tags","StringParameter","StringParameter","Tags","UserPoolClient","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","fs","path","Duration","RemovalPolicy","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","import_workflows","AttributeType","BillingMode","Table","Construct","Construct","Table","AttributeType","BillingMode","EventBus","EventBus","EventBus","EventBus","fs","path","Duration","Stack","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","Stack","NodejsFunction","Runtime","Duration","Duration","Construct","Bucket","Duration","Construct","Construct","Bucket","Duration","import_config","UserPool","UserPoolClient","UserPoolDomain","Effect","PolicyStatement","Key","Stack","import_config","Table","Certificate","EventBus","HostedZone","StringParameter","Construct","fs","path","Duration","Stack","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","Stack","NodejsFunction","Runtime","Duration","PolicyStatement","Effect","Construct","HostedZone","StringParameter","Certificate","EventBus","fs","path","Duration","Stack","Rule","LambdaFunction","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","Duration","PolicyStatement","Effect","Stack","Rule","LambdaFunction","Construct","Construct","fs","path","PLATFORM_ROLE_IDS","Duration","Stack","Rule","LambdaFunction","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","Duration","PLATFORM_ROLE_IDS","PolicyStatement","Effect","Stack","Rule","LambdaFunction","Construct","Construct","Table","fs","path","Duration","Rule","LambdaFunction","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","PolicyStatement","Effect","Rule","LambdaFunction","Duration","Construct","Construct","UserPool","UserPoolClient","UserPoolDomain","Key","PolicyStatement","Effect","Stack","import_config","HttpApi","Effect","PolicyStatement","HostedZone","Duration","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","HttpApi","HostedZone","PolicyStatement","Effect","Duration"]}
|
|
1
|
+
{"version":3,"sources":["../../config/src/open-hi-config.ts","../../config/src/index.ts","../src/app/open-hi-app.ts","../src/app/open-hi-environment.ts","../src/app/open-hi-stage.ts","../src/app/open-hi-service.ts","../src/components/acm/root-wildcard-certificate.ts","../src/components/api-gateway/root-http-api.ts","../src/components/app-sync/root-graphql-api.ts","../src/components/ssm/discoverable-string-parameter.ts","../src/components/cognito/cognito-fixture-seeder-client.ts","../src/components/cognito/cognito-user-pool.ts","../src/components/cognito/cognito-user-pool-client.ts","../src/components/cognito/cognito-user-pool-domain.ts","../src/components/cognito/cognito-user-pool-kms-key.ts","../src/components/cognito/post-authentication-lambda.ts","../src/components/cognito/post-confirmation-lambda.ts","../src/components/cognito/pre-token-generation-lambda.ts","../src/components/dynamodb/data-store-historical-archive.ts","../src/components/dynamodb/dynamo-db-data-store.ts","../src/components/dynamodb/workflow-dedup-table.ts","../src/components/event-bridge/data-event-bus.ts","../src/components/event-bridge/ops-event-bus.ts","../src/components/event-bridge/control-event-bus.ts","../src/components/postgres/data-store-postgres-replica.ts","../src/components/route-53/child-hosted-zone.ts","../src/components/route-53/root-hosted-zone.ts","../src/components/static-hosting/static-hosting.ts","../src/services/open-hi-auth-service.ts","../src/services/open-hi-data-service.ts","../src/services/open-hi-global-service.ts","../src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge.ts","../src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge-lambda.ts","../src/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.ts","../src/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.ts","../src/workflows/control-plane/seed-system-data/seed-system-data-lambda.ts","../src/workflows/control-plane/seed-system-data/seed-system-data-workflow.ts","../src/workflows/control-plane/user-onboarding/provision-default-workspace-lambda.ts","../src/workflows/control-plane/user-onboarding/user-onboarding-workflow.ts","../src/services/open-hi-rest-api-service.ts","../src/data/lambda/cors-options-lambda.ts","../src/data/lambda/rest-api-lambda.ts","../src/services/open-hi-graphql-service.ts","../src/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-lambdas.ts","../src/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-workflow.ts","../src/workflows/control-plane/rename-cascade/rename-cascade-lambdas.ts","../src/workflows/control-plane/rename-cascade/rename-cascade-workflow.ts"],"sourcesContent":["/*******************************************************************************\n *\n * OpenHi Config\n *\n * These types are kept in their own package to prevent dependency conflicts and\n * conditions between @openhi/constructs and @openhi/platform..\n *\n ******************************************************************************/\n\n/**\n * Stage Types\n *\n * What stage of deployment is this? Dev, staging, or prod?\n */\nexport const OPEN_HI_STAGE = {\n /**\n * Development environment, typically used for testing and development.\n */\n DEV: \"dev\",\n /**\n * Staging environment, used for pre-production testing.\n */\n STAGE: \"stage\",\n /**\n * Production environment, used for live deployments.\n */\n PROD: \"prod\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type OpenHiStageType =\n (typeof OPEN_HI_STAGE)[keyof typeof OPEN_HI_STAGE];\n\n/**\n * Deployment Target Role\n *\n * Is this (account, region) the primary or a secondary deployment target for the stage?\n * Works for both multi-region (different regions) and cellular (same region, different accounts).\n */\nexport const OPEN_HI_DEPLOYMENT_TARGET_ROLE = {\n /**\n * The primary deployment target for this stage (main account/region).\n * For example, the base DynamoDB region for global tables.\n */\n PRIMARY: \"primary\",\n\n /**\n * A secondary deployment target for this stage (additional account/region).\n * For example, a replica region for a global DynamoDB table, or another cell in the same region.\n */\n SECONDARY: \"secondary\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type OpenHiDeploymentTargetRoleType =\n (typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE)[keyof typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE];\n\nexport interface OpenHiEnvironmentConfig {\n account: string;\n region: string;\n /**\n * Route53 zone containing DNS for this service.\n */\n hostedZoneId?: string;\n zoneName?: string;\n}\n\n/**\n * Represents the configuration for OpenHi services across different stages and\n * deployment targets.\n */\nexport interface OpenHiConfig {\n versions?: {\n cdk?: {\n cdkLibVersion?: string;\n cdkCliVersion?: string;\n };\n };\n deploymentTargets?: {\n [OPEN_HI_STAGE.DEV]?: {\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]?: OpenHiEnvironmentConfig;\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]?: Array<OpenHiEnvironmentConfig>;\n };\n [OPEN_HI_STAGE.STAGE]?: {\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]?: OpenHiEnvironmentConfig;\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]?: Array<OpenHiEnvironmentConfig>;\n };\n [OPEN_HI_STAGE.PROD]?: {\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]?: OpenHiEnvironmentConfig;\n [OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]?: Array<OpenHiEnvironmentConfig>;\n };\n };\n}\n","export * from \"./open-hi-config\";\n","import {\n OPEN_HI_DEPLOYMENT_TARGET_ROLE,\n OPEN_HI_STAGE,\n OpenHiConfig,\n OpenHiEnvironmentConfig,\n} from \"@openhi/config\";\nimport { App, AppProps } from \"aws-cdk-lib\";\nimport { IConstruct } from \"constructs\";\nimport { OpenHiEnvironment } from \"./open-hi-environment\";\nimport { OpenHiStage } from \"./open-hi-stage\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-app.md\n */\n\n/**\n * Symbol used for runtime type checking to identify OpenHiApp instances.\n *\n * @internal\n */\nconst OPEN_HI_APP_SYMBOL = Symbol.for(\"@openhi/constructs/core.OpenHiApp\");\n\n/**\n * Properties for creating an OpenHiApp instance.\n */\nexport interface OpenHiAppProps extends AppProps {\n /**\n * Optional name for the application.\n * ```\n */\n readonly appName?: string;\n\n /**\n * The OpenHi configuration object that defines stages, environments, and\n * their associated AWS account and region settings.\n */\n readonly config: OpenHiConfig;\n}\n\n/**\n * Root application construct for OpenHi CDK applications.\n */\nexport class OpenHiApp extends App {\n /**\n * Finds the OpenHiApp instance that contains the given construct in its\n * construct tree.\n */\n public static of(construct: IConstruct): OpenHiApp | undefined {\n return construct.node.scopes.reverse().find(OpenHiApp.isOpenHiApp);\n }\n\n /**\n * Type guard that checks if a value is an OpenHiApp instance.\n */\n public static isOpenHiApp(this: void, x: any): x is OpenHiApp {\n return x !== null && typeof x === \"object\" && OPEN_HI_APP_SYMBOL in x;\n }\n\n /**\n * Name for the application.\n */\n readonly appName: string;\n\n /**\n * The OpenHi configuration object for this application.\n */\n readonly config: OpenHiConfig;\n\n /**\n * Creates a new OpenHiApp instance.\n */\n constructor(props: OpenHiAppProps) {\n super(props);\n\n // Set runtime symbol for type checking\n Object.defineProperty(this, OPEN_HI_APP_SYMBOL, { value: true });\n\n // Store app name, defaulting to \"openhi\" if not provided\n this.appName = props.appName ?? \"openhi\";\n\n // Store configuration for use by child constructs\n this.config = props.config;\n\n // Create stages and environments based on configuration\n // Iterate through all possible stage types (dev, stage, prod)\n Object.values(OPEN_HI_STAGE).forEach((stageType) => {\n // Only create a stage if it's configured in the config\n if (this.config.deploymentTargets?.[stageType]) {\n const stage = new OpenHiStage(this, { stageType });\n\n // Create primary deployment target if configured\n // Each stage can have at most one primary deployment target\n if (\n this.config.deploymentTargets?.[stageType]?.[\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY\n ]\n ) {\n const envConfig =\n this.config.deploymentTargets[stageType][\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY\n ]!;\n new OpenHiEnvironment(stage, {\n deploymentTargetRole: OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY,\n config: envConfig,\n env: { account: envConfig.account, region: envConfig.region },\n });\n }\n\n // Create secondary deployment targets if configured\n // Each stage can have zero or more secondary deployment targets\n if (\n this.config.deploymentTargets?.[stageType]?.[\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY\n ]\n ) {\n this.config.deploymentTargets[stageType][\n OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY\n ]!.forEach((envConfig: OpenHiEnvironmentConfig) => {\n new OpenHiEnvironment(stage, {\n deploymentTargetRole: OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY,\n config: envConfig,\n env: { account: envConfig.account, region: envConfig.region },\n });\n });\n }\n }\n });\n }\n\n /*****************************************************************************\n *\n * Stages\n *\n ****************************************************************************/\n\n /**\n * Gets all OpenHiStage instances that are direct children of this app.\n\n */\n public get stages(): Array<OpenHiStage> {\n return this.node.children.filter(OpenHiStage.isOpenHiStage);\n }\n\n /**\n * Gets the development stage, if it exists.\n */\n public get devStage(): OpenHiStage | undefined {\n return this.stages.find((stage) => stage.stageType === OPEN_HI_STAGE.DEV);\n }\n\n /**\n * Gets the staging stage, if it exists.\n */\n public get stageStage(): OpenHiStage | undefined {\n return this.stages.find((stage) => stage.stageType === OPEN_HI_STAGE.STAGE);\n }\n\n /**\n * Gets the production stage, if it exists.\n */\n public get prodStage(): OpenHiStage | undefined {\n return this.stages.find((stage) => stage.stageType === OPEN_HI_STAGE.PROD);\n }\n\n /*****************************************************************************\n *\n * Environments\n *\n ****************************************************************************/\n\n /**\n * Gets all OpenHiEnvironment instances across all stages in this app.\n */\n public get environments(): Array<OpenHiEnvironment> {\n return this.stages.flatMap((stage) => stage.environments);\n }\n\n /**\n * Gets all primary environments across all stages in this app.\n */\n public get primaryEnvironments(): Array<OpenHiEnvironment> {\n return this.environments.filter(\n (env) => env.deploymentTargetRole === \"primary\",\n );\n }\n\n /**\n * Gets all secondary environments across all stages in this app.\n */\n public get secondaryEnvironments(): Array<OpenHiEnvironment> {\n return this.environments.filter(\n (env) => env.deploymentTargetRole === \"secondary\",\n );\n }\n}\n","import {\n OPEN_HI_DEPLOYMENT_TARGET_ROLE,\n OpenHiEnvironmentConfig,\n} from \"@openhi/config\";\nimport { Stage, StageProps } from \"aws-cdk-lib\";\nimport { IConstruct } from \"constructs\";\nimport { OpenHiStage } from \"./open-hi-stage\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-environment.md\n */\n\n/**\n * Symbol used to identify OpenHiEnvironment instances at runtime.\n */\nconst OPEN_HI_ENVIRONMENT_SYMBOL = Symbol.for(\n \"@openhi/constructs/core.OpenHiEnvironment\",\n);\n\n/**\n * Properties for creating an OpenHiEnvironment.\n */\nexport interface OpenHiEnvironmentProps extends StageProps {\n /**\n * The deployment target role for this (account, region).\n */\n readonly deploymentTargetRole: (typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE)[keyof typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE];\n\n /**\n * Configuration for this specific environment.\n */\n readonly config: OpenHiEnvironmentConfig;\n}\n\n/**\n * Represents an OpenHi environment within an AWS CDK stage.\n */\nexport class OpenHiEnvironment extends Stage {\n /**\n * Finds the OpenHiEnvironment that contains the given construct.\n * ```\n */\n public static of(construct: IConstruct): OpenHiEnvironment | undefined {\n return construct.node.scopes\n .reverse()\n .find(OpenHiEnvironment.isOpenHiEnvironment);\n }\n\n /**\n * Type guard to check if a value is an OpenHiEnvironment instance.\n */\n public static isOpenHiEnvironment(\n this: void,\n x: any,\n ): x is OpenHiEnvironment {\n return (\n x !== null && typeof x === \"object\" && OPEN_HI_ENVIRONMENT_SYMBOL in x\n );\n }\n\n /**\n * Configuration for this specific environment.\n */\n readonly config: OpenHiEnvironmentConfig;\n\n /**\n * The deployment target role for this (account, region).\n */\n public readonly deploymentTargetRole: (typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE)[keyof typeof OPEN_HI_DEPLOYMENT_TARGET_ROLE];\n\n /**\n * Creates a new OpenHiEnvironment.\n */\n constructor(\n /**\n * The OpenHiStage that contains this environment.\n */\n public ohStage: OpenHiStage,\n /**\n * Properties for creating the environment.\n */\n public props: OpenHiEnvironmentProps,\n ) {\n // Copy account and region from config into env, if provided.\n // This allows all resources in this environment to default to the correct\n // account and region without having to specify it on each stack or resource.\n if (props.config.account && props.config.region) {\n props = {\n ...props,\n env: {\n account: props.config.account,\n region: props.config.region,\n },\n };\n }\n\n // Determine the stage name:\n // - Primary environments use the environment type as the name\n // - Secondary deployment targets use \"{deploymentTargetRole}-{index}\" format\n const stageName =\n props.deploymentTargetRole === OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY\n ? props.deploymentTargetRole\n : [props.deploymentTargetRole, ohStage.environments.length].join(\"-\");\n\n super(ohStage, stageName, {\n env: props.env ?? ohStage.props.env,\n ...props,\n });\n\n // Mark this instance as an OpenHiEnvironment for runtime type checking\n Object.defineProperty(this, OPEN_HI_ENVIRONMENT_SYMBOL, { value: true });\n\n this.deploymentTargetRole = props.deploymentTargetRole;\n this.config = props.config;\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport { Stage, StageProps } from \"aws-cdk-lib\";\nimport { IConstruct } from \"constructs\";\nimport { OpenHiApp } from \"./open-hi-app\";\nimport { OpenHiEnvironment } from \"./open-hi-environment\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-stage.md\n */\n\n/**\n * Symbol used to identify OpenHiStage instances at runtime.\n *\n * @internal\n */\nconst OPEN_HI_STAGE_SYMBOL = Symbol.for(\"@openhi/constructs/core.OpenHiStage\");\n\n/**\n * Properties for creating an OpenHiStage instance.\n */\nexport interface OpenHiStageProps extends StageProps {\n /**\n * The type of the OpenHi stage.\n */\n readonly stageType: (typeof OPEN_HI_STAGE)[keyof typeof OPEN_HI_STAGE];\n}\n\n/**\n * Represents a deployment stage in the OpenHi infrastructure hierarchy.\n */\nexport class OpenHiStage extends Stage {\n /**\n * Finds the OpenHiStage that contains the given construct.\n */\n public static of(construct: IConstruct): OpenHiStage | undefined {\n return construct.node.scopes.reverse().find(OpenHiStage.isOpenHiStage);\n }\n\n /**\n * Type guard to check if a value is an OpenHiStage instance.\n */\n public static isOpenHiStage(this: void, x: any): x is OpenHiStage {\n return x !== null && typeof x === \"object\" && OPEN_HI_STAGE_SYMBOL in x;\n }\n\n /**\n * The type of this OpenHi stage.\n */\n public readonly stageType: (typeof OPEN_HI_STAGE)[keyof typeof OPEN_HI_STAGE];\n\n /**\n * Creates a new OpenHiStage instance.\n */\n constructor(\n /**\n * The OpenHiApp that this stage belongs to.\n *\n * @public\n */\n public ohApp: OpenHiApp,\n\n /**\n * Properties for configuring the stage.\n *\n * @public\n */\n public props: OpenHiStageProps,\n ) {\n super(ohApp, props.stageType, props);\n\n Object.defineProperty(this, OPEN_HI_STAGE_SYMBOL, { value: true });\n\n this.stageType = props.stageType;\n }\n\n /**\n * Gets all OpenHiEnvironment instances contained within this stage.\n */\n public get environments(): Array<OpenHiEnvironment> {\n return this.node.children.filter(OpenHiEnvironment.isOpenHiEnvironment);\n }\n\n /**\n * Gets the primary OpenHiEnvironment for this stage, if one exists.\n */\n public get primaryEnvironment(): OpenHiEnvironment | undefined {\n return this.environments.find(\n (env) => env.deploymentTargetRole === \"primary\",\n );\n }\n\n /**\n * Gets all secondary OpenHiEnvironment instances for this stage.\n */\n public get secondaryEnvironments(): Array<OpenHiEnvironment> {\n return this.environments.filter(\n (env) => env.deploymentTargetRole === \"secondary\",\n );\n }\n}\n","import {\n findGitBranch,\n findGitRepoName,\n hashString,\n} from \"@codedrifters/utils\";\nimport { OPEN_HI_STAGE, OpenHiEnvironmentConfig } from \"@openhi/config\";\nimport { RemovalPolicy, Stack, StackProps, Tags } from \"aws-cdk-lib\";\nimport { paramCase } from \"change-case\";\nimport { OpenHiEnvironment } from \"./open-hi-environment\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/app/open-hi-service.md\n */\n\n/**\n * Known OpenHI service type strings. Each service class defines its own\n * static SERVICE_TYPE (e.g. OpenHiAuthService.SERVICE_TYPE === \"auth\").\n *\n * @public\n */\nexport type OpenHiServiceType =\n | \"auth\"\n | \"rest-api\"\n | \"data\"\n | \"global\"\n | \"graphql-api\";\n\n/**\n * Tag-key suffixes applied by every OpenHiService stack via Tags.of().\n * Full keys are composed `${appName}:${suffix}` — see {@link openHiTagKey}.\n * Consumers that filter or project these tags (e.g. the platform-deploy\n * bridge) import these suffixes rather than redeclaring the strings.\n *\n * @public\n */\nexport const OPENHI_TAG_SUFFIX_REPO_NAME = \"repo-name\";\n/** @public */\nexport const OPENHI_TAG_SUFFIX_BRANCH_NAME = \"branch-name\";\n/** @public */\nexport const OPENHI_TAG_SUFFIX_SERVICE_TYPE = \"service-type\";\n/** @public */\nexport const OPENHI_TAG_SUFFIX_STAGE_TYPE = \"stage-type\";\n\n/**\n * Compose a full stack-tag key from an `appName` and a suffix from\n * {@link OPENHI_TAG_SUFFIX_REPO_NAME} et al.\n *\n * @public\n */\nexport const openHiTagKey = (appName: string, suffix: string): string =>\n `${appName}:${suffix}`;\n\n/**\n * Properties for creating an {@link OpenHiService} stack.\n *\n * @public\n */\nexport interface OpenHiServiceProps extends StackProps {\n /**\n * Optional branch name override.\n */\n readonly branchName?: string;\n\n /**\n * Optional repository name override.\n */\n readonly repoName?: string;\n\n /**\n * Optional application name override.\n */\n readonly appName?: string;\n\n /**\n * Default release branch name.\n */\n readonly defaultReleaseBranch?: string;\n\n /**\n * The removal policy for persistent stack resources.\n */\n readonly removalPolicy?: RemovalPolicy;\n\n /**\n * Environment configuration for this service.\n */\n readonly config?: OpenHiEnvironmentConfig;\n\n /**\n * A constant that identifies the service type.\n */\n readonly serviceType?: OpenHiServiceType;\n}\n\n/**\n * Represents an OpenHI service stack within the OpenHI platform.\n * Subclasses must override {@link serviceType} to return their static SERVICE_TYPE.\n */\nexport abstract class OpenHiService extends Stack {\n /**\n * The service/stack ID that was passed to the constructor.\n */\n public readonly serviceId: string;\n\n /**\n * The deployment target role identifier.\n */\n public readonly deploymentTargetRole: string;\n\n /**\n * Repository name used in resource tagging.\n */\n public readonly repoName: string;\n\n /**\n * Application name identifier.\n */\n public readonly appName: string;\n\n /**\n * Default release branch name.\n */\n public readonly defaultReleaseBranch: string;\n\n /**\n * Branch name used when calculating resource names and hashes.\n */\n public readonly branchName: string;\n\n /**\n * Short hash unique to the deployment target (app name, deployment target role, account, region).\n */\n public readonly environmentHash: string;\n\n /**\n * Short hash unique to the environment and branch combination.\n */\n public readonly branchHash: string;\n\n /**\n * Short hash unique to the specific stack/service.\n */\n public readonly stackHash: string;\n\n /**\n * The removal policy for persistent stack resources.\n */\n public readonly removalPolicy: RemovalPolicy;\n\n /**\n * Environment configuration for this service.\n * This is either the value passed in or the default config\n */\n public readonly config: OpenHiEnvironmentConfig;\n\n /**\n * Service type identifier. Override in subclasses to return the class's static SERVICE_TYPE.\n * Used for parameter names, tags, and service discovery.\n */\n abstract get serviceType(): OpenHiServiceType | string;\n\n /**\n * Creates a new OpenHI service stack.\n *\n * @param ohEnv - The OpenHI environment (stage) this service belongs to\n * @param id - Unique identifier for this service stack (e.g., \"user-service\")\n * @param props - Optional properties for configuring the service\n *\n * @throws {Error} If account and region are not defined in props or environment\n *\n */\n constructor(\n public ohEnv: OpenHiEnvironment,\n id: string,\n public props: OpenHiServiceProps = {},\n ) {\n // Determine the account and region based on environment or user passed props.\n // This must be done before calling super() as it's needed for stack naming.\n const { account, region } = props.env || ohEnv;\n if (!account || !region) {\n throw new Error(\n \"Account and region must be defined in OpenHiServiceProps or OpenHiEnvironment\",\n );\n }\n\n // Get app name from the app in the hierarchy (via environment -> stage -> app)\n const appName = props.appName ?? ohEnv.ohStage.ohApp.appName ?? \"openhi\";\n\n // Initialize deployment context properties\n // Repo name is used in tagging. This tag value is important for tracking\n // when tearing preview stacks back down. If not provided, detect from git.\n const repoName = props.repoName ?? findGitRepoName();\n\n // Default release branch is used when not in dev stage. Defaults to \"main\" if not provided.\n const defaultReleaseBranch = props.defaultReleaseBranch ?? \"main\";\n\n // Branch name is used to calculate hashes and names for resources.\n // Detection logic:\n // - If explicitly provided, use that value\n // - If Jest is running, use \"test-branch\" to avoid snapshot test issues\n // - If GIT_BRANCH_NAME env is set (e.g. by CI), use it\n // - If in dev stage, detect from git using findGitBranch()\n // - Otherwise (stage/prod), default to defaultReleaseBranch\n const branchName =\n props.branchName ??\n (process.env.JEST_WORKER_ID\n ? \"test-branch\"\n : process.env.GIT_BRANCH_NAME?.trim() ||\n (ohEnv.ohStage.stageType === OPEN_HI_STAGE.DEV\n ? findGitBranch()\n : defaultReleaseBranch));\n\n // Compute environment hash: unique to deployment target (app name, role, account, region)\n // Mainly used for DNS names and deployment-target-scoped resources\n const environmentHash = hashString(\n [appName, ohEnv.deploymentTargetRole, account, region].join(\"-\"),\n 6,\n );\n\n // Compute branch hash: unique to deployment target and branch combination\n // Useful for resources shared across stacks within the same branch\n const branchHash = hashString(\n [appName, ohEnv.deploymentTargetRole, account, region, branchName].join(\n \"-\",\n ),\n 6,\n );\n\n // Compute stack hash: unique to the specific stack/service\n // Useful for stack-specific resources like S3 buckets, KMS key aliases\n // This ensures two PR builds or different services don't collide\n const stackHash = hashString(\n [\n appName,\n ohEnv.deploymentTargetRole,\n account,\n region,\n branchName,\n id,\n ].join(\"-\"),\n 6,\n );\n\n // Set the removal policy for this stack based on the deployment target role.\n // Production stages retain resources, others destroy them on stack deletion.\n const removalPolicy =\n props.removalPolicy ??\n (ohEnv.ohStage.stageType === OPEN_HI_STAGE.PROD\n ? RemovalPolicy.RETAIN\n : RemovalPolicy.DESTROY);\n Object.assign(props, { removalPolicy });\n\n // Description to use for the stack and all resources within it.\n // Includes service ID, branch name, and hash for easy identification.\n const description = `OpenHi Service: ${id} [${branchName}] - ${branchHash}`;\n\n // Call the super constructor of Stack.\n // This initializes the AWS CDK Stack with:\n // - Scope: the OpenHI environment\n // - ID: unique stack name including branch hash\n // - Props: stack properties including description and removal policy\n super(ohEnv, [branchHash, id, account, region].join(\"-\"), {\n ...props,\n description,\n });\n\n // Store the service ID for use in deployment context and other operations.\n this.serviceId = id;\n\n // Set the removal policy for this stack based on the deployment target role.\n this.removalPolicy = removalPolicy;\n\n /**\n * Explicit config or use the environment config as a backup,\n */\n this.config = props.config ?? ohEnv.props.config;\n\n // Initialize deployment context properties directly on the service\n this.deploymentTargetRole = ohEnv.deploymentTargetRole;\n this.repoName = repoName;\n this.appName = appName;\n this.defaultReleaseBranch = defaultReleaseBranch;\n this.branchName = branchName;\n this.environmentHash = environmentHash;\n this.branchHash = branchHash;\n this.stackHash = stackHash;\n\n // Pre-populate the AZ context cache for this stack so any construct that\n // calls `stack.availabilityZones` (notably RDS DatabaseCluster, ELBs, and\n // anything else that fans out across AZs) gets concrete values without\n // triggering a CDK context lookup. Without this, CI synth records the\n // lookup as \"missing\" and deploy fails because the GitHubOpenHiDeployer\n // role can't assume `cdk-…-lookup-role-…` (only granted to dev machines\n // by default). AZ names follow the stable `<region>a/b/c…` pattern across\n // all current commercial AWS regions; if a deployment ever targets a\n // region where this assumption breaks, override here per region.\n this.node.setContext(\n `availability-zones:account=${account}:region=${region}`,\n [`${region}a`, `${region}b`, `${region}c`],\n );\n\n // Standard tagging across all resources in the stack.\n // Use id (the service type string passed to super) since abstract serviceType cannot be accessed in constructor.\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_REPO_NAME),\n repoName.slice(0, 255),\n );\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_BRANCH_NAME),\n branchName.slice(0, 255),\n );\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_SERVICE_TYPE),\n id.slice(0, 255),\n );\n Tags.of(this).add(\n openHiTagKey(appName, OPENHI_TAG_SUFFIX_STAGE_TYPE),\n ohEnv.ohStage.stageType.slice(0, 255),\n );\n }\n\n /**\n * DNS prefix for this branche's child zone.\n */\n public get childZonePrefix(): string {\n return paramCase(this.branchName).slice(0, 200);\n }\n}\n","import {\n Certificate,\n CertificateProps,\n} from \"aws-cdk-lib/aws-certificatemanager\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/acm/root-wildcard-certificate.md\n */\n\nexport class RootWildcardCertificate extends Certificate {\n /**\n * Used when storing the Certificate ARN in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"ROOT_WILDCARD_CERT_ARN\";\n\n /**\n * Using a special name here since this will be shared and used among many\n * stacks and services. Use with OpenHiGlobalService.rootWildcardCertificateFromConstruct.\n */\n public static ssmParameterName(): string {\n return (\n \"/\" +\n [\"GLOBAL\", RootWildcardCertificate.SSM_PARAM_NAME].join(\"/\").toUpperCase()\n );\n }\n\n constructor(scope: Construct, props: CertificateProps) {\n super(scope, \"root-wildcard-certificate\", { ...props });\n\n /**\n * Generate the SSM Parameter used to store this Certificate's ARN.\n */\n new StringParameter(this, \"wildcard-cert-param\", {\n parameterName: RootWildcardCertificate.ssmParameterName(),\n stringValue: this.certificateArn,\n });\n }\n}\n","import { HttpApi, HttpApiProps } from \"aws-cdk-lib/aws-apigatewayv2\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/api-gateway/root-http-api.md\n */\n\nexport interface RootHttpApiProps extends HttpApiProps {}\n\nexport class RootHttpApi extends HttpApi {\n /**\n * Used when storing the API ID in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"ROOT_HTTP_API\";\n\n constructor(scope: Construct, props: RootHttpApiProps = {}) {\n const stack = OpenHiService.of(scope) as OpenHiService;\n\n const origins = props.corsPreflight?.allowOrigins;\n if (origins?.length) {\n const withTrailingSlash = origins.filter((o) => o.endsWith(\"/\"));\n if (withTrailingSlash.length > 0) {\n throw new Error(\n `CORS allowOrigins must not include a trailing slash. The browser Origin header is scheme + host + port only (no path), so API Gateway will not match origins like \"https://example.com/\" and CORS can fail. Invalid: ${withTrailingSlash.join(\", \")}. Use e.g. \"https://example.com\" instead.`,\n );\n }\n }\n\n super(scope, \"http-api\", {\n /**\n * User provided props\n */\n ...props,\n\n /**\n * Required\n */\n apiName: [\"root\", \"http\", \"api\", stack.branchHash].join(\"-\"),\n });\n }\n}\n","import {\n Definition,\n GraphqlApi,\n GraphqlApiProps,\n IGraphqlApi,\n} from \"aws-cdk-lib/aws-appsync\";\nimport { CodeFirstSchema, GraphqlType, ObjectType } from \"awscdk-appsync-utils\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\nimport { DiscoverableStringParameter } from \"../ssm\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/app-sync/root-graphql-api.md\n */\n\nexport interface RootGraphqlApiProps extends GraphqlApiProps {}\n\nexport class RootGraphqlApi extends GraphqlApi {\n /**\n * Used when storing the GraphQl API ID in SSM\n */\n public static readonly SSM_PARAM_NAME = \"ROOT_GRAPHQL_API\";\n\n public static fromConstruct(scope: Construct): IGraphqlApi {\n const graphqlApiId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: RootGraphqlApi.SSM_PARAM_NAME,\n serviceType: \"graphql-api\",\n });\n\n return GraphqlApi.fromGraphqlApiAttributes(scope, \"root-graphql-api\", {\n graphqlApiId,\n });\n }\n\n constructor(scope: Construct, props?: Omit<RootGraphqlApiProps, \"name\">) {\n const stack = OpenHiService.of(scope) as OpenHiService;\n\n const schema = new CodeFirstSchema();\n schema.addType(\n new ObjectType(\"Query\", {\n definition: { HelloWorld: GraphqlType.string() },\n }),\n );\n\n super(scope, \"root-graphql-api\", {\n /**\n * Defaults\n */\n queryDepthLimit: 2,\n resolverCountLimit: 50,\n definition: Definition.fromSchema(schema),\n\n /**\n * Overrideable props\n */\n ...props,\n\n /**\n * Required\n */\n name: [\"root\", \"graphql\", \"api\", stack.branchHash].join(\"-\"),\n });\n\n /**\n * Generate the SSM Parameter used to store this GraphQL API's ID.\n */\n new DiscoverableStringParameter(this, \"graphql-api-param\", {\n ssmParamName: RootGraphqlApi.SSM_PARAM_NAME,\n serviceType: \"graphql-api\",\n stringValue: this.apiId,\n });\n }\n}\n","import { Tags } from \"aws-cdk-lib\";\nimport {\n StringParameter,\n type StringParameterProps,\n} from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/ssm/discoverable-string-parameter.md\n */\n\n/*******************************************************************************\n *\n * DiscoverableStringParameterProps: props for creating or looking up SSM\n * parameters. Includes StringParameterProps (minus parameterName) plus\n * name-building fields used by buildParameterName.\n *\n ******************************************************************************/\n\nexport interface DiscoverableStringParameterProps extends Omit<\n StringParameterProps,\n \"parameterName\"\n> {\n /**\n * SSM param name used to build the SSM parameter name via buildParameterName\n * and stored as a tag on the parameter for discoverability.\n */\n readonly ssmParamName: string;\n\n /**\n * The environment hash the parameter belongs to.\n * @default - the current stack's environment hash\n */\n readonly branchHash?: string;\n\n /**\n * The service type the parameter belongs to.\n * @default - the current stack's service type\n */\n readonly serviceType?: string;\n\n /**\n * The AWS account the parameter belongs to.\n * @default - the current stack's account\n */\n readonly account?: string;\n\n /**\n * The AWS region the parameter belongs to.\n * @default - the current stack's region\n */\n readonly region?: string;\n}\n\n/**\n * Props for buildParameterName and valueForLookupName.\n * Includes ssmParamName (required) and optional overrides (branchHash, serviceType, account, region).\n */\nexport type BuildParameterNameProps = Pick<\n DiscoverableStringParameterProps,\n \"ssmParamName\" | \"branchHash\" | \"serviceType\" | \"account\" | \"region\"\n>;\n\n/**\n * Discoverable SSM string parameter construct. Extends CDK StringParameter:\n * builds parameterName from the given name via buildParameterName and tags\n * the parameter with the name constant.\n */\nexport class DiscoverableStringParameter extends StringParameter {\n /**\n * Version of the parameter name format / discoverability schema.\n * Bump when buildParameterName or tagging semantics change.\n * Also used to drive replacement of parameters during CloudFormation deploys.\n */\n public static readonly version = \"v1\";\n\n /**\n * Build a param name based on predictable attributes found in services and\n * constructs. Used for storage and retrieval of SSM values across services.\n */\n public static buildParameterName(\n scope: Construct,\n props: BuildParameterNameProps,\n ): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return (\n \"/\" +\n [\n DiscoverableStringParameter.version,\n props.branchHash ?? stack.branchHash,\n props.serviceType ?? stack.serviceType,\n props.account ?? stack.account,\n props.region ?? stack.region,\n props.ssmParamName,\n ]\n .join(\"/\")\n .toUpperCase()\n );\n }\n\n /**\n * Read the string value of an SSM parameter created with DiscoverableStringParameter,\n * using props that include ssmParamName and optional overrides (e.g. serviceType).\n */\n public static valueForLookupName(\n scope: Construct,\n props: BuildParameterNameProps,\n ): string {\n const paramName = DiscoverableStringParameter.buildParameterName(\n scope,\n props,\n );\n return StringParameter.valueForStringParameter(scope, paramName);\n }\n\n constructor(\n scope: Construct,\n id: string,\n props: DiscoverableStringParameterProps,\n ) {\n const { ssmParamName, branchHash, serviceType, account, region, ...rest } =\n props;\n\n const parameterName = DiscoverableStringParameter.buildParameterName(\n scope,\n props,\n );\n\n super(scope, id + \"-\" + DiscoverableStringParameter.version, {\n ...rest,\n parameterName,\n });\n\n const { appName } = OpenHiService.of(scope) as OpenHiService;\n Tags.of(this).add(`${appName}:param-name`, ssmParamName);\n }\n}\n","import { Duration } from \"aws-cdk-lib\";\nimport {\n IUserPool,\n UserPoolClient,\n UserPoolClientProps,\n} from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\n\nexport interface CognitoFixtureSeederClientProps extends Partial<\n Omit<UserPoolClientProps, \"userPool\" | \"generateSecret\">\n> {\n readonly userPool: IUserPool;\n}\n\n/**\n * Dedicated Cognito app client for the OpenHI fixture-seeder CLI\n * (`@openhi/seed-fixtures`).\n *\n * Why a dedicated client (vs reusing the SPA client):\n * - Tightly scoped: only the seeder consumes tokens issued here, so an\n * audit trail of seeder activity is cleanly separable.\n * - Decoupled from the SPA client's OAuth flows — no risk of breaking\n * web-app sign-in by tweaking auth-flow settings here.\n * - Stage-conditional creation upstream (only provisioned in non-prod\n * environments) means prod stacks never carry a code path that could\n * issue a fixture-seeder token in the first place.\n *\n * Why USER_PASSWORD_AUTH (vs M2M client-credentials):\n * - Cognito's M2M tier has a per-app-client monthly fee plus per-token\n * activity charges. For sporadic non-prod fixture runs the per-client\n * fee dominates the bill, especially if every dev branch spins up\n * its own auth stack.\n * - USER_PASSWORD_AUTH against a service `fixture-seeder` user keeps\n * the cost in MAU territory (free under the 50K MAU tier).\n * - Tradeoff: passwords need rotation and the service user must be\n * provisioned per non-prod environment (manual or scripted post-deploy).\n *\n * No client secret (`generateSecret: false`): USER_PASSWORD_AUTH\n * authenticates with the password directly; a secret would just add\n * another credential to manage without strengthening anything.\n */\nexport class CognitoFixtureSeederClient extends UserPoolClient {\n /**\n * SSM parameter name suffix used to publish this client's ID for\n * cross-stack lookups. Built into a full parameter name via\n * `buildParameterName` with `serviceType` AUTH (since the auth stack\n * owns this resource).\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_FIXTURE_SEEDER_CLIENT\";\n\n constructor(scope: Construct, props: CognitoFixtureSeederClientProps) {\n const { userPool, ...rest } = props;\n super(scope, \"fixture-seeder-client\", {\n userPool,\n generateSecret: false,\n authFlows: {\n userPassword: true,\n },\n // No OAuth flows — the seeder calls Cognito's `InitiateAuth`\n // directly with USER_PASSWORD_AUTH, not through the hosted-UI\n // OAuth grant flows the SPA client uses. `disableOAuth: true`\n // causes CDK to omit `AllowedOAuthFlowsUserPoolClient` entirely;\n // passing an empty `oAuth` block instead still flips that flag on\n // and Cognito rejects the create call for missing flows/scopes.\n disableOAuth: true,\n // Short-lived tokens: a seeder run takes seconds, not hours.\n // 1h access-token validity is the minimum Cognito permits and is\n // plenty for a fixture run.\n accessTokenValidity: Duration.hours(1),\n idTokenValidity: Duration.hours(1),\n refreshTokenValidity: Duration.days(1),\n preventUserExistenceErrors: true,\n ...rest,\n });\n }\n}\n","import {\n FeaturePlan,\n UserPool,\n UserPoolProps,\n VerificationEmailStyle,\n} from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool.md\n */\n\nexport class CognitoUserPool extends UserPool {\n /**\n * Used when storing the User Pool ID in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL\";\n\n constructor(scope: Construct, props: UserPoolProps = {}) {\n const service = OpenHiService.of(scope) as OpenHiService;\n\n super(scope, \"user-pool\", {\n /**\n * Defaults\n */\n selfSignUpEnabled: true,\n signInAliases: {\n email: true,\n },\n userVerification: {\n emailSubject: \"Verify your email!\",\n emailBody: \"Your verification code is {####}.\",\n emailStyle: VerificationEmailStyle.CODE,\n },\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n // Plus is required for access-token V2 claim customization in the\n // pre-token-generation Lambda. Essentials silently drops\n // claimsAndScopeOverrideDetails.accessTokenGeneration.claimsToAddOrOverride.\n featurePlan: FeaturePlan.PLUS,\n\n /**\n * Over-rideable props\n */\n ...props,\n\n /**\n * Required\n */\n userPoolName: [\"cognito\", \"user\", \"pool\", service.branchHash].join(\"-\"),\n });\n }\n}\n","import { UserPoolClient, UserPoolClientProps } from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool-client.md\n */\n\nexport class CognitoUserPoolClient extends UserPoolClient {\n /**\n * Used when storing the User Pool Client ID in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL_CLIENT\";\n\n constructor(scope: Construct, props: UserPoolClientProps) {\n super(scope, \"user-pool-client\", {\n /**\n * Defaults\n */\n generateSecret: false,\n oAuth: {\n flows: {\n authorizationCodeGrant: true,\n implicitCodeGrant: true,\n },\n callbackUrls: [`https://localhost:3000/oauth/callback`],\n },\n\n /**\n * Overrideable props\n */\n ...props,\n });\n }\n}\n","import { UserPoolDomain, UserPoolDomainProps } from \"aws-cdk-lib/aws-cognito\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool-domain.md\n */\n\nexport class CognitoUserPoolDomain extends UserPoolDomain {\n /**\n * Used when storing the User Pool Domain in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL_DOMAIN\";\n\n constructor(scope: Construct, props: UserPoolDomainProps) {\n /**\n * This supports both custom and native Cognito domains, but we need to\n * name them uniquely so that swap outs work and don't cause conflicts\n * when cloudformation does it's deploy.\n */\n const id = props.cognitoDomain?.domainPrefix\n ? \"cognito-domain\"\n : \"custom-domain\";\n\n super(scope, id, {\n ...props,\n });\n }\n}\n","import { Key, KeyProps } from \"aws-cdk-lib/aws-kms\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/cognito-user-pool-kms-key.md\n */\n\nexport class CognitoUserPoolKmsKey extends Key {\n /**\n * Used when storing the KMS Key in SSM.\n */\n public static readonly SSM_PARAM_NAME = \"COGNITO_USER_POOL_KMS_KEY\";\n\n constructor(scope: Construct, props: KeyProps = {}) {\n const service = OpenHiService.of(scope) as OpenHiService;\n\n super(scope, \"kms-key\", {\n ...props,\n // alias: [\"alias\", \"cognito\", service.branchHash].join(\"/\"),\n description: `KMS Key for Cognito User Pool - ${service.branchHash}`,\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/post-authentication-lambda.md\n */\n\nconst HANDLER_NAME = \"post-authentication.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\n/**\n * Lambda used as Cognito Post Authentication trigger.\n */\nexport class PostAuthenticationLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct) {\n super(scope, \"post-authentication-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/post-confirmation-lambda.md\n */\n\nconst HANDLER_NAME = \"post-confirmation.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nconst resolveHandlerEntry = (dirname: string): string => {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n};\n\nexport interface PostConfirmationLambdaProps {\n /**\n * Control-plane EventBridge bus name. Passed to the Lambda as\n * CONTROL_EVENT_BUS_NAME so it can publish onboarding workflow events.\n */\n readonly controlEventBusName: string;\n}\n\n/**\n * Lambda used as Cognito Post Confirmation trigger. It publishes a control\n * event and returns quickly; workflow Lambdas own provisioning.\n */\nexport class PostConfirmationLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, props: PostConfirmationLambdaProps) {\n super(scope, \"post-confirmation-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n CONTROL_EVENT_BUS_NAME: props.controlEventBusName,\n },\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/cognito/pre-token-generation-lambda.md\n */\n\nconst HANDLER_NAME = \"pre-token-generation.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\nexport interface PreTokenGenerationLambdaProps {\n /**\n * DynamoDB data store table name. Passed to the Lambda as DYNAMO_TABLE_NAME\n * so the control-plane ElectroDB service reads the User by Cognito `sub`\n * (GSI2) and the user's first active Membership (fallback path).\n */\n readonly dynamoTableName: string;\n}\n\n/**\n * Lambda used as Cognito Pre Token Generation trigger. Resolves the OpenHI\n * User from the request's Cognito `sub` and injects `ohi_tid`, `ohi_wid`,\n * `ohi_uid`, `ohi_uname` into both the ID token and the access token\n * (ADR 2026-03-17-01).\n */\nexport class PreTokenGenerationLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, props: PreTokenGenerationLambdaProps) {\n super(scope, \"pre-token-generation-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n DYNAMO_TABLE_NAME: props.dynamoTableName,\n },\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration, RemovalPolicy, Size } from \"aws-cdk-lib\";\nimport * as events from \"aws-cdk-lib/aws-events\";\nimport * as kinesis from \"aws-cdk-lib/aws-kinesis\";\nimport * as kinesisfirehose from \"aws-cdk-lib/aws-kinesisfirehose\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport * as s3 from \"aws-cdk-lib/aws-s3\";\nimport { Construct } from \"constructs\";\n\nconst HANDLER_NAME = \"firehose-archive-transform.handler.js\";\n\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n return path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface DataStoreHistoricalArchiveProps {\n /**\n * Kinesis stream that receives DynamoDB item-level changes (table Kinesis destination).\n */\n readonly kinesisStream: kinesis.IStream;\n /**\n * Removal policy for the archive bucket and related resources.\n */\n readonly removalPolicy: RemovalPolicy;\n /**\n * Short hash for unique stream/bucket naming within the deployment.\n */\n readonly stackHash: string;\n /**\n * When set, the Firehose transform Lambda publishes qualifying changes to\n * this bus via PutEvents (ADR 2026-03-02-01).\n */\n readonly dataEventBus?: events.IEventBus;\n}\n\n/**\n * DynamoDB change stream → Kinesis → Firehose → S3 with a transform Lambda for\n * scope filtering and dynamic partitioning (ADR 2026-03-11-02). The same Lambda\n * publishes qualifying current-resource changes to the data event bus (ADR 2026-03-02-01)\n * when {@link DataStoreHistoricalArchiveProps.dataEventBus} is set.\n */\nexport class DataStoreHistoricalArchive extends Construct {\n public readonly archiveBucket: s3.Bucket;\n /**\n * Receives PutEvents payloads that still fail after in-Lambda retries when\n * {@link DataStoreHistoricalArchiveProps.dataEventBus} is configured.\n */\n public readonly putEventsFailureDlqBucket?: s3.Bucket;\n public readonly deliveryStream: kinesisfirehose.IDeliveryStream;\n public readonly transformFunction: NodejsFunction;\n\n constructor(\n scope: Construct,\n id: string,\n props: DataStoreHistoricalArchiveProps,\n ) {\n super(scope, id);\n\n this.archiveBucket = new s3.Bucket(this, \"ArchiveBucket\", {\n blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,\n encryption: s3.BucketEncryption.S3_MANAGED,\n enforceSSL: true,\n removalPolicy: props.removalPolicy,\n autoDeleteObjects: props.removalPolicy === RemovalPolicy.DESTROY,\n versioned: true,\n });\n\n const putEventsFailureDlqBucket = props.dataEventBus\n ? new s3.Bucket(this, \"PutEventsFailureDlq\", {\n blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,\n encryption: s3.BucketEncryption.S3_MANAGED,\n enforceSSL: true,\n removalPolicy: props.removalPolicy,\n autoDeleteObjects: props.removalPolicy === RemovalPolicy.DESTROY,\n versioned: false,\n })\n : undefined;\n this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;\n\n this.transformFunction = new NodejsFunction(this, \"FirehoseTransform\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n description:\n \"Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents\",\n environment:\n props.dataEventBus && putEventsFailureDlqBucket\n ? {\n DATA_EVENT_BUS_NAME: props.dataEventBus.eventBusName,\n DATA_STORE_PUT_EVENTS_DLQ_BUCKET:\n putEventsFailureDlqBucket.bucketName,\n }\n : undefined,\n bundling: {\n minify: true,\n sourceMap: false,\n },\n });\n\n props.dataEventBus?.grantPutEventsTo(this.transformFunction);\n putEventsFailureDlqBucket?.grantPut(this.transformFunction);\n\n const processor = new kinesisfirehose.LambdaFunctionProcessor(\n this.transformFunction,\n {\n bufferInterval: Duration.seconds(60),\n bufferSize: Size.mebibytes(3),\n retries: 3,\n },\n );\n\n const destination = new kinesisfirehose.S3Bucket(this.archiveBucket, {\n compression: kinesisfirehose.Compression.GZIP,\n bufferingInterval: Duration.seconds(300),\n // Firehose requires SizeInMBs ≥ 64 when dynamic partitioning is enabled.\n bufferingSize: Size.mebibytes(64),\n processors: [processor],\n errorOutputPrefix:\n \"errors/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd/HH}/\",\n loggingConfig: new kinesisfirehose.EnableLogging(),\n });\n\n this.deliveryStream = new kinesisfirehose.DeliveryStream(\n this,\n \"ArchiveDeliveryStream\",\n {\n deliveryStreamName: `openhi-dstore-arch-${props.stackHash}`,\n source: new kinesisfirehose.KinesisStreamSource(props.kinesisStream),\n destination,\n },\n );\n\n const cfn = this.deliveryStream.node\n .defaultChild as kinesisfirehose.CfnDeliveryStream;\n cfn.addPropertyOverride(\n \"ExtendedS3DestinationConfiguration.DynamicPartitioningConfiguration\",\n {\n Enabled: true,\n RetryOptions: { DurationInSeconds: 300 },\n },\n );\n cfn.addPropertyOverride(\n \"ExtendedS3DestinationConfiguration.Prefix\",\n \"!{partitionKeyFromLambda:tenantId}/!{partitionKeyFromLambda:workspaceId}/!{partitionKeyFromLambda:resourceType}/!{partitionKeyFromLambda:resourceId}/!{partitionKeyFromLambda:version}/\",\n );\n }\n}\n","import { RemovalPolicy } from \"aws-cdk-lib\";\nimport {\n AttributeType,\n BillingMode,\n ProjectionType,\n Table,\n TableProps,\n} from \"aws-cdk-lib/aws-dynamodb\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/dynamodb/dynamo-db-data-store.md\n */\n\n/**\n * DynamoDB table name for the data store. Used for cross-stack reference and\n * deterministic naming per branch. The table backs the app data store.\n */\nexport function getDynamoDbDataStoreTableName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `data-store-${stack.branchHash}`;\n}\n\nexport interface DynamoDbDataStoreProps extends Omit<\n TableProps,\n \"tableName\" | \"removalPolicy\"\n> {\n /**\n * Optional removal policy override. If not set, uses the service's default\n * removal policy (RETAIN for prod, DESTROY otherwise).\n */\n readonly removalPolicy?: RemovalPolicy;\n}\n\n/**\n * DynamoDB table implementing the single-table design for app data (FHIR\n * resources data plane and platform control plane), per planning ADR-011 and\n * DR-004.\n *\n * @see {@link https://github.com/codedrifters/openhi/blob/main/sites/www-docs/content/architecture/dynamodb-single-table-design.md | DynamoDB Single-Table Design}\n *\n * Primary key: PK (String), SK (String).\n *\n * GSIs:\n * - **GSI1 — Unified Sharded List** (`GSI1PK`/`GSI1SK`, INCLUDE projection per\n * DR-004). Primary list/lookup index for both data-plane FHIR resources and\n * control-plane entities (User, Tenant, Workspace, Membership, Role,\n * RoleAssignment, Configuration). PK shape:\n * `TID#<tid>#WID#<wid>#RT#<Type>#SHARD#<n>` with 4 shards\n * (`n = hash(id) mod 4`). SK shape per `extractSortKey`: labeled types use\n * `<normalizedLabel>#<id>`; unlabeled use `<ISO-8601 lastUpdated>#<id>`.\n * - **GSI2 — Sub-Lookup** (`GSI2PK`/`GSI2SK`, INCLUDE projection). Resolves\n * `UserEntity` from a Cognito `sub` for the Pre Token Generation Lambda.\n * PK shape: `USER#SUB#<cognitoSub>`. SK shape: `CURRENT`.\n *\n * For historical archive to S3, pass `kinesisStream` and `stream` (e.g.\n * `StreamViewType.NEW_AND_OLD_IMAGES`) on the table props per ADR 2026-03-11-02.\n */\nexport class DynamoDbDataStore extends Table {\n constructor(\n scope: Construct,\n id: string,\n props: DynamoDbDataStoreProps = {},\n ) {\n const service = OpenHiService.of(scope) as OpenHiService;\n\n super(scope, id, {\n ...props,\n tableName: getDynamoDbDataStoreTableName(scope),\n partitionKey: {\n name: \"PK\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"SK\",\n type: AttributeType.STRING,\n },\n billingMode: BillingMode.PAY_PER_REQUEST,\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n });\n\n // GSI1 — Unified Sharded List (data plane + control plane) per ADR-011 and DR-004.\n this.addGlobalSecondaryIndex({\n indexName: \"GSI1\",\n partitionKey: {\n name: \"GSI1PK\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"GSI1SK\",\n type: AttributeType.STRING,\n },\n projectionType: ProjectionType.INCLUDE,\n nonKeyAttributes: [\n \"id\",\n \"summary\",\n \"vid\",\n \"lastUpdated\",\n \"createdDate\",\n \"modifiedDate\",\n \"createdById\",\n \"modifiedById\",\n // ElectroDB filters every query result through `ownsItem`, which\n // verifies `__edb_e__` (entity name) and `__edb_v__` (version) match\n // the entity. Without these projected, every GSI1 query returns 0\n // results — list endpoints silently return empty bundles.\n \"__edb_e__\",\n \"__edb_v__\",\n ],\n });\n\n // GSI2 — Sub-Lookup: Cognito sub → UserEntity (Pre Token Generation Lambda).\n this.addGlobalSecondaryIndex({\n indexName: \"GSI2\",\n partitionKey: {\n name: \"GSI2PK\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"GSI2SK\",\n type: AttributeType.STRING,\n },\n projectionType: ProjectionType.INCLUDE,\n nonKeyAttributes: [\n \"id\",\n \"currentTenant\",\n \"currentWorkspace\",\n \"displayName\",\n // See GSI1 above: ElectroDB's `ownsItem` filter rejects items\n // without these, so any query against GSI2 returns 0 results\n // unless they're projected.\n \"__edb_e__\",\n \"__edb_v__\",\n ],\n });\n }\n}\n","import {\n WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH,\n WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR,\n} from \"@openhi/workflows\";\nimport { Annotations, RemovalPolicy } from \"aws-cdk-lib\";\nimport { AttributeType, BillingMode, Table } from \"aws-cdk-lib/aws-dynamodb\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Function } from \"aws-cdk-lib/aws-lambda\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService, type OpenHiServiceType } from \"../../app\";\nimport { DiscoverableStringParameter } from \"../ssm\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/dynamodb/workflow-dedup-table.md\n */\n\n/**\n * Deterministic table name for the shared workflow dedup table.\n * Mirrors `getDynamoDbDataStoreTableName` naming: `workflow-dedup-${branchHash}`.\n */\nexport function getWorkflowDedupTableName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `workflow-dedup-${stack.branchHash}`;\n}\n\n/** Props for `WorkflowDedupTable`. */\nexport interface WorkflowDedupTableProps {\n /**\n * Optional removal policy override. Defaults to the service's default\n * (RETAIN for prod, DESTROY otherwise).\n */\n readonly removalPolicy?: RemovalPolicy;\n}\n\n/** Options for `WorkflowDedupTable.grantConsumer`. */\nexport interface GrantConsumerOptions {\n /**\n * Override the default TTL applied by the runtime client. The 14-day\n * default lives in `@openhi/workflows`; per-consumer overrides clamp\n * shorter per TR-015. Stored in the consumer's environment so the\n * `WorkflowDedupClient` factory can pick it up.\n */\n readonly defaultTtlSeconds?: number;\n}\n\n/**\n * Shared platform-level dedup table every retryable workflow consumer\n * dedupes against. Provisioned exactly once at the platform stack.\n *\n * Schema (per TR-015):\n * - Partition key `consumerName` (S)\n * - Sort key `sk` (S) — encodes `<eventId>#<attempt>`\n * - TTL attribute `expiresAt` (N, Unix epoch seconds)\n * - On-demand billing\n *\n * @see https://github.com/codedrifters/openhi-planning/blob/main/docs/src/content/docs/requirements/technical-requirements/TR-015-workflow-dedup-table.md\n */\nexport class WorkflowDedupTable extends Construct {\n /** SSM param name (short) used by `DiscoverableStringParameter` for the table name lookup. */\n public static readonly TABLE_NAME_SSM_PARAM_NAME =\n \"workflow-dedup-table-name\";\n /** SSM param name (short) used by `DiscoverableStringParameter` for the table ARN lookup. */\n public static readonly TABLE_ARN_SSM_PARAM_NAME = \"workflow-dedup-table-arn\";\n\n /** Cross-stack lookup for the table name. */\n public static tableNameFromLookup(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME,\n serviceType: WorkflowDedupTable.PUBLISHER_SERVICE_TYPE,\n });\n }\n\n /** Cross-stack lookup for the table ARN. */\n public static tableArnFromLookup(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME,\n serviceType: WorkflowDedupTable.PUBLISHER_SERVICE_TYPE,\n });\n }\n\n /**\n * Cross-stack equivalent of {@link grantConsumer}. Use when the dedup\n * table is on a different stack than the consumer Lambda — the\n * grant resolves the table name + ARN via SSM at synth time, so the\n * consumer stack does not pick up a CloudFormation export dependency\n * on the global stack.\n *\n * Inverts the singleton-guard semantics of `grantConsumer`: there is\n * no synth-time check that the same `consumerName` was registered\n * twice across stacks. Consumer names are agreed by convention\n * (see TR-015); double-registration is operator error caught at\n * design time, not synth time.\n */\n public static grantConsumerFromLookup(\n scope: Construct,\n fn: Function,\n consumerName: string,\n options: GrantConsumerOptions = {},\n ): void {\n WorkflowDedupTable.assertConsumerNameStatic(consumerName);\n const tableName = WorkflowDedupTable.tableNameFromLookup(scope);\n const tableArn = WorkflowDedupTable.tableArnFromLookup(scope);\n\n fn.addEnvironment(WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR, tableName);\n if (options.defaultTtlSeconds !== undefined) {\n fn.addEnvironment(\n \"OPENHI_WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS\",\n String(options.defaultTtlSeconds),\n );\n }\n\n fn.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n ],\n resources: [tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": [consumerName],\n },\n },\n }),\n );\n }\n\n /**\n * Service-type the publishing stack runs under. The cross-stack lookups\n * pin to this value so consumer stacks on a different service-type\n * (e.g. `data`, `auth`) resolve the parameter at the publisher's SSM\n * path instead of their own. Typed against `OpenHiServiceType` so a\n * future rename of the literal triggers a compile error; not pulled\n * from `OpenHiGlobalService.SERVICE_TYPE` because\n * `OpenHiGlobalService` already imports `WorkflowDedupTable` — a\n * back-import would create a circular dependency.\n */\n private static readonly PUBLISHER_SERVICE_TYPE: OpenHiServiceType = \"global\";\n\n /**\n * Standalone consumer-name validator shared by the instance method\n * and `grantConsumerFromLookup` so the two grants enforce identical\n * invariants.\n */\n private static assertConsumerNameStatic(consumerName: string): void {\n if (consumerName.length === 0) {\n throw new WorkflowDedupConsumerNameInvalidError(\n \"consumerName must be non-empty.\",\n );\n }\n if (consumerName.length > WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH) {\n throw new WorkflowDedupConsumerNameInvalidError(\n `consumerName must be at most ${WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH} chars; got ${consumerName.length}.`,\n );\n }\n if (/\\s/.test(consumerName)) {\n throw new WorkflowDedupConsumerNameInvalidError(\n \"consumerName must not contain whitespace.\",\n );\n }\n }\n\n /** The underlying DynamoDB table. */\n public readonly table: Table;\n\n private readonly registeredConsumers = new Set<string>();\n\n constructor(\n scope: Construct,\n id: string,\n props: WorkflowDedupTableProps = {},\n ) {\n super(scope, id);\n\n const service = OpenHiService.of(scope) as OpenHiService;\n\n // Synth-time singleton guard: refuse a second WorkflowDedupTable in\n // the same owning service (one stack per deploy target). The check is\n // intentionally scoped to the host service rather than to the CDK\n // app root: openhi/global/src/app.ts maps over `app.environments` and\n // instantiates one `OpenHiGlobalService` per environment, and each of\n // those is a separate deployment target that owns its own dedup\n // table per TR-015.\n const others = service.node\n .findAll()\n .filter(\n (c): c is WorkflowDedupTable =>\n c instanceof WorkflowDedupTable && c !== this,\n );\n if (others.length > 0) {\n throw new WorkflowDedupTableDuplicateError(\n `WorkflowDedupTable already exists at ${others[0].node.path}; ` +\n \"only one shared dedup table is allowed per service stack (TR-015).\",\n );\n }\n\n this.table = new Table(this, \"Table\", {\n tableName: getWorkflowDedupTableName(scope),\n partitionKey: {\n name: \"consumerName\",\n type: AttributeType.STRING,\n },\n sortKey: {\n name: \"sk\",\n type: AttributeType.STRING,\n },\n billingMode: BillingMode.PAY_PER_REQUEST,\n timeToLiveAttribute: \"expiresAt\",\n removalPolicy: props.removalPolicy ?? service.removalPolicy,\n });\n\n // Publish the table name and ARN so consumer stacks can discover\n // them without a cross-stack prop dependency.\n new DiscoverableStringParameter(this, \"table-name-param\", {\n ssmParamName: WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME,\n stringValue: this.table.tableName,\n });\n new DiscoverableStringParameter(this, \"table-arn-param\", {\n ssmParamName: WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME,\n stringValue: this.table.tableArn,\n });\n }\n\n /**\n * Wire a Lambda consumer to this table. Injects the table-name env var\n * so the runtime `WorkflowDedupClient` can resolve it, then attaches a\n * per-consumer IAM grant scoped by `dynamodb:LeadingKeys` so the\n * consumer can only read/write its own partition.\n */\n public grantConsumer(\n fn: Function,\n consumerName: string,\n options: GrantConsumerOptions = {},\n ): void {\n this.assertConsumerName(consumerName);\n\n if (this.registeredConsumers.has(consumerName)) {\n Annotations.of(this).addWarning(\n `WorkflowDedupTable: consumerName \"${consumerName}\" registered more than once; ` +\n \"subsequent grantConsumer calls add policy statements but do not re-inject the env var.\",\n );\n }\n this.registeredConsumers.add(consumerName);\n\n fn.addEnvironment(WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR, this.table.tableName);\n if (options.defaultTtlSeconds !== undefined) {\n fn.addEnvironment(\n \"OPENHI_WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS\",\n String(options.defaultTtlSeconds),\n );\n }\n\n fn.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n ],\n resources: [this.table.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": [consumerName],\n },\n },\n }),\n );\n }\n\n private assertConsumerName(consumerName: string): void {\n WorkflowDedupTable.assertConsumerNameStatic(consumerName);\n }\n}\n\n/** Thrown when a second `WorkflowDedupTable` is instantiated in the same app. */\nexport class WorkflowDedupTableDuplicateError extends Error {\n /** @param message - human-readable description of the duplicate. */\n constructor(message: string) {\n super(message);\n this.name = \"WorkflowDedupTableDuplicateError\";\n }\n}\n\n/** Thrown when a consumerName violates the TR-015 invariants. */\nexport class WorkflowDedupConsumerNameInvalidError extends Error {\n /** @param message - human-readable description of the invariant violation. */\n constructor(message: string) {\n super(message);\n this.name = \"WorkflowDedupConsumerNameInvalidError\";\n }\n}\n","import { EventBus, EventBusProps } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/event-bridge/data-event-bus.md\n */\n\nexport class DataEventBus extends EventBus {\n /*****************************************************************************\n *\n * Return a name for this EventBus based on the stack environment hash. This\n * name is common across all stacks since it's using the environment hash in\n * it's name.\n *\n ****************************************************************************/\n\n public static getEventBusName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `datav1${stack.branchHash}`;\n }\n\n constructor(scope: Construct, props?: EventBusProps) {\n super(scope, \"data-event-bus-v1\", {\n ...props,\n eventBusName: DataEventBus.getEventBusName(scope),\n });\n }\n}\n","import { EventBus, EventBusProps } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/event-bridge/ops-event-bus.md\n */\n\nexport class OpsEventBus extends EventBus {\n /*****************************************************************************\n *\n * Return a name for this EventBus based on the stack environment hash. This\n * name is common across all stacks since it's using the environment hash in\n * it's name.\n *\n ****************************************************************************/\n\n public static getEventBusName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `opsv1${stack.branchHash}`;\n }\n\n constructor(scope: Construct, props?: EventBusProps) {\n super(scope, \"ops-event-bus-v1\", {\n ...props,\n eventBusName: OpsEventBus.getEventBusName(scope),\n });\n }\n}\n","import { EventBus, EventBusProps } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/event-bridge/control-event-bus.md\n */\n\nexport class ControlEventBus extends EventBus {\n /*****************************************************************************\n *\n * Return a name for this EventBus based on the stack environment hash. This\n * name is common across all stacks since it's using the environment hash in\n * its name.\n *\n ****************************************************************************/\n\n public static getEventBusName(scope: Construct): string {\n const stack = OpenHiService.of(scope) as OpenHiService;\n return `controlv1${stack.branchHash}`;\n }\n\n constructor(scope: Construct, props?: EventBusProps) {\n super(scope, \"control-event-bus-v1\", {\n ...props,\n eventBusName: ControlEventBus.getEventBusName(scope),\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration, RemovalPolicy, Stack } from \"aws-cdk-lib\";\nimport * as ec2 from \"aws-cdk-lib/aws-ec2\";\nimport * as kinesis from \"aws-cdk-lib/aws-kinesis\";\nimport { Runtime, StartingPosition } from \"aws-cdk-lib/aws-lambda\";\nimport { KinesisEventSource } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport * as rds from \"aws-cdk-lib/aws-rds\";\nimport { Construct } from \"constructs\";\nimport { DiscoverableStringParameter } from \"../ssm/discoverable-string-parameter\";\n\nconst HANDLER_NAME = \"data-store-postgres-replication.handler.js\";\nconst DEFAULT_DATABASE_NAME = \"openhi\";\nconst SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;\n\n/**\n * SSM parameter names that publish the Postgres replica's coordinates so other\n * stacks (notably the REST API stack) can discover them without a direct CDK\n * cross-stack reference. The schema name is intentionally NOT published — it\n * is a deterministic function of `branchHash` and consumers compute it locally\n * via {@link getPostgresReplicaSchemaName}.\n */\nexport const POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME =\n \"POSTGRES_REPLICA_CLUSTER_ARN\";\nexport const POSTGRES_REPLICA_SECRET_ARN_SSM_NAME =\n \"POSTGRES_REPLICA_SECRET_ARN\";\nexport const POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME =\n \"POSTGRES_REPLICA_DATABASE_NAME\";\n\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n return path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\n/**\n * Derive the per-branch Postgres schema name from a branch hash. The `b_`\n * prefix guarantees a leading letter (Postgres identifier rule). Branch hashes\n * are 6 hex chars from {@link OpenHiService.branchHash} so the resulting\n * `b_xxxxxx` is well within the 63-byte identifier limit.\n */\nexport function getPostgresReplicaSchemaName(branchHash: string): string {\n const candidate = `b_${branchHash.toLowerCase()}`;\n if (!SCHEMA_NAME_PATTERN.test(candidate)) {\n throw new Error(\n `Branch hash ${JSON.stringify(branchHash)} produces an invalid Postgres ` +\n `schema name ${JSON.stringify(candidate)}; expected /[a-z_][a-z0-9_]{0,62}/.`,\n );\n }\n return candidate;\n}\n\nexport interface DataStorePostgresReplicaProps {\n /**\n * Kinesis stream that receives DynamoDB item-level changes (the same stream\n * that backs {@link DataStoreHistoricalArchive}). The replication Lambda is\n * registered as a parallel consumer.\n */\n readonly kinesisStream: kinesis.IStream;\n /**\n * Removal policy for the cluster, secret, and dependent resources.\n */\n readonly removalPolicy: RemovalPolicy;\n /**\n * Short hash unique to the stack — used in the cluster identifier.\n */\n readonly stackHash: string;\n /**\n * Short hash unique to the branch — used to derive the per-branch schema\n * name (`b_<branchHash>`) inside the Postgres database.\n */\n readonly branchHash: string;\n /**\n * Optional VPC override. If absent, the construct creates a minimal isolated\n * VPC (2 AZs, no NAT gateways) just for the cluster and replication Lambda.\n */\n readonly vpc?: ec2.IVpc;\n /**\n * Optional database name override.\n * @default \"openhi\"\n */\n readonly databaseName?: string;\n /**\n * Aurora Serverless v2 minimum capacity in ACUs. Defaults to 1 so the\n * writer stays warm — avoids the ~10–20s scale-up wait that a cold\n * (0 ACU) cluster imposes on the next request. Set explicitly to 0 to\n * opt back into scale-to-zero if idle cost becomes the dominant concern.\n */\n readonly minCapacity?: number;\n /**\n * Aurora Serverless v2 maximum capacity in ACUs. Defaults to 2 — adequate\n * for the PoC's replication-only workload.\n */\n readonly maxCapacity?: number;\n}\n\n/**\n * DynamoDB change stream → Postgres replication tier (ADR 2026-04-17-01,\n * phase 1). Provisions an Aurora Serverless v2 PostgreSQL cluster and a\n * Lambda consumer on the existing change-stream that projects each current\n * FHIR resource into a JSONB `resources` table under a per-branch schema.\n *\n * Phase 1 is replication-only; query routing and SearchParameter-specific\n * indexes are intentionally deferred. Per-branch *clusters* (rather than the\n * shared cluster suggested by the ADR) are an explicit PoC simplification —\n * see the ADR's \"Operational notes\" section for the long-term direction.\n *\n * @see sites/www-docs/content/architecture/adr/2026-04-17-01-ad-hoc-query-support-fhir-api.md\n */\nexport class DataStorePostgresReplica extends Construct {\n /**\n * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.\n * Use from any stack that needs to grant `rds-data:ExecuteStatement` against\n * the cluster.\n */\n public static clusterArnFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,\n serviceType: \"data\",\n });\n }\n\n /**\n * Resolve the credentials secret ARN published by an upstream\n * {@link DataStorePostgresReplica}. Use from any stack that needs to grant\n * `secretsmanager:GetSecretValue` against the secret.\n */\n public static secretArnFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,\n serviceType: \"data\",\n });\n }\n\n /**\n * Resolve the database name published by an upstream\n * {@link DataStorePostgresReplica}.\n */\n public static databaseNameFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,\n serviceType: \"data\",\n });\n }\n\n public readonly vpc: ec2.IVpc;\n public readonly cluster: rds.DatabaseCluster;\n public readonly replicationFunction: NodejsFunction;\n public readonly databaseName: string;\n public readonly schemaName: string;\n\n constructor(\n scope: Construct,\n id: string,\n props: DataStorePostgresReplicaProps,\n ) {\n super(scope, id);\n\n this.databaseName = props.databaseName ?? DEFAULT_DATABASE_NAME;\n this.schemaName = getPostgresReplicaSchemaName(props.branchHash);\n\n // Pass explicit AZ names (derived from the stack region) instead of using\n // `maxAzs`, which triggers a CDK availability-zones context lookup. CI's\n // synth step doesn't have full deploy-account creds, so an unresolved AZ\n // lookup gets recorded as \"missing\" in the cdk.out manifest and the deploy\n // step then refuses to proceed. AWS region AZ names follow a stable\n // `<region>a/b/c…` pattern across all current commercial regions.\n const region = Stack.of(this).region;\n this.vpc =\n props.vpc ??\n new ec2.Vpc(this, \"Vpc\", {\n availabilityZones: [`${region}a`, `${region}b`],\n natGateways: 0,\n subnetConfiguration: [\n {\n name: \"isolated\",\n subnetType: ec2.SubnetType.PRIVATE_ISOLATED,\n cidrMask: 24,\n },\n ],\n });\n\n this.cluster = new rds.DatabaseCluster(this, \"Cluster\", {\n clusterIdentifier: `openhi-dstore-pg-${props.stackHash}`,\n engine: rds.DatabaseClusterEngine.auroraPostgres({\n version: rds.AuroraPostgresEngineVersion.VER_16_4,\n }),\n vpc: this.vpc,\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },\n writer: rds.ClusterInstance.serverlessV2(\"writer\"),\n serverlessV2MinCapacity: props.minCapacity ?? 1,\n serverlessV2MaxCapacity: props.maxCapacity ?? 2,\n defaultDatabaseName: this.databaseName,\n credentials: rds.Credentials.fromGeneratedSecret(\"openhi_admin\"),\n storageEncrypted: true,\n removalPolicy: props.removalPolicy,\n // Phase 2 of ADR 2026-04-17-01: the REST API Lambda queries Postgres\n // via the RDS Data API (HTTPS) so it can stay out of the cluster's VPC.\n // Direct `pg` from the replication Lambda continues to work in parallel.\n enableDataApi: true,\n });\n\n this.publishCoordinatesToSsm();\n\n this.replicationFunction = new NodejsFunction(this, \"ReplicationFunction\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n vpc: this.vpc,\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },\n description:\n \"Replicates DynamoDB current-resource changes into the Postgres `resources` JSONB table (ADR 2026-04-17-01).\",\n environment: {\n OPENHI_PG_HOST: this.cluster.clusterEndpoint.hostname,\n OPENHI_PG_PORT: this.cluster.clusterEndpoint.port.toString(),\n OPENHI_PG_DATABASE: this.databaseName,\n OPENHI_PG_SCHEMA: this.schemaName,\n OPENHI_PG_SECRET_ARN: this.cluster.secret!.secretArn,\n OPENHI_PG_SSL: \"true\",\n },\n bundling: {\n minify: true,\n sourceMap: false,\n // pg has conditional/optional deps (pg-native, pg-cloudflare) that\n // historically misbehave when bundled by esbuild; keep it as a real\n // node_module in the Lambda zip instead.\n nodeModules: [\"pg\"],\n },\n });\n\n this.cluster.secret!.grantRead(this.replicationFunction);\n this.cluster.connections.allowDefaultPortFrom(this.replicationFunction);\n\n this.replicationFunction.addEventSource(\n new KinesisEventSource(props.kinesisStream, {\n startingPosition: StartingPosition.LATEST,\n batchSize: 100,\n maxBatchingWindow: Duration.seconds(5),\n retryAttempts: 10,\n bisectBatchOnError: true,\n parallelizationFactor: 2,\n reportBatchItemFailures: true,\n }),\n );\n }\n\n /**\n * Publishes the cluster ARN, secret ARN, and database name as discoverable\n * SSM parameters so the REST API stack (and any future read-side consumer)\n * can wire RDS Data API access without a direct CDK cross-stack reference.\n */\n private publishCoordinatesToSsm(): void {\n new DiscoverableStringParameter(this, \"cluster-arn-param\", {\n ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,\n stringValue: this.cluster.clusterArn,\n description:\n \"ARN of the Aurora Serverless v2 cluster backing the Postgres replication tier (ADR 2026-04-17-01).\",\n });\n new DiscoverableStringParameter(this, \"secret-arn-param\", {\n ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,\n stringValue: this.cluster.secret!.secretArn,\n description:\n \"ARN of the Secrets Manager secret with credentials for the Postgres replication tier.\",\n });\n new DiscoverableStringParameter(this, \"database-name-param\", {\n ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,\n stringValue: this.databaseName,\n description: \"Database name within the Postgres replication cluster.\",\n });\n }\n}\n","import { Duration } from \"aws-cdk-lib\";\nimport {\n HostedZone,\n HostedZoneProps,\n IHostedZone,\n NsRecord,\n} from \"aws-cdk-lib/aws-route53\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/route-53/child-hosted-zone.md\n */\n\nexport interface ChildHostedZoneProps extends HostedZoneProps {\n /**\n * The root zone we will attach this sub-zone to.\n */\n readonly parentHostedZone: IHostedZone;\n}\n\nexport class ChildHostedZone extends HostedZone {\n /**\n * Used when storing the child zone ID in SSM. Use {@link OpenHiGlobalService.childHostedZoneFromConstruct} to look up.\n */\n public static readonly SSM_PARAM_NAME = \"CHILDHOSTEDZONE\";\n\n constructor(scope: Construct, id: string, props: ChildHostedZoneProps) {\n super(scope, id, { ...props });\n\n /**\n * Chain the child zone to the parent zone using NS record.\n */\n new NsRecord(this, \"child-ns-record\", {\n zone: props.parentHostedZone,\n recordName: this.zoneName,\n values: this.hostedZoneNameServers || [],\n ttl: Duration.minutes(5),\n });\n }\n}\n","import { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/components/route-53/root-hosted-zone.md\n */\n\n/**\n * Placeholder for root hosted zone. Use {@link OpenHiGlobalService.rootHostedZoneFromConstruct}\n * to obtain an IHostedZone from attributes (e.g. from config). The root zone is always\n * created manually and imported via config.\n */\nexport class RootHostedZone extends Construct {}\n","import {\n CachePolicy,\n Distribution,\n type DistributionProps,\n} from \"aws-cdk-lib/aws-cloudfront\";\nimport { S3BucketOrigin } from \"aws-cdk-lib/aws-cloudfront-origins\";\nimport { Bucket, type BucketProps, type IBucket } from \"aws-cdk-lib/aws-s3\";\nimport { Duration } from \"aws-cdk-lib/core\";\nimport { Construct } from \"constructs\";\nimport { OpenHiService } from \"../../app\";\nimport { DiscoverableStringParameter } from \"../ssm\";\n\n/**\n * Service type for the website service. Used in SSM parameter paths and by\n * OpenHiWebsiteService for fromConstruct() lookups.\n */\nexport const STATIC_HOSTING_SERVICE_TYPE = \"website\";\n\n/**\n * Props for the StaticHosting construct.\n */\nexport interface StaticHostingProps {\n /**\n * Optional S3 bucket props. Bucket name must not be set statically.\n */\n readonly bucketProps?: Omit<BucketProps, \"bucketName\">;\n\n /**\n * Optional CloudFront distribution props. Do not enable invalidation.\n * Default TTL is 10 seconds via a custom cache policy.\n */\n readonly distributionProps?: Omit<\n DistributionProps,\n \"defaultBehavior\" | \"defaultRootObject\"\n >;\n\n /**\n * Service type for SSM parameter paths.\n * @default STATIC_HOSTING_SERVICE_TYPE (\"website\")\n */\n readonly serviceType?: string;\n}\n\n/**\n * Static hosting: S3 bucket (private) + CloudFront distribution with Origin\n * Access Control (OAC). Stores bucket ARN and distribution ARN in SSM via\n * DiscoverableStringParameter for cross-stack lookup. No cache invalidation;\n * default TTL 10 seconds.\n */\nexport class StaticHosting extends Construct {\n /**\n * SSM parameter name for the S3 bucket ARN.\n */\n public static readonly SSM_PARAM_NAME_BUCKET_ARN =\n \"STATIC_HOSTING_BUCKET_ARN\";\n\n /**\n * SSM parameter name for the CloudFront distribution ARN.\n */\n public static readonly SSM_PARAM_NAME_DISTRIBUTION_ARN =\n \"STATIC_HOSTING_DISTRIBUTION_ARN\";\n\n public readonly bucket: IBucket;\n public readonly distribution: Distribution;\n\n constructor(scope: Construct, id: string, props: StaticHostingProps = {}) {\n super(scope, id);\n\n const stack = OpenHiService.of(scope) as OpenHiService;\n const serviceType = props.serviceType ?? STATIC_HOSTING_SERVICE_TYPE;\n\n this.bucket = new Bucket(this, \"bucket\", {\n blockPublicAccess: {\n blockPublicAcls: true,\n blockPublicPolicy: true,\n ignorePublicAcls: true,\n restrictPublicBuckets: true,\n },\n ...props.bucketProps,\n });\n\n const origin = S3BucketOrigin.withOriginAccessControl(this.bucket);\n\n const cachePolicy = new CachePolicy(this, \"cache-policy\", {\n cachePolicyName: `static-hosting-10s-${stack.branchHash}`,\n comment: \"Low TTL (10s) for static hosting; no invalidation\",\n defaultTtl: Duration.seconds(10),\n minTtl: Duration.seconds(0),\n maxTtl: Duration.seconds(10),\n });\n\n this.distribution = new Distribution(this, \"distribution\", {\n defaultBehavior: {\n origin,\n cachePolicy,\n },\n ...props.distributionProps,\n });\n\n new DiscoverableStringParameter(this, \"bucket-arn-param\", {\n ssmParamName: StaticHosting.SSM_PARAM_NAME_BUCKET_ARN,\n serviceType,\n stringValue: this.bucket.bucketArn,\n });\n\n new DiscoverableStringParameter(this, \"distribution-arn-param\", {\n ssmParamName: StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN,\n serviceType,\n stringValue: this.distribution.distributionArn,\n });\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport {\n IUserPool,\n IUserPoolClient,\n IUserPoolDomain,\n LambdaVersion,\n UserPool,\n UserPoolClient,\n UserPoolDomain,\n UserPoolOperation,\n UserPoolProps,\n} from \"aws-cdk-lib/aws-cognito\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { IKey, Key } from \"aws-cdk-lib/aws-kms\";\nimport { IFunction } from \"aws-cdk-lib/aws-lambda\";\nimport { Stack } from \"aws-cdk-lib/core\";\nimport { Construct } from \"constructs\";\nimport { OpenHiDataService } from \"./open-hi-data-service\";\nimport { OpenHiGlobalService } from \"./open-hi-global-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { CognitoFixtureSeederClient } from \"../components/cognito/cognito-fixture-seeder-client\";\nimport { CognitoUserPool } from \"../components/cognito/cognito-user-pool\";\nimport { CognitoUserPoolClient } from \"../components/cognito/cognito-user-pool-client\";\nimport { CognitoUserPoolDomain } from \"../components/cognito/cognito-user-pool-domain\";\nimport { CognitoUserPoolKmsKey } from \"../components/cognito/cognito-user-pool-kms-key\";\nimport { PostAuthenticationLambda } from \"../components/cognito/post-authentication-lambda\";\nimport { PostConfirmationLambda } from \"../components/cognito/post-confirmation-lambda\";\nimport { PreTokenGenerationLambda } from \"../components/cognito/pre-token-generation-lambda\";\nimport { DiscoverableStringParameter } from \"../components/ssm\";\nimport { UserOnboardingWorkflow } from \"../workflows/control-plane/user-onboarding\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-auth-service.md\n */\n\nexport interface OpenHiAuthServiceProps extends OpenHiServiceProps {\n /**\n * Optional props for the Cognito User Pool.\n */\n readonly userPoolProps?: UserPoolProps;\n}\n\n/**\n * OpenHI Auth Service stack.\n *\n * @remarks\n * The Auth service manages authentication infrastructure including:\n * - Cognito User Pool for user management and authentication\n * - User Pool Client for application integration\n * - User Pool Domain for hosting the Cognito hosted UI\n * - KMS Key for Cognito User Pool encryption\n *\n * Resources are created in protected methods; subclasses may override to customize.\n * Other stacks obtain auth by calling **OpenHiAuthService.userPoolFromConstruct(scope)**,\n * **OpenHiAuthService.userPoolClientFromConstruct(scope)**,\n * **OpenHiAuthService.userPoolDomainFromConstruct(scope)**,\n * and **OpenHiAuthService.userPoolKmsKeyFromConstruct(scope)** for each resource needed.\n *\n * Only one instance of the auth service should exist per environment.\n *\n * @public\n */\nexport class OpenHiAuthService extends OpenHiService {\n static readonly SERVICE_TYPE = \"auth\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.\n */\n static userPoolFromConstruct(scope: Construct): IUserPool {\n const userPoolId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoUserPool.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return UserPool.fromUserPoolId(scope, \"user-pool\", userPoolId);\n }\n\n /**\n * Returns an IUserPoolClient by looking up the Auth stack's User Pool Client ID from SSM.\n */\n static userPoolClientFromConstruct(scope: Construct): IUserPoolClient {\n const userPoolClientId = DiscoverableStringParameter.valueForLookupName(\n scope,\n {\n ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n },\n );\n return UserPoolClient.fromUserPoolClientId(\n scope,\n \"user-pool-client\",\n userPoolClientId,\n );\n }\n\n /**\n * Returns the dedicated fixture-seeder IUserPoolClient by looking up\n * its ID from SSM. Only non-prod auth stacks publish this parameter\n * (per the conditional in {@link createFixtureSeederClient}); calling\n * this against a prod-deployed stack will fail at lookup time.\n *\n * Consumed by `OpenHiRestApiService` (in non-prod) so the authorizer\n * accepts tokens issued by this client, and by the seed-fixtures CLI\n * to drive USER_PASSWORD_AUTH against this client's ID.\n */\n static fixtureSeederClientFromConstruct(scope: Construct): IUserPoolClient {\n const clientId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return UserPoolClient.fromUserPoolClientId(\n scope,\n \"fixture-seeder-client\",\n clientId,\n );\n }\n\n /**\n * Returns an IUserPoolDomain by looking up the Auth stack's User Pool Domain from SSM.\n */\n static userPoolDomainFromConstruct(scope: Construct): IUserPoolDomain {\n const domainName = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return UserPoolDomain.fromDomainName(scope, \"user-pool-domain\", domainName);\n }\n\n /**\n * Returns an IKey (KMS) by looking up the Auth stack's User Pool KMS Key ARN from SSM.\n */\n static userPoolKmsKeyFromConstruct(scope: Construct): IKey {\n const keyArn = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,\n serviceType: OpenHiAuthService.SERVICE_TYPE,\n });\n return Key.fromKeyArn(scope, \"kms-key\", keyArn);\n }\n\n get serviceType(): string {\n return OpenHiAuthService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options (e.g. userPoolProps). */\n public override props: OpenHiAuthServiceProps;\n\n public readonly userPoolKmsKey: IKey;\n public readonly preTokenGenerationLambda: IFunction;\n public readonly postAuthenticationLambda: IFunction;\n public readonly postConfirmationLambda: IFunction;\n public readonly userOnboardingWorkflow: UserOnboardingWorkflow;\n public readonly userPool: IUserPool;\n public readonly userPoolClient: IUserPoolClient;\n public readonly userPoolDomain: IUserPoolDomain;\n /**\n * Dedicated USER_PASSWORD_AUTH client for the seed-fixtures CLI.\n * Only created in non-prod environments (see\n * {@link createFixtureSeederClient}). `undefined` in prod.\n */\n public readonly fixtureSeederClient?: IUserPoolClient;\n\n /**\n * Cross-stack reference to the data store table. Cached so repeated\n * lookups share a single CDK construct id (\"dynamo-db-data-store\") in\n * this stack — a second `Table.fromTableName` call under the same scope\n * would collide.\n */\n private _dataStoreTable: ReturnType<\n typeof OpenHiDataService.dynamoDbDataStoreFromConstruct\n > | null = null;\n private _controlEventBus: IEventBus | null = null;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiAuthServiceProps = {}) {\n super(ohEnv, OpenHiAuthService.SERVICE_TYPE, props);\n this.props = props;\n\n this.userPoolKmsKey = this.createUserPoolKmsKey();\n this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();\n this.postAuthenticationLambda = this.createPostAuthenticationLambda();\n this.postConfirmationLambda = this.createPostConfirmationLambda();\n this.userOnboardingWorkflow = this.createUserOnboardingWorkflow();\n this.userPool = this.createUserPool();\n this.grantPreTokenGenerationPermissions();\n this.grantPostAuthenticationPermissions();\n this.grantPostConfirmationPermissions();\n this.userPoolClient = this.createUserPoolClient();\n this.userPoolDomain = this.createUserPoolDomain();\n this.fixtureSeederClient = this.createFixtureSeederClient();\n }\n\n /**\n * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.\n * Look up via {@link OpenHiAuthService.userPoolKmsKeyFromConstruct}.\n * Override to customize.\n */\n protected createUserPoolKmsKey(): IKey {\n const key = new CognitoUserPoolKmsKey(this);\n new DiscoverableStringParameter(this, \"kms-key-param\", {\n ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,\n stringValue: key.keyArn,\n description:\n \"KMS key ARN for Cognito User Pool (e.g. custom sender); cross-stack reference\",\n });\n return key;\n }\n\n /**\n * Creates the Pre Token Generation Lambda (Cognito trigger). On every\n * sign-in and token refresh the Lambda resolves the User by Cognito `sub`\n * (GSI2) and injects `ohi_tid`, `ohi_wid`, `ohi_uid`, `ohi_uname` into\n * both the ID token and the access token (ADR 2026-03-17-01).\n */\n protected createPreTokenGenerationLambda(): IFunction {\n const construct = new PreTokenGenerationLambda(this, {\n dynamoTableName: this.dataStoreTable().tableName,\n });\n return construct.lambda;\n }\n\n /**\n * Creates the Post Authentication Lambda (Cognito trigger). Calls\n * AdminUserGlobalSignOut on every sign-in to enforce single-device-per-user\n * sessions per ADR 2026-03-17-01.\n */\n protected createPostAuthenticationLambda(): IFunction {\n const construct = new PostAuthenticationLambda(this);\n return construct.lambda;\n }\n\n /**\n * Creates the Post Confirmation Lambda (Cognito trigger). On sign-up\n * confirmation, publishes a control-plane workflow event; provisioning lives\n * behind EventBridge.\n */\n protected createPostConfirmationLambda(): IFunction {\n const construct = new PostConfirmationLambda(this, {\n controlEventBusName: this.controlEventBus().eventBusName,\n });\n return construct.lambda;\n }\n\n protected createUserOnboardingWorkflow(): UserOnboardingWorkflow {\n return new UserOnboardingWorkflow(this, {\n controlEventBus: this.controlEventBus(),\n dataStoreTable: this.dataStoreTable(),\n });\n }\n\n private dataStoreTable() {\n if (this._dataStoreTable === null) {\n this._dataStoreTable =\n OpenHiDataService.dynamoDbDataStoreFromConstruct(this);\n }\n return this._dataStoreTable;\n }\n\n private controlEventBus() {\n if (this._controlEventBus === null) {\n this._controlEventBus =\n OpenHiGlobalService.controlEventBusFromConstruct(this);\n }\n return this._controlEventBus;\n }\n\n /**\n * Creates the Cognito User Pool and exports its ID to SSM.\n * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.\n * Override to customize.\n */\n protected createUserPool(): IUserPool {\n const userPool = new CognitoUserPool(this, {\n ...this.props.userPoolProps,\n customSenderKmsKey: this.userPoolKmsKey,\n });\n // Access-token-only claims require Pre Token Generation V2_0.\n userPool.addTrigger(\n UserPoolOperation.PRE_TOKEN_GENERATION_CONFIG,\n this.preTokenGenerationLambda,\n LambdaVersion.V2_0,\n );\n userPool.addTrigger(\n UserPoolOperation.POST_AUTHENTICATION,\n this.postAuthenticationLambda,\n );\n userPool.addTrigger(\n UserPoolOperation.POST_CONFIRMATION,\n this.postConfirmationLambda,\n );\n new DiscoverableStringParameter(this, \"user-pool-param\", {\n ssmParamName: CognitoUserPool.SSM_PARAM_NAME,\n stringValue: userPool.userPoolId,\n description:\n \"Cognito User Pool ID for this Auth stack; cross-stack reference\",\n });\n return userPool;\n }\n\n /**\n * Grants the Pre Token Generation Lambda read-only access on the data\n * store table and its GSIs. The Lambda only needs:\n * - `Query` on GSI2 to resolve a User by Cognito `sub`\n * - `GetItem` on the base table for direct User reads\n *\n * No write or scan access: a User missing `currentTenant`/`currentWorkspace`\n * falls into the absent-claims path; repair belongs in a separate backfill.\n */\n protected grantPreTokenGenerationPermissions(): void {\n const dataStoreTable = this.dataStoreTable();\n const dynamoActions = [\"dynamodb:GetItem\", \"dynamodb:Query\"] as const;\n dataStoreTable.grant(this.preTokenGenerationLambda, ...dynamoActions);\n this.preTokenGenerationLambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [...dynamoActions],\n resources: [`${dataStoreTable.tableArn}/index/*`],\n }),\n );\n }\n\n /**\n * Grants the Post Authentication Lambda permission to call\n * `cognito-idp:AdminUserGlobalSignOut`.\n *\n * Scoped via `Stack.of(this).formatArn` rather than `userPool.userPoolArn`\n * because the User Pool registers this Lambda as a Post Authentication\n * trigger, creating the cycle:\n * userPool → lambda (trigger ARN) → role policy → userPool ARN.\n * Using `formatArn` avoids referencing the User Pool resource directly\n * while still scoping to user pools in this account+region. The Lambda\n * is invoked only by Cognito with a Cognito-provided `event.userPoolId`,\n * so the runtime target is constrained by the trigger contract.\n */\n protected grantPostAuthenticationPermissions(): void {\n this.postAuthenticationLambda.addToRolePolicy(\n new PolicyStatement({\n actions: [\"cognito-idp:AdminUserGlobalSignOut\"],\n resources: [\n Stack.of(this).formatArn({\n service: \"cognito-idp\",\n resource: \"userpool\",\n resourceName: \"*\",\n }),\n ],\n }),\n );\n }\n\n /**\n * Grants the Post Confirmation Lambda publish-only access to the\n * control-plane event bus. Workflow Lambdas own DynamoDB writes.\n */\n protected grantPostConfirmationPermissions(): void {\n this.controlEventBus().grantPutEventsTo(this.postConfirmationLambda);\n }\n\n /**\n * Creates the User Pool Client and exports its ID to SSM (AUTH service type).\n * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.\n * Override to customize.\n */\n protected createUserPoolClient(): IUserPoolClient {\n const client = new CognitoUserPoolClient(this, {\n userPool: this.userPool,\n });\n new DiscoverableStringParameter(this, \"user-pool-client-param\", {\n ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,\n stringValue: client.userPoolClientId,\n description:\n \"Cognito User Pool Client ID for this Auth stack; cross-stack reference\",\n });\n return client;\n }\n\n /**\n * Creates the dedicated USER_PASSWORD_AUTH app client for the\n * `@openhi/seed-fixtures` CLI, **only** in non-prod environments.\n * Returns `undefined` when this stack is being deployed to a prod\n * stage so the prod auth stack carries no fixture-seeder code path.\n *\n * Operator post-deploy: create a `fixture-seeder` Cognito user with\n * a service password (manually via console or scripted with\n * `aws cognito-idp admin-create-user`); the CLI consumes those creds\n * via env vars to drive `InitiateAuth`.\n */\n protected createFixtureSeederClient(): IUserPoolClient | undefined {\n if (this.ohEnv.ohStage.stageType === OPEN_HI_STAGE.PROD) {\n return undefined;\n }\n const client = new CognitoFixtureSeederClient(this, {\n userPool: this.userPool,\n });\n new DiscoverableStringParameter(this, \"fixture-seeder-client-param\", {\n ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,\n stringValue: client.userPoolClientId,\n description:\n \"Cognito User Pool Client ID for the OpenHI fixture-seeder CLI \" +\n \"(USER_PASSWORD_AUTH; non-prod only); cross-stack reference\",\n });\n return client;\n }\n\n /**\n * Creates the User Pool Domain (Cognito hosted UI) and exports domain name to SSM.\n * Look up via {@link OpenHiAuthService.userPoolDomainFromConstruct}.\n * Override to customize.\n */\n protected createUserPoolDomain(): IUserPoolDomain {\n const domain = new CognitoUserPoolDomain(this, {\n userPool: this.userPool,\n cognitoDomain: {\n domainPrefix: `auth-${this.branchHash}`,\n },\n });\n new DiscoverableStringParameter(this, \"user-pool-domain-param\", {\n ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,\n stringValue: domain.domainName,\n description:\n \"Cognito User Pool Domain (hosted UI) for this Auth stack; cross-stack reference\",\n });\n return domain;\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport { StreamViewType, ITable, Table } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport * as kinesis from \"aws-cdk-lib/aws-kinesis\";\nimport { Construct } from \"constructs\";\nimport { OpenHiAuthService } from \"./open-hi-auth-service\";\nimport { OpenHiGlobalService } from \"./open-hi-global-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { DataStoreHistoricalArchive } from \"../components/dynamodb/data-store-historical-archive\";\nimport {\n DynamoDbDataStore,\n getDynamoDbDataStoreTableName,\n} from \"../components/dynamodb/dynamo-db-data-store\";\nimport { DataStorePostgresReplica } from \"../components/postgres/data-store-postgres-replica\";\nimport { SeedDemoDataWorkflow } from \"../workflows/control-plane/seed-demo-data\";\nimport { SeedSystemDataWorkflow } from \"../workflows/control-plane/seed-system-data\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-data-service.md\n */\n\nexport type OpenHiDataServiceProps = OpenHiServiceProps;\n\n/**\n * Data storage service stack: centralizes DynamoDB, S3, and other persistence\n * resources for OpenHI. Creates the single-table data store in a protected\n * method; subclasses may override to customize. EventBridge event buses\n * (data, ops, control) are owned by {@link OpenHiGlobalService} so they deploy\n * ahead of regional services.\n */\nexport class OpenHiDataService extends OpenHiService {\n static readonly SERVICE_TYPE = \"data\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.\n */\n static dynamoDbDataStoreFromConstruct(\n scope: Construct,\n id = \"dynamo-db-data-store\",\n ): ITable {\n return Table.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));\n }\n\n get serviceType(): string {\n return OpenHiDataService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options. */\n public override props: OpenHiDataServiceProps;\n\n /**\n * The single-table DynamoDB data store. Use {@link OpenHiDataService.dynamoDbDataStoreFromConstruct}\n * from other stacks to obtain an ITable reference by name.\n */\n public readonly dataStore: ITable;\n\n /**\n * Kinesis stream receiving DynamoDB item-level changes for the data store table.\n */\n public readonly dataStoreChangeStream: kinesis.IStream;\n\n /**\n * Historical archive pipeline (Kinesis → Firehose → S3) and data-event-bus\n * notifications for current FHIR resources (ADRs 2026-03-11-02, 2026-03-02-01).\n */\n public readonly dataStoreHistoricalArchive: DataStoreHistoricalArchive;\n\n /**\n * Postgres replication tier (ADR 2026-04-17-01, phase 1). A second consumer\n * on the change stream that projects current FHIR resources into a JSONB\n * `resources` table on Aurora Serverless v2. Phase 1 is replication-only;\n * the read path is not wired up yet.\n */\n public readonly dataStorePostgresReplica: DataStorePostgresReplica;\n\n /**\n * Deploy-triggered workflow that idempotently re-asserts the\n * platform-singleton control-plane records (today: the three canonical\n * Roles via `PLATFORM_ROLE_CONCEPTS`; future: additional system\n * data). Subscribes to `platform.deployment-completed.v1` on the\n * control event bus and dedups via the shared `WorkflowDedupTable`.\n */\n public readonly seedSystemDataWorkflow: SeedSystemDataWorkflow;\n\n /**\n * Deploy-triggered workflow that idempotently re-asserts the demo\n * data graph (placeholder + 3 demo Tenants + 5 Workspaces; per\n * dev-user Cognito users with their DynamoDB User records,\n * Memberships, and RoleAssignments). **Non-prod only** —\n * `undefined` on prod stages. The synth-time stage gate in\n * {@link createSeedDemoDataWorkflow} is the only guarantee\n * separating prod stacks from the workflow's IAM grants and rule\n * target; the construct itself never checks the stage.\n */\n public readonly seedDemoDataWorkflow?: SeedDemoDataWorkflow;\n\n /**\n * Cached control-event-bus lookup. `OpenHiGlobalService.controlEventBusFromConstruct`\n * registers a child `EventBus.fromEventBusName` construct with a\n * fixed id under the scope it is passed, so calling it twice on the\n * same `OpenHiDataService` instance collides. The cache mirrors the\n * `private controlEventBus()` pattern already used in\n * `OpenHiAuthService`. Use {@link controlEventBus} from this class\n * — never call the static lookup from inside `OpenHiDataService`.\n */\n private _controlEventBus: IEventBus | null = null;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiDataServiceProps = {}) {\n super(ohEnv, OpenHiDataService.SERVICE_TYPE, props);\n this.props = props;\n\n this.dataStoreChangeStream = new kinesis.Stream(\n this,\n \"data-store-change-stream\",\n {\n streamName: `openhi-dstore-cdc-${this.branchHash}`,\n streamMode: kinesis.StreamMode.ON_DEMAND,\n // CDK default for kinesis.Stream is RETAIN, which strands the stream\n // when a non-prod stack is destroyed. Use the service's policy so\n // non-prod tears down cleanly while prod retains.\n removalPolicy: this.removalPolicy,\n },\n );\n\n this.dataStore = this.createDataStore();\n\n this.dataStoreHistoricalArchive = new DataStoreHistoricalArchive(\n this,\n \"data-store-historical-archive\",\n {\n kinesisStream: this.dataStoreChangeStream,\n removalPolicy: this.removalPolicy,\n stackHash: this.stackHash,\n dataEventBus: OpenHiGlobalService.dataEventBusFromConstruct(this),\n },\n );\n\n this.dataStorePostgresReplica = new DataStorePostgresReplica(\n this,\n \"data-store-postgres-replica\",\n {\n kinesisStream: this.dataStoreChangeStream,\n removalPolicy: this.removalPolicy,\n stackHash: this.stackHash,\n branchHash: this.branchHash,\n },\n );\n\n this.seedSystemDataWorkflow = this.createSeedSystemDataWorkflow();\n this.seedDemoDataWorkflow = this.createSeedDemoDataWorkflow();\n }\n\n /**\n * Lazily looks up the control event bus exactly once per\n * `OpenHiDataService` instance and caches the reference. Every\n * workflow that consumes the bus must read it through this method\n * — see {@link _controlEventBus} for the underlying collision risk.\n */\n private controlEventBus(): IEventBus {\n if (this._controlEventBus === null) {\n this._controlEventBus =\n OpenHiGlobalService.controlEventBusFromConstruct(this);\n }\n return this._controlEventBus;\n }\n\n /**\n * Creates the seed-system-data workflow. Override to customize.\n */\n protected createSeedSystemDataWorkflow(): SeedSystemDataWorkflow {\n return new SeedSystemDataWorkflow(this, {\n controlEventBus: this.controlEventBus(),\n dataStoreTable: this.dataStore,\n });\n }\n\n /**\n * Creates the seed-demo-data workflow — but only on non-prod\n * stages. Returns `undefined` on prod so the workflow literally\n * does not exist in prod stacks. Override to customize.\n */\n protected createSeedDemoDataWorkflow(): SeedDemoDataWorkflow | undefined {\n if (this.ohEnv.ohStage.stageType === OPEN_HI_STAGE.PROD) {\n return undefined;\n }\n return new SeedDemoDataWorkflow(this, {\n controlEventBus: this.controlEventBus(),\n dataStoreTable: this.dataStore,\n userPool: OpenHiAuthService.userPoolFromConstruct(this),\n });\n }\n\n /**\n * Creates the single-table DynamoDB data store.\n * Override to customize.\n */\n protected createDataStore(): ITable {\n return new DynamoDbDataStore(this, \"dynamo-db-data-store\", {\n kinesisStream: this.dataStoreChangeStream,\n stream: StreamViewType.NEW_AND_OLD_IMAGES,\n });\n }\n}\n","import {\n Certificate,\n CertificateValidation,\n ICertificate,\n} from \"aws-cdk-lib/aws-certificatemanager\";\nimport { EventBus, IEventBus } from \"aws-cdk-lib/aws-events\";\nimport {\n HostedZone,\n HostedZoneAttributes,\n IHostedZone,\n} from \"aws-cdk-lib/aws-route53\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { RootWildcardCertificate } from \"../components/acm/root-wildcard-certificate\";\nimport { WorkflowDedupTable } from \"../components/dynamodb/workflow-dedup-table\";\nimport { ControlEventBus } from \"../components/event-bridge/control-event-bus\";\nimport { DataEventBus } from \"../components/event-bridge/data-event-bus\";\nimport { OpsEventBus } from \"../components/event-bridge/ops-event-bus\";\nimport { ChildHostedZone } from \"../components/route-53/child-hosted-zone\";\nimport { DiscoverableStringParameter } from \"../components/ssm\";\nimport { PlatformDeployBridge } from \"../workflows/control-plane/platform-deploy-bridge\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-global-service.md\n */\n\nexport interface OpenHiGlobalServiceProps extends OpenHiServiceProps {}\n\n/**\n * Global Infrastructure stack: owns global DNS, certificates, and the\n * cross-region EventBridge buses (data, ops, control). Resources (root zone,\n * optional child zone, wildcard cert, data/ops/control buses) are created in\n * protected methods; subclasses may override to customize.\n */\nexport class OpenHiGlobalService extends OpenHiService {\n static readonly SERVICE_TYPE = \"global\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns an IHostedZone from the given attributes (no SSM). Use when the zone is imported from config.\n */\n static rootHostedZoneFromConstruct(\n scope: Construct,\n props: HostedZoneAttributes,\n ): IHostedZone {\n return HostedZone.fromHostedZoneAttributes(scope, \"root-zone\", props);\n }\n\n /**\n * Returns an ICertificate by looking up the Global stack's wildcard cert ARN from SSM.\n */\n static rootWildcardCertificateFromConstruct(scope: Construct): ICertificate {\n const certificateArn = StringParameter.valueForStringParameter(\n scope,\n RootWildcardCertificate.ssmParameterName(),\n );\n return Certificate.fromCertificateArn(\n scope,\n \"wildcard-certificate\",\n certificateArn,\n );\n }\n\n /**\n * Returns an IHostedZone by looking up the child hosted zone ID from SSM. Defaults to GLOBAL service type.\n */\n static childHostedZoneFromConstruct(\n scope: Construct,\n props: { zoneName: string; serviceType?: OpenHiServiceType },\n ): IHostedZone {\n const hostedZoneId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: ChildHostedZone.SSM_PARAM_NAME,\n serviceType: props.serviceType ?? OpenHiGlobalService.SERVICE_TYPE,\n });\n return HostedZone.fromHostedZoneAttributes(scope, \"child-zone\", {\n hostedZoneId,\n zoneName: props.zoneName,\n });\n }\n\n /**\n * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.\n */\n static dataEventBusFromConstruct(scope: Construct): IEventBus {\n return EventBus.fromEventBusName(\n scope,\n \"data-event-bus\",\n DataEventBus.getEventBusName(scope),\n );\n }\n\n /**\n * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.\n */\n static opsEventBusFromConstruct(scope: Construct): IEventBus {\n return EventBus.fromEventBusName(\n scope,\n \"ops-event-bus\",\n OpsEventBus.getEventBusName(scope),\n );\n }\n\n /**\n * Returns the control-plane event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.\n */\n static controlEventBusFromConstruct(scope: Construct): IEventBus {\n return EventBus.fromEventBusName(\n scope,\n \"control-event-bus\",\n ControlEventBus.getEventBusName(scope),\n );\n }\n\n /**\n * Returns the workflow dedup table by name (deterministic per branch).\n * Use from other stacks to obtain an ITable reference. Consumer Lambdas\n * are typically wired via `WorkflowDedupTable.grantConsumer(fn, name)`\n * on the owning service's `workflowDedupTable` reference; the\n * `tableNameFromLookup` / `tableArnFromLookup` SSM helpers on the\n * construct cover cross-stack consumers that need only the name/ARN.\n */\n static workflowDedupTableNameFromLookup(scope: Construct): string {\n return WorkflowDedupTable.tableNameFromLookup(scope);\n }\n\n get serviceType(): string {\n return OpenHiGlobalService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options. */\n public override props: OpenHiGlobalServiceProps;\n\n public readonly rootHostedZone: IHostedZone;\n public readonly childHostedZone?: IHostedZone;\n public readonly rootWildcardCertificate: ICertificate;\n\n /**\n * Event bus for data-related events (ingestion, transformation, storage).\n * Other stacks obtain it via {@link OpenHiGlobalService.dataEventBusFromConstruct}.\n */\n public readonly dataEventBus: IEventBus;\n\n /**\n * Event bus for operational events (monitoring, alerting, system health).\n * Other stacks obtain it via {@link OpenHiGlobalService.opsEventBusFromConstruct}.\n */\n public readonly opsEventBus: IEventBus;\n\n /**\n * Event bus for control-plane lifecycle and command events.\n * Other stacks obtain it via {@link OpenHiGlobalService.controlEventBusFromConstruct}.\n */\n public readonly controlEventBus: IEventBus;\n\n /**\n * Bridge that watches CloudFormation Stack Status Change events on the\n * default AWS bus and republishes terminal-success events for OpenHi-tagged\n * stacks onto {@link controlEventBus} as `platform.deployment-completed.v1`.\n */\n public readonly platformDeployBridge: PlatformDeployBridge;\n\n /**\n * Shared dedup table every retryable workflow consumer dedupes against\n * (TR-015). Singleton per deployment — provisioned here on the global\n * stack so consumer stacks reach it via SSM lookups, not props.\n */\n public readonly workflowDedupTable: WorkflowDedupTable;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiGlobalServiceProps = {}) {\n super(ohEnv, OpenHiGlobalService.SERVICE_TYPE, props);\n this.props = props;\n\n this.validateConfig(props);\n\n this.rootHostedZone = this.createRootHostedZone();\n this.childHostedZone = this.createChildHostedZone();\n this.rootWildcardCertificate = this.createRootWildcardCertificate();\n this.dataEventBus = this.createDataEventBus();\n this.opsEventBus = this.createOpsEventBus();\n this.controlEventBus = this.createControlEventBus();\n this.workflowDedupTable = this.createWorkflowDedupTable();\n this.platformDeployBridge = this.createPlatformDeployBridge();\n }\n\n /**\n * Validates that config required for the Global stack is present.\n */\n protected validateConfig(props: OpenHiGlobalServiceProps): void {\n const { config } = props;\n if (!config) {\n throw new Error(\"Config is required\");\n }\n if (!config.zoneName) {\n throw new Error(\"Zone name is required to import the root zone\");\n }\n if (!config.hostedZoneId) {\n throw new Error(\"Hosted zone ID is required to import the root zone\");\n }\n }\n\n /**\n * Creates the root hosted zone (imported via attributes from config).\n * Override to customize or create the zone.\n */\n protected createRootHostedZone(): IHostedZone {\n return OpenHiGlobalService.rootHostedZoneFromConstruct(this, {\n zoneName: this.config.zoneName!,\n hostedZoneId: this.config.hostedZoneId!,\n });\n }\n\n /**\n * Creates the optional child hosted zone (e.g. branch subdomain).\n * Override to create a child zone when config provides childHostedZoneAttributes.\n * If you create a ChildHostedZone, also create a DiscoverableStringParameter\n * with ChildHostedZone.SSM_PARAM_NAME and the zone's hostedZoneId.\n */\n protected createChildHostedZone(): IHostedZone | undefined {\n return undefined;\n }\n\n /**\n * Creates the root wildcard certificate. On main branch, creates a new cert\n * with DNS validation; otherwise imports from SSM.\n * Override to customize certificate creation.\n */\n protected createRootWildcardCertificate(): ICertificate {\n if (this.branchName === \"main\") {\n return new RootWildcardCertificate(this, {\n domainName: `*.${this.rootHostedZone.zoneName}`,\n subjectAlternativeNames: [this.rootHostedZone.zoneName],\n validation: CertificateValidation.fromDns(this.rootHostedZone),\n });\n }\n return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);\n }\n\n /**\n * Creates the data event bus.\n * Override to customize.\n */\n protected createDataEventBus(): IEventBus {\n return new DataEventBus(this);\n }\n\n /**\n * Creates the ops event bus.\n * Override to customize.\n */\n protected createOpsEventBus(): IEventBus {\n return new OpsEventBus(this);\n }\n\n /**\n * Creates the control-plane event bus.\n * Override to customize.\n */\n protected createControlEventBus(): IEventBus {\n return new ControlEventBus(this);\n }\n\n /**\n * Creates the platform deploy bridge that republishes CloudFormation\n * Stack Status Change events onto the control event bus.\n * Override to customize.\n */\n protected createPlatformDeployBridge(): PlatformDeployBridge {\n return new PlatformDeployBridge(this, {\n controlEventBus: this.controlEventBus,\n });\n }\n\n /**\n * Creates the shared workflow dedup table (TR-015 singleton).\n * Override to customize.\n */\n protected createWorkflowDedupTable(): WorkflowDedupTable {\n return new WorkflowDedupTable(this, \"workflow-dedup-table\");\n }\n}\n","import { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { PlatformDeployBridgeLambda } from \"./platform-deploy-bridge-lambda\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/platform-deploy-bridge/index.md\n */\n\nexport interface PlatformDeployBridgeProps {\n /** Destination control event bus the bridge republishes onto. */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Source-side reactor that watches CloudFormation Stack Status Change\n * events on the default AWS bus and republishes terminal-success events\n * (`CREATE_COMPLETE` / `UPDATE_COMPLETE`) for OpenHi-tagged stacks onto\n * the control event bus as `platform.deployment-completed.v1`.\n *\n * Implements row 4 of the workflow placement matrix\n * (codedrifters/openhi#953): ops-plane reactor → republishes to\n * control event bus.\n */\nexport class PlatformDeployBridge extends Construct {\n public readonly bridgeLambda: PlatformDeployBridgeLambda;\n\n constructor(scope: Construct, props: PlatformDeployBridgeProps) {\n super(scope, \"platform-deploy-bridge\");\n\n this.bridgeLambda = new PlatformDeployBridgeLambda(this, {\n controlEventBus: props.controlEventBus,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration, Stack } from \"aws-cdk-lib\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n BRIDGED_STATUSES,\n CLOUDFORMATION_EVENT_SOURCE,\n CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE,\n CONTROL_EVENT_BUS_NAME_ENV_VAR,\n OPENHI_REPO_TAG_KEY_ENV_VAR,\n OPENHI_TAG_KEY_PREFIX_ENV_VAR,\n} from \"./events\";\nimport {\n OPENHI_TAG_SUFFIX_REPO_NAME,\n OpenHiService,\n openHiTagKey,\n} from \"../../../app/open-hi-service\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/platform-deploy-bridge/index.md\n */\n\nconst HANDLER_NAME = \"platform-deploy-bridge.handler.js\";\n\n/**\n * Resolve handler entry so it works from src/ (tests) or lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface PlatformDeployBridgeLambdaProps {\n /** Destination control event bus the bridge republishes onto. */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Lambda that bridges CloudFormation Stack Status Change events from the\n * default AWS bus into typed `platform.deployment-completed.v1` envelopes on\n * the OpenHI control event bus.\n *\n * Owns its EventBridge Rule (on the default AWS bus) and the IAM\n * permissions it needs — colocating routing + permissions with the\n * function they target.\n *\n * The EventBridge rule pre-filters by stack-id prefix so the rule (and\n * therefore the Lambda) only fires on the host stack's own branch deploys.\n * This prevents cross-branch leak when multiple branches are deployed into\n * the same account.\n */\nexport class PlatformDeployBridgeLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: PlatformDeployBridgeLambdaProps) {\n super(scope, \"platform-deploy-bridge-lambda\");\n\n // Resolve the host OpenHiService so we can pin the rule to this\n // branch's stacks and project the appName-aware tag key.\n const service = OpenHiService.of(this) as OpenHiService;\n const repoTagKey = openHiTagKey(\n service.appName,\n OPENHI_TAG_SUFFIX_REPO_NAME,\n );\n const tagKeyPrefix = `${service.appName}:`;\n\n // Derive the shared sibling-stack prefix from this stack's own\n // synthesized name. `service.branchHash` alone (e.g. `4e4512-`)\n // is wrong because CDK prepends the Stage hierarchy\n // (`<stage>-<environment>-…`) to every stack name, so the\n // CloudFormation events carry stack-ids like\n // `dev-primary-4e4512-data-…`. Stripping the known\n // `-<serviceId>-<account>-<region>` suffix off the bridge's own\n // stack name yields the prefix every sibling stack shares.\n const ownStackName = Stack.of(this).stackName;\n const ownSuffix = `-${service.serviceId}-${Stack.of(this).account}-${\n Stack.of(this).region\n }`;\n const sharedPrefix = ownStackName.endsWith(ownSuffix)\n ? ownStackName.slice(0, -ownSuffix.length)\n : service.branchHash;\n const stackIdPrefix = `arn:aws:cloudformation:${Stack.of(this).region}:${\n Stack.of(this).account\n }:stack/${sharedPrefix}-`;\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 256,\n timeout: Duration.seconds(30),\n environment: {\n [CONTROL_EVENT_BUS_NAME_ENV_VAR]: props.controlEventBus.eventBusName,\n [OPENHI_REPO_TAG_KEY_ENV_VAR]: repoTagKey,\n [OPENHI_TAG_KEY_PREFIX_ENV_VAR]: tagKeyPrefix,\n },\n });\n\n // Fetch stack tags so the handler can project them into the envelope.\n // Scope to stacks in the deploying account/region.\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"cloudformation:DescribeStacks\"],\n resources: [\n `arn:aws:cloudformation:${Stack.of(this).region}:${\n Stack.of(this).account\n }:stack/*`,\n ],\n }),\n );\n\n // Republish the projected envelope onto the control event bus.\n props.controlEventBus.grantPutEventsTo(this.lambda);\n\n // Rule lives on the default AWS bus — that is where AWS publishes\n // its own CloudFormation Stack Status Change events. Omitting\n // `eventBus` defaults to the account's default bus.\n //\n // The `stack-id` prefix scopes the rule to this branch's own stacks\n // only (OpenHi stack names start with the deterministic per-branch\n // hash), so other branches' deploys never trigger this Lambda even\n // though every branch deploys its own bridge into the same account.\n this.rule = new Rule(this, \"rule\", {\n eventPattern: {\n source: [CLOUDFORMATION_EVENT_SOURCE],\n detailType: [CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE],\n detail: {\n \"stack-id\": [{ prefix: stackIdPrefix }],\n \"status-details\": {\n status: [...BRIDGED_STATUSES],\n },\n },\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { PLATFORM_ROLE_IDS } from \"@openhi/types\";\nimport { Duration, Stack } from \"aws-cdk-lib\";\nimport { IUserPool } from \"aws-cdk-lib/aws-cognito\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n DEV_USERS,\n PlatformSystemDataSeededV1,\n demoBasePartitionKeys,\n demoDevUserPartitionKeys,\n rolePartitionKey,\n} from \"./events\";\nimport { SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR } from \"./seed-demo-data.handler\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.md\n */\n\nconst HANDLER_NAME = \"seed-demo-data.handler.js\";\n\n/**\n * Resolve the bundled handler entry. Same dual-path lookup the\n * seed-system-data Lambda uses: src/ for tests (the file lives next\n * to this one) or lib/ for the compiled bundle.\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface SeedDemoDataLambdaProps {\n /**\n * Data-store table the workflow upserts demo-data records into.\n * Wired via `DYNAMO_TABLE_NAME` env var; granted scoped read on the\n * Role PKs (pre-flight check) and scoped write on the enumerated\n * demo Tenant / Workspace / Membership / RoleAssignment / User PKs.\n */\n readonly dataStoreTable: ITable;\n\n /**\n * Control event bus that re-publishes\n * `platform.deployment-completed.v1` from the platform-deploy bridge.\n * The Rule mounts here.\n */\n readonly controlEventBus: IEventBus;\n\n /**\n * Cognito User Pool the workflow provisions dev users into. The\n * Lambda's IAM grant is scoped to this exact user-pool ARN — the\n * grant uses the user-pool ARN, **not** the wildcard formatArn\n * pattern used by `post-authentication-lambda` (that Lambda's\n * trigger-driven dependency cycle does not apply here, so the\n * tighter scope is safe).\n */\n readonly userPool: IUserPool;\n}\n\n/**\n * Lambda + EventBridge Rule pair for the seed-demo-data workflow.\n * Owns the routing (`source` / `detail-type` pattern), the scoped\n * DynamoDB grants, and the scoped Cognito Admin grant — co-locating\n * routing + permissions with the function they target. Wiring to the\n * workflow dedup table is the parent construct's job (it has the\n * singleton reference) and happens via `WorkflowDedupTable.grantConsumer`.\n *\n * Stage-gating is the parent's job too — this construct itself never\n * checks the stage. The CDK stage-router (`OpenHiDataService`)\n * decides whether to instantiate it at all on each stage.\n */\nexport class SeedDemoDataLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: SeedDemoDataLambdaProps) {\n super(scope, \"seed-demo-data-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(2),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n [SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR]: props.userPool.userPoolId,\n },\n });\n\n // Pre-flight Role check: read the three platform-singleton Role\n // PKs only. A regression that tried to read other records would\n // be rejected by IAM, not by application code.\n const roleReadKeys = Object.values(PLATFORM_ROLE_IDS).map(rolePartitionKey);\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:GetItem\"],\n resources: [props.dataStoreTable.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": roleReadKeys,\n },\n },\n }),\n );\n\n // Write grant: the deterministic set of demo Tenant / Workspace /\n // Membership / RoleAssignment / User PKs the workflow writes.\n // {@link DEV_USERS} is a compile-time constant so the set is\n // fully enumerable at synth time.\n const writeKeys: string[] = [\n ...demoBasePartitionKeys(),\n ...demoDevUserPartitionKeys(DEV_USERS),\n ];\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:PutItem\", \"dynamodb:UpdateItem\"],\n resources: [props.dataStoreTable.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": writeKeys,\n },\n },\n }),\n );\n\n // Cognito grant. The User Pool is imported by ARN from the auth\n // stack via SSM lookup, so reconstructing the ARN with\n // `Stack.of(this).formatArn` scopes the grant to this exact\n // account+region+pool without depending on the auth stack's\n // exported ARN.\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"cognito-idp:AdminCreateUser\",\n \"cognito-idp:AdminGetUser\",\n \"cognito-idp:AdminSetUserPassword\",\n ],\n resources: [\n Stack.of(this).formatArn({\n service: \"cognito-idp\",\n resource: \"userpool\",\n resourceName: props.userPool.userPoolId,\n }),\n ],\n }),\n );\n\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.controlEventBus,\n eventPattern: {\n source: [PlatformSystemDataSeededV1.source],\n detailType: [PlatformSystemDataSeededV1.detailType],\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import { IUserPool } from \"aws-cdk-lib/aws-cognito\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { SEED_DEMO_DATA_CONSUMER_NAME } from \"./events\";\nimport { SeedDemoDataLambda } from \"./seed-demo-data-lambda\";\nimport { WorkflowDedupTable } from \"../../../components/dynamodb/workflow-dedup-table\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.md\n */\n\nexport interface SeedDemoDataWorkflowProps {\n /** Control event bus carrying `platform.system-data-seeded.v1`. */\n readonly controlEventBus: IEventBus;\n /** Data-store table the workflow upserts demo-data records into. */\n readonly dataStoreTable: ITable;\n /** Cognito User Pool the workflow provisions dev users into. */\n readonly userPool: IUserPool;\n}\n\n/**\n * Control-plane workflow that fires on every platform deploy and\n * idempotently re-asserts the demo-data graph: placeholder tenant +\n * workspace, 3 demo tenants + 4 workspaces, and per-dev-user Cognito\n * users with their DynamoDB User records, Memberships, and\n * RoleAssignments.\n *\n * Mounted on the data-service stack so the IAM grants against the\n * data-store table stay local. The control event bus and the workflow\n * dedup table reach in cross-stack via the SSM lookups\n * `OpenHiGlobalService.controlEventBusFromConstruct` and\n * `WorkflowDedupTable.grantConsumerFromLookup` respectively. The\n * Cognito User Pool similarly reaches in via\n * `OpenHiAuthService.userPoolFromConstruct`.\n *\n * Non-prod-only: the CDK stage-router (`OpenHiDataService`)\n * conditionally constructs this workflow only on non-prod stages.\n * The construct itself never checks the stage — its absence in prod\n * stacks is the gate.\n */\nexport class SeedDemoDataWorkflow extends Construct {\n public readonly seedDemoData: SeedDemoDataLambda;\n\n constructor(scope: Construct, props: SeedDemoDataWorkflowProps) {\n super(scope, \"seed-demo-data-workflow\");\n\n this.seedDemoData = new SeedDemoDataLambda(this, {\n controlEventBus: props.controlEventBus,\n dataStoreTable: props.dataStoreTable,\n userPool: props.userPool,\n });\n\n // Cross-stack grant resolves the dedup table's name + ARN via SSM\n // at synth time, so the data-service stack does not pick up a\n // CloudFormation export dependency on the global stack that owns\n // the dedup table.\n WorkflowDedupTable.grantConsumerFromLookup(\n this,\n this.seedDemoData.lambda,\n SEED_DEMO_DATA_CONSUMER_NAME,\n );\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { PLATFORM_ROLE_IDS } from \"@openhi/types\";\nimport { Duration, Stack } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n PlatformDeploymentCompletedV1,\n SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR,\n} from \"./events\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-system-data/seed-system-data-lambda.md\n */\n\nconst HANDLER_NAME = \"seed-system-data.handler.js\";\n\n/**\n * Resolve the bundled handler entry. Same dual-path lookup the user-onboarding\n * Lambda uses: src/ for tests (the file lives next to this one) or lib/ for\n * the compiled bundle.\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface SeedSystemDataLambdaProps {\n /**\n * Data-store table the workflow upserts platform-singleton control-plane\n * records into. Wired via `DYNAMO_TABLE_NAME` env var; granted scoped\n * write permission to the role records' partition keys only.\n */\n readonly dataStoreTable: ITable;\n\n /**\n * Control event bus that re-publishes\n * `platform.deployment-completed.v1` from the platform-deploy bridge.\n * The Rule mounts here.\n */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Lambda + EventBridge Rule pair for the seed-system-data workflow. Owns\n * the routing (`source` / `detail-type` pattern) and the scoped data-store\n * grants — co-locating routing + permissions with the function they\n * target. Wiring to the workflow dedup table is the parent construct's\n * job (it has the singleton reference) and happens via\n * `WorkflowDedupTable.grantConsumer`.\n */\nexport class SeedSystemDataLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: SeedSystemDataLambdaProps) {\n super(scope, \"seed-system-data-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n [SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR]:\n props.controlEventBus.eventBusName,\n },\n });\n\n // Least-privilege grant: only the three known role PKs are\n // writable. A regression that tried to write a non-Role record\n // (or a Role with an unrecognized id) would be rejected by IAM,\n // not by application code. Updating the role-id set means\n // amending the generator's `ID_PREFIX_BY_VALUE_SET_URL` table\n // and regenerating — the role-id values flow through.\n //\n // The leading-keys values must match what ElectroDB *actually\n // writes*, not the entity definition's pretty template. The\n // base-table PK template `ROLE#ID#${id}` has no\n // `casing: \"none\"`, so ElectroDB applies its default casing\n // (lowercase) at runtime and the on-the-wire PK is\n // `role#id#<id>`. Authoring the policy in the uppercase\n // template form silently produces an IAM denial on every\n // PutItem the seeder attempts.\n const roleArns = Object.values(PLATFORM_ROLE_IDS).map(\n (id) => `role#id#${id}`,\n );\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:PutItem\", \"dynamodb:UpdateItem\"],\n resources: [props.dataStoreTable.tableArn],\n conditions: {\n \"ForAllValues:StringEquals\": {\n \"dynamodb:LeadingKeys\": roleArns,\n },\n },\n }),\n );\n\n // Allow the handler to publish `platform.system-data-seeded.v1`\n // onto the control event bus after a successful seed. Downstream\n // consumers (`seed-demo-data`) subscribe to that event instead\n // of the raw deploy-completion event so the dependency is\n // enforced by a happens-before edge rather than by EventBridge\n // retry timing.\n props.controlEventBus.grantPutEventsTo(this.lambda);\n\n // Gate the rule on the host (data) stack's own completion event.\n // The data-store table is created by this stack, so seeding only\n // becomes safe once this stack reaches CREATE/UPDATE_COMPLETE.\n // Without this filter, sibling stacks (global, auth, rest-api,\n // graphql) completing before the data stack would trigger the\n // seeder against a not-yet-created table.\n //\n // The filter targets `detail.payload.stackName`: the outer\n // `detail` is EventBridge's envelope (which holds the whole\n // workflow envelope), and `payload` is the per-workflow payload\n // field on `WorkflowEvent` — i.e. the projection the bridge\n // produced from the CloudFormation Stack Status Change event.\n const hostStackName = Stack.of(this).stackName;\n\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.controlEventBus,\n eventPattern: {\n source: [PlatformDeploymentCompletedV1.source],\n detailType: [PlatformDeploymentCompletedV1.detailType],\n detail: {\n payload: {\n stackName: [hostStackName],\n },\n },\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { SEED_SYSTEM_DATA_CONSUMER_NAME } from \"./events\";\nimport { SeedSystemDataLambda } from \"./seed-system-data-lambda\";\nimport { WorkflowDedupTable } from \"../../../components/dynamodb/workflow-dedup-table\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-system-data/seed-system-data-workflow.md\n */\n\nexport interface SeedSystemDataWorkflowProps {\n /** Control event bus carrying `platform.deployment-completed.v1`. */\n readonly controlEventBus: IEventBus;\n /** Data-store table the workflow upserts platform-singleton records into. */\n readonly dataStoreTable: ITable;\n}\n\n/**\n * Control-plane workflow that fires on every platform deploy and\n * idempotently re-asserts the platform-singleton control-plane records\n * (today: the three canonical Roles; future: additional system data\n * slotted in as sibling steps under the same dedup record).\n *\n * Mounted on the data-service stack so the IAM grants against the\n * data-store table stay local. The control event bus and the\n * workflow dedup table reach in cross-stack via the SSM lookups\n * `OpenHiGlobalService.controlEventBusFromConstruct` and\n * `WorkflowDedupTable.grantConsumerFromLookup` respectively.\n */\nexport class SeedSystemDataWorkflow extends Construct {\n public readonly seedSystemData: SeedSystemDataLambda;\n\n constructor(scope: Construct, props: SeedSystemDataWorkflowProps) {\n super(scope, \"seed-system-data-workflow\");\n\n this.seedSystemData = new SeedSystemDataLambda(this, {\n controlEventBus: props.controlEventBus,\n dataStoreTable: props.dataStoreTable,\n });\n\n // Cross-stack grant resolves the dedup table's name + ARN via SSM\n // at synth time, so the data-service stack does not pick up a\n // CloudFormation export dependency on the global stack that owns\n // the dedup table.\n WorkflowDedupTable.grantConsumerFromLookup(\n this,\n this.seedSystemData.lambda,\n SEED_SYSTEM_DATA_CONSUMER_NAME,\n );\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport {\n PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,\n USER_ONBOARDING_EVENT_SOURCE,\n} from \"./events\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/user-onboarding/provision-default-workspace-lambda.md\n */\n\nconst HANDLER_NAME = \"provision-default-workspace.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n return path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n}\n\nexport interface ProvisionDefaultWorkspaceLambdaProps {\n /**\n * DynamoDB data store table. Used for the Lambda's `DYNAMO_TABLE_NAME`\n * env var and for granting the Lambda the writes + GSI queries it needs\n * to provision default control-plane resources.\n */\n readonly dataStoreTable: ITable;\n\n /**\n * Control-plane event bus that the EventBridge Rule listens on.\n */\n readonly controlEventBus: IEventBus;\n}\n\n/**\n * Lambda used by the user-onboarding workflow to create a user's default\n * Tenant, Workspace, Memberships, and RoleAssignment.\n *\n * Owns the EventBridge Rule that routes the default-workspace onboarding\n * event to itself, and the IAM permissions it needs on the data store\n * table — colocating routing + permissions with the function they target.\n */\nexport class ProvisionDefaultWorkspaceLambda extends Construct {\n public readonly lambda: NodejsFunction;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: ProvisionDefaultWorkspaceLambdaProps) {\n super(scope, \"provision-default-workspace-lambda\");\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n },\n });\n\n // Grant table writes for default resources and User repair.\n props.dataStoreTable.grant(\n this.lambda,\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n );\n\n // Table.grant(\"dynamodb:Query\") only covers the table itself, not its\n // GSIs, so an explicit policy is required to query GSI2 by cognitoSub.\n this.lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"dynamodb:Query\"],\n resources: [`${props.dataStoreTable.tableArn}/index/*`],\n }),\n );\n\n // Route only the default-workspace onboarding event to this worker.\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.controlEventBus,\n eventPattern: {\n source: [USER_ONBOARDING_EVENT_SOURCE],\n detailType: [PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE],\n },\n targets: [\n new LambdaFunction(this.lambda, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Construct } from \"constructs\";\nimport { ProvisionDefaultWorkspaceLambda } from \"./provision-default-workspace-lambda\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/user-onboarding/user-onboarding-workflow.md\n */\n\nexport interface UserOnboardingWorkflowProps {\n readonly controlEventBus: IEventBus;\n readonly dataStoreTable: ITable;\n}\n\n/**\n * Control-plane workflow for onboarding users after Cognito confirmation.\n */\nexport class UserOnboardingWorkflow extends Construct {\n public readonly provisionDefaultWorkspace: ProvisionDefaultWorkspaceLambda;\n\n constructor(scope: Construct, props: UserOnboardingWorkflowProps) {\n super(scope, \"user-onboarding-workflow\");\n\n this.provisionDefaultWorkspace = new ProvisionDefaultWorkspaceLambda(this, {\n dataStoreTable: props.dataStoreTable,\n controlEventBus: props.controlEventBus,\n });\n }\n}\n","import { OPEN_HI_STAGE } from \"@openhi/config\";\nimport {\n CorsHttpMethod,\n DomainName,\n HttpApi,\n HttpMethod,\n HttpNoneAuthorizer,\n HttpRoute,\n HttpRouteKey,\n IHttpApi,\n} from \"aws-cdk-lib/aws-apigatewayv2\";\nimport { HttpUserPoolAuthorizer } from \"aws-cdk-lib/aws-apigatewayv2-authorizers\";\nimport { HttpLambdaIntegration } from \"aws-cdk-lib/aws-apigatewayv2-integrations\";\nimport { ICertificate } from \"aws-cdk-lib/aws-certificatemanager\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport {\n ARecord,\n HostedZone,\n IHostedZone,\n RecordTarget,\n} from \"aws-cdk-lib/aws-route53\";\nimport { ApiGatewayv2DomainProperties } from \"aws-cdk-lib/aws-route53-targets\";\nimport { Duration } from \"aws-cdk-lib/core\";\nimport { Construct } from \"constructs\";\nimport { OpenHiAuthService } from \"./open-hi-auth-service\";\nimport { OpenHiDataService } from \"./open-hi-data-service\";\nimport { OpenHiGlobalService } from \"./open-hi-global-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport {\n RootHttpApi,\n RootHttpApiProps,\n} from \"../components/api-gateway/root-http-api\";\nimport {\n DataStorePostgresReplica,\n getPostgresReplicaSchemaName,\n} from \"../components/postgres/data-store-postgres-replica\";\nimport { DiscoverableStringParameter } from \"../components/ssm\";\nimport { CorsOptionsLambda } from \"../data/lambda/cors-options-lambda\";\nimport { RestApiLambda } from \"../data/lambda/rest-api-lambda\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/services/open-hi-rest-api-service.md\n */\n\nexport interface OpenHiRestApiServiceProps extends OpenHiServiceProps {\n /**\n * Optional props passed through to the RootHttpApi (API Gateway HTTP API) construct.\n * Use corsPreflight (CDK CorsPreflightOptions) for CORS; other HttpApiProps (e.g. description, disableExecuteApiEndpoint) apply as well.\n */\n readonly rootHttpApiProps?: RootHttpApiProps;\n}\n\n/**\n * SSM parameter name suffix for the REST API base URL.\n * Full parameter name is built via buildParameterName with serviceType REST_API.\n */\nexport const REST_API_BASE_URL_SSM_NAME = \"REST_API_BASE_URL\";\n\n/**\n * REST API service stack: HTTP API, custom domain, and Lambda; exports base URL via SSM.\n * Resources are created in protected methods; subclasses may override to customize.\n */\nexport class OpenHiRestApiService extends OpenHiService {\n static readonly SERVICE_TYPE =\n \"rest-api\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns an IHttpApi by looking up the REST API stack's HTTP API ID from SSM.\n */\n static rootHttpApiFromConstruct(scope: Construct): IHttpApi {\n const httpApiId = DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: RootHttpApi.SSM_PARAM_NAME,\n serviceType: OpenHiRestApiService.SERVICE_TYPE,\n });\n return HttpApi.fromHttpApiAttributes(scope, \"http-api\", { httpApiId });\n }\n\n /**\n * Returns the REST API base URL (e.g. https://api.example.com) by looking it up from SSM.\n * Use in other stacks for E2E, scripts, or config.\n */\n static restApiBaseUrlFromConstruct(scope: Construct): string {\n return DiscoverableStringParameter.valueForLookupName(scope, {\n ssmParamName: REST_API_BASE_URL_SSM_NAME,\n serviceType: OpenHiRestApiService.SERVICE_TYPE,\n });\n }\n\n get serviceType(): string {\n return OpenHiRestApiService.SERVICE_TYPE;\n }\n\n /** Override so this.props is typed with this service's options (e.g. rootHttpApiProps). */\n public override props: OpenHiRestApiServiceProps;\n\n public readonly rootHttpApi: RootHttpApi;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiRestApiServiceProps = {}) {\n super(ohEnv, OpenHiRestApiService.SERVICE_TYPE, props);\n this.props = props;\n\n this.validateConfig(props);\n\n const hostedZone = this.createHostedZone();\n const certificate = this.createCertificate();\n const apiDomainName = this.createApiDomainNameString(hostedZone);\n this.createRestApiBaseUrlParameter(apiDomainName);\n const domainName = this.createDomainName(hostedZone, certificate);\n this.rootHttpApi = this.createRootHttpApi(domainName);\n this.createRestApiLambdaAndRoutes(hostedZone, domainName);\n }\n\n /**\n * Validates that config required for the REST API stack is present.\n */\n protected validateConfig(props: OpenHiRestApiServiceProps): void {\n const { config } = props;\n if (!config) {\n throw new Error(\"Config is required\");\n }\n if (!config.hostedZoneId) {\n throw new Error(\"Hosted zone ID is required\");\n }\n if (!config.zoneName) {\n throw new Error(\"Zone name is required\");\n }\n }\n\n /**\n * Creates the hosted zone reference (imported from config).\n * Override to customize.\n */\n protected createHostedZone(): IHostedZone {\n const { config } = this.props;\n return HostedZone.fromHostedZoneAttributes(this, \"root-zone\", {\n hostedZoneId: config!.hostedZoneId!,\n zoneName: config!.zoneName!,\n });\n }\n\n /**\n * Creates the wildcard certificate (imported from Global stack via SSM).\n * Override to customize.\n */\n protected createCertificate() {\n return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);\n }\n\n /**\n * Returns the API domain name string (e.g. api.example.com or api-{prefix}.example.com).\n * Override to customize.\n */\n protected createApiDomainNameString(hostedZone: IHostedZone): string {\n const apiPrefix =\n this.branchName === \"main\" ? `api` : `api-${this.childZonePrefix}`;\n return [apiPrefix, hostedZone.zoneName].join(\".\");\n }\n\n /**\n * Creates the SSM parameter for the REST API base URL.\n * Look up via {@link OpenHiRestApiService.restApiBaseUrlFromConstruct}.\n * Override to customize.\n */\n protected createRestApiBaseUrlParameter(apiDomainName: string): void {\n const restApiBaseUrl = `https://${apiDomainName}`;\n new DiscoverableStringParameter(this, \"rest-api-base-url-param\", {\n ssmParamName: REST_API_BASE_URL_SSM_NAME,\n stringValue: restApiBaseUrl,\n description: \"REST API base URL for this deployment (E2E, scripts)\",\n });\n }\n\n /**\n * Creates the API Gateway custom domain name resource.\n * Override to customize.\n */\n protected createDomainName(\n _hostedZone: IHostedZone,\n certificate: ICertificate,\n ): DomainName {\n const apiDomainName = this.createApiDomainNameString(_hostedZone);\n return new DomainName(this, \"domain\", {\n domainName: apiDomainName,\n certificate,\n });\n }\n\n /**\n * Creates the Lambda integration, HTTP routes, and API DNS record.\n * Override to customize. Uses {@link rootHttpApi} set by the constructor.\n */\n protected createRestApiLambdaAndRoutes(\n hostedZone: IHostedZone,\n domainName: DomainName,\n ): void {\n const dataStoreTable =\n OpenHiDataService.dynamoDbDataStoreFromConstruct(this);\n\n // Phase 2 of ADR 2026-04-17-01: REST API Lambda queries Postgres via the\n // RDS Data API. Cluster ARN, secret ARN, and database name come from SSM\n // (cross-stack discovery); the per-branch schema name is deterministic\n // from `branchHash` and computed locally to avoid an extra SSM lookup.\n const postgresClusterArn =\n DataStorePostgresReplica.clusterArnFromConstruct(this);\n const postgresSecretArn =\n DataStorePostgresReplica.secretArnFromConstruct(this);\n const postgresDatabase =\n DataStorePostgresReplica.databaseNameFromConstruct(this);\n const postgresSchema = getPostgresReplicaSchemaName(this.branchHash);\n\n const { lambda } = new RestApiLambda(this, {\n dynamoTableName: dataStoreTable.tableName,\n branchTagValue: this.branchName,\n httpApiTagValue: RootHttpApi.SSM_PARAM_NAME,\n postgresClusterArn,\n postgresSecretArn,\n postgresDatabase,\n postgresSchema,\n });\n\n // Allow the Lambda to issue Data API statements against this cluster and\n // read the cluster credentials secret. These are scoped to the specific\n // ARNs published by the data stack — no wildcards.\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"rds-data:ExecuteStatement\",\n \"rds-data:BatchExecuteStatement\",\n ],\n resources: [postgresClusterArn],\n }),\n );\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"secretsmanager:GetSecretValue\"],\n resources: [postgresSecretArn],\n }),\n );\n const dynamoActions = [\n \"dynamodb:GetItem\",\n \"dynamodb:Query\",\n \"dynamodb:BatchGetItem\",\n \"dynamodb:ConditionCheckItem\",\n \"dynamodb:DescribeTable\",\n \"dynamodb:BatchWriteItem\",\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:DeleteItem\",\n ] as const;\n dataStoreTable.grant(lambda, ...dynamoActions);\n // Query (and other operations) on GSIs require the index resource ARN\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [...dynamoActions],\n resources: [`${dataStoreTable.tableArn}/index/*`],\n }),\n );\n // Temporary: broad SSM read for dynamic config (test only)\n lambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\n \"ssm:GetParameter\",\n \"ssm:GetParameters\",\n \"ssm:DescribeParameters\",\n ],\n resources: [\"*\"],\n }),\n );\n const integration = new HttpLambdaIntegration(\"lambda-integration\", lambda);\n const { lambda: optionsLambda } = new CorsOptionsLambda(this);\n const optionsIntegration = new HttpLambdaIntegration(\n \"options-integration\",\n optionsLambda,\n );\n const noAuth = new HttpNoneAuthorizer();\n // OPTIONS routes use dedicated low-memory Lambda so main REST API Lambda is not invoked for preflight (#694).\n new HttpRoute(this, \"options-route-root\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/\", HttpMethod.OPTIONS),\n integration: optionsIntegration,\n authorizer: noAuth,\n });\n new HttpRoute(this, \"options-route-proxy\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/{proxy+}\", HttpMethod.OPTIONS),\n integration: optionsIntegration,\n authorizer: noAuth,\n });\n new HttpRoute(this, \"proxy-route-root\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/\", HttpMethod.ANY),\n integration,\n });\n new HttpRoute(this, \"proxy-route\", {\n httpApi: this.rootHttpApi,\n routeKey: HttpRouteKey.with(\"/{proxy+}\", HttpMethod.ANY),\n integration,\n });\n const apiPrefix =\n this.branchName === \"main\" ? `api` : `api-${this.childZonePrefix}`;\n new ARecord(this, \"api-a-record\", {\n zone: hostedZone,\n recordName: apiPrefix,\n target: RecordTarget.fromAlias(\n new ApiGatewayv2DomainProperties(\n domainName.regionalDomainName,\n domainName.regionalHostedZoneId,\n ),\n ),\n });\n }\n\n /**\n * Creates the Root HTTP API with default domain mapping, Cognito JWT authorizer, and exports API ID to SSM.\n * Look up via {@link OpenHiRestApiService.rootHttpApiFromConstruct}.\n * Override to customize.\n */\n protected createRootHttpApi(domainName: DomainName): RootHttpApi {\n const userPool = OpenHiAuthService.userPoolFromConstruct(this);\n const userPoolClient = OpenHiAuthService.userPoolClientFromConstruct(this);\n // In non-prod, also accept tokens issued by the dedicated\n // fixture-seeder client (provisioned in the auth stack only when\n // stage !== prod). Adding it to the authorizer's accepted-clients\n // list lets the seed-fixtures CLI authenticate against the same\n // API the SPA uses, without weakening prod which never sees this\n // client at all.\n const userPoolClients = [userPoolClient];\n if (this.ohEnv.ohStage.stageType !== OPEN_HI_STAGE.PROD) {\n userPoolClients.push(\n OpenHiAuthService.fixtureSeederClientFromConstruct(this),\n );\n }\n const cognitoAuthorizer = new HttpUserPoolAuthorizer(\n \"cognito-authorizer\",\n userPool,\n { userPoolClients },\n );\n const { corsPreflight: cors, ...restRootHttpApiProps } =\n this.props.rootHttpApiProps ?? {};\n const corsPreflight =\n cors !== undefined\n ? {\n allowOrigins: cors.allowOrigins,\n allowMethods: cors.allowMethods ?? [\n CorsHttpMethod.GET,\n CorsHttpMethod.HEAD,\n CorsHttpMethod.POST,\n CorsHttpMethod.PUT,\n CorsHttpMethod.PATCH,\n CorsHttpMethod.DELETE,\n CorsHttpMethod.OPTIONS,\n ],\n allowHeaders: cors.allowHeaders ?? [\n \"Content-Type\",\n \"Authorization\",\n ],\n allowCredentials: cors.allowCredentials ?? true,\n maxAge: cors.maxAge ?? Duration.days(1),\n ...(cors.exposeHeaders !== undefined && {\n exposeHeaders: cors.exposeHeaders,\n }),\n }\n : undefined;\n const rootHttpApi = new RootHttpApi(this, {\n ...restRootHttpApiProps,\n ...(corsPreflight !== undefined && { corsPreflight }),\n defaultDomainMapping: {\n domainName,\n mappingKey: undefined,\n },\n defaultAuthorizer: cognitoAuthorizer,\n });\n new DiscoverableStringParameter(this, \"http-api-url-param\", {\n ssmParamName: RootHttpApi.SSM_PARAM_NAME,\n stringValue: rootHttpApi.httpApiId,\n description:\n \"API Gateway HTTP API ID for this REST API stack (cross-stack reference)\",\n });\n return rootHttpApi;\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * Dedicated Lambda for CORS preflight (OPTIONS) requests. Returns 204 so API Gateway\n * can add CORS headers from the API's corsPreflight config. Low memory footprint.\n * @see #694\n */\n\nconst HANDLER_NAME = \"cors-options-lambda.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\nexport class CorsOptionsLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, id: string = \"cors-options-lambda\") {\n super(scope, id);\n\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 128,\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/data/lambda/rest-api-lambda.md\n */\n\nconst HANDLER_NAME = \"rest-api-lambda.handler.js\";\n\n/**\n * Resolve Lambda entry so it works when running from src/ (tests) or from lib/ (built).\n */\nfunction resolveHandlerEntry(dirname: string): string {\n const sameDir = path.join(dirname, HANDLER_NAME);\n if (fs.existsSync(sameDir)) {\n return sameDir;\n }\n\n const fromLib = path.join(dirname, \"..\", \"..\", \"..\", \"lib\", HANDLER_NAME);\n return fromLib;\n}\n\nexport interface RestApiLambdaProps {\n /**\n * DynamoDB table name for the data store. The Lambda receives it as the\n * environment variable DYNAMO_TABLE_NAME at runtime.\n */\n readonly dynamoTableName: string;\n\n /**\n * Branch name from the service. Passed as BRANCH_TAG_VALUE at runtime.\n */\n readonly branchTagValue: string;\n\n /**\n * SSM parameter name for the HTTP API (e.g. RootHttpApi.SSM_PARAM_NAME).\n * Passed as HTTP_API_TAG_VALUE at runtime.\n */\n readonly httpApiTagValue: string;\n\n /**\n * Aurora cluster ARN published by `DataStorePostgresReplica`. Passed as\n * `OPENHI_PG_CLUSTER_ARN` at runtime so the Lambda can target the cluster\n * via the RDS Data API (ADR 2026-04-17-01, phase 2).\n */\n readonly postgresClusterArn: string;\n\n /**\n * Secrets Manager ARN with the cluster credentials. Passed as\n * `OPENHI_PG_SECRET_ARN` at runtime; consumed by the RDS Data API client.\n */\n readonly postgresSecretArn: string;\n\n /**\n * Database name on the cluster. Passed as `OPENHI_PG_DATABASE` at runtime.\n */\n readonly postgresDatabase: string;\n\n /**\n * Per-branch schema name on the cluster (e.g. `b_<branchHash>`). Passed as\n * `OPENHI_PG_SCHEMA` at runtime.\n */\n readonly postgresSchema: string;\n}\n\nexport class RestApiLambda extends Construct {\n public readonly lambda: NodejsFunction;\n\n constructor(scope: Construct, props: RestApiLambdaProps) {\n super(scope, \"rest-api-lambda\");\n\n /**\n * Create a Lambda function\n */\n this.lambda = new NodejsFunction(this, \"handler\", {\n entry: resolveHandlerEntry(__dirname),\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 1024,\n environment: {\n DYNAMO_TABLE_NAME: props.dynamoTableName,\n BRANCH_TAG_VALUE: props.branchTagValue,\n HTTP_API_TAG_VALUE: props.httpApiTagValue,\n OPENHI_PG_CLUSTER_ARN: props.postgresClusterArn,\n OPENHI_PG_SECRET_ARN: props.postgresSecretArn,\n OPENHI_PG_DATABASE: props.postgresDatabase,\n OPENHI_PG_SCHEMA: props.postgresSchema,\n },\n bundling: {\n minify: true,\n sourceMap: false,\n },\n });\n }\n}\n","import {\n AuthorizationType,\n IGraphqlApi,\n UserPoolDefaultAction,\n} from \"aws-cdk-lib/aws-appsync\";\nimport { Construct } from \"constructs\";\nimport { OpenHiAuthService } from \"./open-hi-auth-service\";\nimport { OpenHiEnvironment } from \"../app/open-hi-environment\";\nimport {\n OpenHiService,\n OpenHiServiceProps,\n OpenHiServiceType,\n} from \"../app/open-hi-service\";\nimport { RootGraphqlApi } from \"../components/app-sync/root-graphql-api\";\n\nexport interface OpenHiGraphqlServiceProps extends OpenHiServiceProps {}\n\n/**\n * GraphQL API service stack: creates the AppSync API via {@link RootGraphqlApi}\n * and exports its ID via SSM. Look up from other stacks via\n * {@link OpenHiGraphqlService.graphqlApiFromConstruct}.\n */\nexport class OpenHiGraphqlService extends OpenHiService {\n static readonly SERVICE_TYPE =\n \"graphql-api\" as const satisfies OpenHiServiceType;\n\n /**\n * Returns the GraphQL API by looking up the GraphQL stack's API ID from SSM.\n * Use from other stacks to obtain an IGraphqlApi reference.\n */\n static graphqlApiFromConstruct(scope: Construct): IGraphqlApi {\n return RootGraphqlApi.fromConstruct(scope);\n }\n\n get serviceType(): string {\n return OpenHiGraphqlService.SERVICE_TYPE;\n }\n\n /* Override so this.props is typed with this service's options */\n public override props: OpenHiGraphqlServiceProps;\n\n public readonly rootGraphqlApi: RootGraphqlApi;\n\n constructor(ohEnv: OpenHiEnvironment, props: OpenHiGraphqlServiceProps = {}) {\n super(ohEnv, OpenHiGraphqlService.SERVICE_TYPE, props);\n this.props = props;\n this.rootGraphqlApi = this.createRootGraphqlApi();\n }\n\n /** Creates the root GraphQL API with Cognito user pool. */\n protected createRootGraphqlApi(): RootGraphqlApi {\n const userPool = OpenHiAuthService.userPoolFromConstruct(this);\n return new RootGraphqlApi(this, {\n authorizationConfig: {\n defaultAuthorization: {\n authorizationType: AuthorizationType.USER_POOL,\n userPoolConfig: {\n userPool,\n defaultAction: UserPoolDefaultAction.ALLOW,\n },\n },\n },\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport { OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR } from \"./events\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-lambdas.md\n */\n\ninterface ResolvedHandler {\n readonly entry: string;\n readonly handler: string;\n}\n\n/**\n * Resolve a Lambda entry under `src/` (tests) or `lib/` (compiled\n * bundle). Mirrors the dual-path lookup the seed-* lambdas use so the\n * same code path runs in unit tests, CDK snapshot tests, and prod.\n */\nfunction resolveHandlerEntry(\n dirname: string,\n handlerName: string,\n): ResolvedHandler {\n const sameDir = path.join(dirname, handlerName);\n if (fs.existsSync(sameDir)) {\n return { entry: sameDir, handler: \"handler\" };\n }\n const libDir = path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", handlerName);\n return { entry: libDir, handler: \"handler\" };\n}\n\nexport interface OwningDeleteCascadeLambdasProps {\n /** Data-store table the cascade reads (Query) and writes (DeleteItem / TransactWriteItems) against. */\n readonly dataStoreTable: ITable;\n /** Ops event bus the cascade finalize step publishes terminal events onto. */\n readonly opsEventBus: IEventBus;\n}\n\n/**\n * The three Lambdas that power the TR-022 owning-entity hard-delete\n * cascade state machine. Bundled together because the state machine\n * wires them in a fixed topology and they share the same data-store\n * grant pattern.\n *\n * - `listChunks` — pages through the owner's adjacency-list partition\n * via ElectroDB Query, splits the page into <=100-item chunks for\n * the inline Map state.\n * - `deleteChunk` — Map-iteration handler; submits one chunk as a\n * single `TransactWriteItems` via `executeMultiWrite`. The state\n * machine's `MaxConcurrency = 8` runs up to eight of these in\n * parallel.\n * - `finalize` — deletes the owning canonical record at\n * `SK = \"CURRENT\"` conditional on `lifecycleState = \"deleting\"`,\n * then emits the `control-plane.owning-delete-complete.v1` terminal\n * event on the ops event bus.\n *\n * IAM grants are scoped per-Lambda: the read/write Lambdas get\n * table-level Query / TransactWriteItems on the data store; the\n * finalize Lambda gets a focused `DeleteItem` + `PutEvents` policy\n * (no Query, no broad writes).\n */\nexport class OwningDeleteCascadeLambdas extends Construct {\n public readonly listChunks: NodejsFunction;\n public readonly deleteChunk: NodejsFunction;\n public readonly finalize: NodejsFunction;\n\n constructor(scope: Construct, props: OwningDeleteCascadeLambdasProps) {\n super(scope, \"owning-delete-cascade-lambdas\");\n\n const listResolved = resolveHandlerEntry(\n __dirname,\n \"list-chunks.handler.js\",\n );\n this.listChunks = new NodejsFunction(this, \"list-chunks-handler\", {\n entry: listResolved.entry,\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n },\n });\n props.dataStoreTable.grant(this.listChunks, \"dynamodb:Query\");\n\n const deleteResolved = resolveHandlerEntry(\n __dirname,\n \"delete-chunk.handler.js\",\n );\n this.deleteChunk = new NodejsFunction(this, \"delete-chunk-handler\", {\n entry: deleteResolved.entry,\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n },\n });\n // TransactWriteItems requires both the resource-level action and\n // (implicitly) DeleteItem on the items it touches. AWS treats\n // `dynamodb:DeleteItem` as the per-item permission inside a\n // TransactWriteItems delete, so grant both.\n props.dataStoreTable.grant(\n this.deleteChunk,\n \"dynamodb:DeleteItem\",\n \"dynamodb:UpdateItem\",\n \"dynamodb:PutItem\",\n );\n\n const finalizeResolved = resolveHandlerEntry(\n __dirname,\n \"finalize.handler.js\",\n );\n this.finalize = new NodejsFunction(this, \"finalize-handler\", {\n entry: finalizeResolved.entry,\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n [OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR]: props.opsEventBus.eventBusName,\n },\n });\n props.dataStoreTable.grant(this.finalize, \"dynamodb:DeleteItem\");\n this.finalize.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"events:PutEvents\"],\n resources: [props.opsEventBus.eventBusArn],\n }),\n );\n }\n}\n","import { Duration } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { SfnStateMachine } from \"aws-cdk-lib/aws-events-targets\";\nimport {\n Choice,\n Condition,\n CustomState,\n DefinitionBody,\n Pass,\n StateMachine,\n Succeed,\n TaskInput,\n Wait,\n WaitTime,\n} from \"aws-cdk-lib/aws-stepfunctions\";\nimport { LambdaInvoke } from \"aws-cdk-lib/aws-stepfunctions-tasks\";\nimport { Construct } from \"constructs\";\nimport {\n ControlPlaneOwningDeleteV1,\n OPENHI_DATA_SOURCE,\n OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY,\n} from \"./events\";\nimport { OwningDeleteCascadeLambdas } from \"./owning-delete-cascade-lambdas\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-workflow.md\n */\n\nexport interface OwningDeleteCascadeWorkflowProps {\n /**\n * Data event bus carrying `control-plane.owning-delete.v1`. The\n * workflow's EventBridge rule lives on this bus and starts a state\n * machine execution per matching event.\n */\n readonly dataEventBus: IEventBus;\n /** Ops event bus the cascade finalize step publishes terminal events onto. */\n readonly opsEventBus: IEventBus;\n /** Data-store table the cascade reads from / writes deletes into. */\n readonly dataStoreTable: ITable;\n /**\n * Inline-Map max concurrency. Defaults to\n * {@link OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY} (8) per the\n * ADR-018 implementation guide section 4 — tunable per environment.\n * NOTE: this is an **inline** Map (NOT Distributed Map — TR-022\n * Choice 2A pins inline; TR-023 uses Distributed for renames).\n */\n readonly cascadeMapConcurrency?: number;\n}\n\n/**\n * Control-plane workflow that fans out the TR-022 owning-entity\n * hard-delete cascade.\n *\n * Pipeline (per the ADR-018 implementation guide section 4):\n *\n * 1. Synchronous API entry point flips the canonical owning record's\n * `lifecycleState: active -> deleting`. (Owned by the REST adapter,\n * not this construct.)\n * 2. DynamoDB stream / Firehose transform publishes\n * `control-plane.owning-delete.v1` on the data event bus.\n * 3. EventBridge rule (owned here) starts this state machine.\n * 4. State machine outer loop:\n * - `ListChunks` Lambda pages through the owner's adjacency-list\n * partition and emits chunks of up to 100 projection rows.\n * - `RewriteChunks` inline Map (MaxConcurrency = 8) deletes each\n * chunk in parallel via `executeMultiWrite`.\n * - `IsExhausted` Choice loops back to `ListChunks` until the page\n * query returns zero items and every per-entity cursor is `null`.\n * 5. `Finalize` Lambda deletes the canonical owning record\n * (conditional on `lifecycleState = \"deleting\"`) and emits\n * `control-plane.owning-delete-complete.v1` on the ops event bus.\n *\n * Idempotency: every Map iteration uses a per-chunk `ClientRequestToken`,\n * and the finalize step's canonical delete is conditional on\n * `lifecycleState = \"deleting\"`. A replayed execution finds no rows\n * to delete, no canonical to remove, and emits no terminal event.\n */\nexport class OwningDeleteCascadeWorkflow extends Construct {\n public readonly lambdas: OwningDeleteCascadeLambdas;\n public readonly stateMachine: StateMachine;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: OwningDeleteCascadeWorkflowProps) {\n super(scope, \"owning-delete-cascade-workflow\");\n\n this.lambdas = new OwningDeleteCascadeLambdas(this, {\n dataStoreTable: props.dataStoreTable,\n opsEventBus: props.opsEventBus,\n });\n\n const concurrency =\n props.cascadeMapConcurrency ?? OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY;\n\n // Step 1: Initialize cascade state from the EventBridge envelope.\n // Pulls `ownerType`, `ownerId`, `tenantId` from the workflow event\n // payload and seeds cursors / accumulators.\n const initState = new Pass(this, \"init-state\", {\n parameters: {\n \"ownerType.$\": \"$.detail.payload.ownerType\",\n \"ownerId.$\": \"$.detail.payload.ownerId\",\n \"tenantId.$\": \"$.detail.payload.tenantId\",\n cursors: {},\n projectionsRemoved: 0,\n chunkCount: 0,\n // Used by the finalize step to compute `durationMs`.\n \"startedAt.$\": \"$$.Execution.StartTime\",\n // Propagate envelope identity for ADR-016 causation chaining.\n \"eventId.$\": \"$.detail.eventId\",\n \"correlationId.$\": \"$.detail.correlationId\",\n \"causationId.$\": \"$.detail.eventId\",\n },\n });\n\n // Step 2: Query a page of child projection rows + split into chunks.\n // `payload` defaults to the entire task input (`$`), so the\n // listChunks handler receives the cascade state verbatim.\n const listChunks = new LambdaInvoke(this, \"list-chunks\", {\n lambdaFunction: this.lambdas.listChunks,\n resultPath: \"$.listResult\",\n retryOnServiceExceptions: true,\n });\n\n // Reconstitute the cascade state from the page response. Carry\n // every field forward so the loop's next iteration has the\n // accumulator + envelope identity intact.\n const updateAfterList = new Pass(this, \"update-after-list\", {\n parameters: {\n \"ownerType.$\": \"$.ownerType\",\n \"ownerId.$\": \"$.ownerId\",\n \"tenantId.$\": \"$.tenantId\",\n \"cursors.$\": \"$.listResult.Payload.cursors\",\n \"projectionsRemoved.$\": \"$.listResult.Payload.projectionsRemoved\",\n \"chunkCount.$\": \"$.listResult.Payload.chunkCount\",\n \"exhausted.$\": \"$.listResult.Payload.exhausted\",\n \"chunks.$\": \"$.listResult.Payload.chunks\",\n \"startedAt.$\": \"$.startedAt\",\n \"eventId.$\": \"$.eventId\",\n \"correlationId.$\": \"$.correlationId\",\n \"causationId.$\": \"$.causationId\",\n },\n });\n\n // Step 3: Inline Map state — fan out chunk deletes.\n //\n // Step Functions L2 `Map` exists, but the L2 + `LambdaInvoke`\n // task-state combination does not surface inline-Map's `Retry` /\n // `Catch` blocks the implementation guide specifies. Drop to an\n // ASL `CustomState` so the retry / catch shapes match the guide\n // exactly. The state is INLINE (not Distributed) per TR-022\n // Choice 2A — `Mode` is omitted (inline is the default); the\n // sibling rename cascade (TR-023) is the one that uses\n // `Mode: DISTRIBUTED`.\n const rewriteChunks = new CustomState(this, \"rewrite-chunks\", {\n stateJson: {\n Type: \"Map\",\n ItemsPath: \"$.chunks\",\n MaxConcurrency: concurrency,\n ResultPath: \"$.rewriteResults\",\n ItemSelector: {\n // The handler receives `CascadeChunkInput` verbatim from the\n // `listChunks` output, no additional wrapping.\n \"ownerType.$\": \"$$.Map.Item.Value.ownerType\",\n \"ownerId.$\": \"$$.Map.Item.Value.ownerId\",\n \"tenantId.$\": \"$$.Map.Item.Value.tenantId\",\n \"rows.$\": \"$$.Map.Item.Value.rows\",\n \"chunkToken.$\": \"$$.Map.Item.Value.chunkToken\",\n },\n ItemProcessor: {\n ProcessorConfig: {\n // Inline mode (NOT Distributed). Per TR-022 Choice 2A.\n Mode: \"INLINE\",\n },\n StartAt: \"DeleteChunk\",\n States: {\n DeleteChunk: {\n Type: \"Task\",\n Resource: \"arn:aws:states:::lambda:invoke\",\n Parameters: {\n FunctionName: this.lambdas.deleteChunk.functionArn,\n \"Payload.$\": \"$\",\n },\n Retry: [\n {\n ErrorEquals: [\n \"DynamoDB.ProvisionedThroughputExceededException\",\n \"DynamoDB.ThrottlingException\",\n \"DynamoDB.TransactionConflictException\",\n \"Lambda.ServiceException\",\n \"Lambda.AWSLambdaException\",\n \"Lambda.SdkClientException\",\n ],\n IntervalSeconds: 1,\n MaxAttempts: 3,\n BackoffRate: 2.0,\n MaxDelaySeconds: 30,\n },\n ],\n Catch: [\n {\n // Replay path: the rows in this chunk are already\n // gone. Treat as a no-op success so the outer loop\n // keeps draining the partition.\n ErrorEquals: [\"DynamoDB.TransactionCanceledException\"],\n Next: \"ChunkAlreadyDeleted\",\n },\n ],\n End: true,\n },\n ChunkAlreadyDeleted: {\n Type: \"Succeed\",\n },\n },\n },\n },\n });\n\n // Outer loop control: a small wait between pages so retries do\n // not hammer DynamoDB on a partial throttle.\n const interPageWait = new Wait(this, \"inter-page-wait\", {\n time: WaitTime.duration(Duration.seconds(0)),\n });\n\n // Step 4: Choice — keep draining until the per-entity cursors all\n // return null AND the page is empty.\n const isExhausted = new Choice(this, \"is-exhausted\");\n\n // Step 5: Finalize — delete the canonical owning row and emit the\n // terminal event.\n const finalize = new LambdaInvoke(this, \"finalize\", {\n lambdaFunction: this.lambdas.finalize,\n payload: TaskInput.fromObject({\n \"ownerType.$\": \"$.ownerType\",\n \"ownerId.$\": \"$.ownerId\",\n \"tenantId.$\": \"$.tenantId\",\n \"projectionsRemoved.$\": \"$.projectionsRemoved\",\n \"chunkCount.$\": \"$.chunkCount\",\n \"startedAt.$\": \"$.startedAt\",\n \"eventId.$\": \"$.eventId\",\n \"correlationId.$\": \"$.correlationId\",\n \"causationId.$\": \"$.causationId\",\n }),\n resultPath: \"$.finalizeResult\",\n retryOnServiceExceptions: true,\n });\n\n const success = new Succeed(this, \"success\");\n\n // Wire the state machine topology:\n // InitState\n // -> ListChunks\n // -> UpdateAfterList\n // -> RewriteChunks (inline Map, MaxConcurrency = 8)\n // -> InterPageWait\n // -> IsExhausted\n // ├── (exhausted) -> Finalize -> Success\n // └── (more) -> ListChunks (loop)\n const definition = initState\n .next(listChunks)\n .next(updateAfterList)\n .next(rewriteChunks)\n .next(interPageWait)\n .next(\n isExhausted\n .when(\n Condition.booleanEquals(\"$.exhausted\", true),\n finalize.next(success),\n )\n .otherwise(listChunks),\n );\n\n this.stateMachine = new StateMachine(this, \"state-machine\", {\n definitionBody: DefinitionBody.fromChainable(definition),\n // Long timeout because real-world cascades can run minutes when\n // a workspace has thousands of members. The stuck-cascade alarm\n // fires at 15 minutes; the state machine itself does not abort.\n timeout: Duration.hours(2),\n });\n\n // EventBridge rule — match the input detail-type on the data bus\n // and start the state machine for each event.\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.dataEventBus,\n eventPattern: {\n source: [OPENHI_DATA_SOURCE],\n detailType: [ControlPlaneOwningDeleteV1.detailType],\n },\n targets: [\n new SfnStateMachine(this.stateMachine, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Duration } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus } from \"aws-cdk-lib/aws-events\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { NodejsFunction } from \"aws-cdk-lib/aws-lambda-nodejs\";\nimport { Construct } from \"constructs\";\nimport { RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR } from \"./events\";\n\ninterface ResolvedHandler {\n readonly entry: string;\n readonly handler: string;\n}\n\n/**\n * Resolve a Lambda entry under `src/` (tests) or `lib/` (compiled\n * bundle). Mirrors the dual-path lookup the sibling cascade lambdas use\n * so the same code path runs in unit tests, CDK snapshot tests, and prod.\n */\nfunction resolveHandlerEntry(\n dirname: string,\n handlerName: string,\n): ResolvedHandler {\n const sameDir = path.join(dirname, handlerName);\n if (fs.existsSync(sameDir)) {\n return { entry: sameDir, handler: \"handler\" };\n }\n const libDir = path.join(dirname, \"..\", \"..\", \"..\", \"..\", \"lib\", handlerName);\n return { entry: libDir, handler: \"handler\" };\n}\n\nexport interface RenameCascadeLambdasProps {\n /** Data-store table the cascade reads (Query) and writes (TransactWriteItems) against. */\n readonly dataStoreTable: ITable;\n /** Ops event bus the cascade finalize step publishes terminal events onto. */\n readonly opsEventBus: IEventBus;\n}\n\n/**\n * The three Lambdas that power the TR-023 rename cascade state machine.\n *\n * - `listTargets` — pages through the affected projection partitions\n * for a rename and emits chunks of up to 50 rewrite targets.\n * - `rewriteChunk` — Distributed-Map iteration handler; submits one\n * chunk as a single `TransactWriteItems` via `executeMultiWrite`. The\n * state machine's `MaxConcurrency = 10` runs up to ten of these in\n * parallel.\n * - `finalize` — emits `control-plane.rename-complete.v1` on the ops\n * event bus.\n *\n * IAM grants are scoped per-Lambda: read/write Lambdas get table-level\n * Query / TransactWriteItems on the data store; the finalize Lambda\n * gets only `events:PutEvents` on the ops event bus.\n */\nexport class RenameCascadeLambdas extends Construct {\n public readonly listTargets: NodejsFunction;\n public readonly rewriteChunk: NodejsFunction;\n public readonly finalize: NodejsFunction;\n\n constructor(scope: Construct, props: RenameCascadeLambdasProps) {\n super(scope, \"rename-cascade-lambdas\");\n\n const listResolved = resolveHandlerEntry(\n __dirname,\n \"rename-list-targets.handler.js\",\n );\n this.listTargets = new NodejsFunction(this, \"list-targets-handler\", {\n entry: listResolved.entry,\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n },\n });\n props.dataStoreTable.grant(this.listTargets, \"dynamodb:Query\");\n\n const rewriteResolved = resolveHandlerEntry(\n __dirname,\n \"rename-rewrite-chunk.handler.js\",\n );\n this.rewriteChunk = new NodejsFunction(this, \"rewrite-chunk-handler\", {\n entry: rewriteResolved.entry,\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,\n },\n });\n // TransactWriteItems with delete + put pairs requires both per-item\n // permissions.\n props.dataStoreTable.grant(\n this.rewriteChunk,\n \"dynamodb:DeleteItem\",\n \"dynamodb:PutItem\",\n \"dynamodb:UpdateItem\",\n );\n\n const finalizeResolved = resolveHandlerEntry(\n __dirname,\n \"rename-finalize.handler.js\",\n );\n this.finalize = new NodejsFunction(this, \"finalize-handler\", {\n entry: finalizeResolved.entry,\n runtime: Runtime.NODEJS_LATEST,\n memorySize: 512,\n timeout: Duration.minutes(1),\n environment: {\n [RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR]: props.opsEventBus.eventBusName,\n },\n });\n this.finalize.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"events:PutEvents\"],\n resources: [props.opsEventBus.eventBusArn],\n }),\n );\n }\n}\n","import { Duration } from \"aws-cdk-lib\";\nimport { ITable } from \"aws-cdk-lib/aws-dynamodb\";\nimport { IEventBus, Rule } from \"aws-cdk-lib/aws-events\";\nimport { SfnStateMachine } from \"aws-cdk-lib/aws-events-targets\";\nimport {\n Choice,\n Condition,\n CustomState,\n DefinitionBody,\n Pass,\n StateMachine,\n Succeed,\n TaskInput,\n} from \"aws-cdk-lib/aws-stepfunctions\";\nimport { LambdaInvoke } from \"aws-cdk-lib/aws-stepfunctions-tasks\";\nimport { Construct } from \"constructs\";\nimport {\n ControlPlaneRenameV1,\n OPENHI_DATA_SOURCE,\n RENAME_CASCADE_DEFAULT_CONCURRENCY,\n} from \"./events\";\nimport { RenameCascadeLambdas } from \"./rename-cascade-lambdas\";\n\nexport interface RenameCascadeWorkflowProps {\n /**\n * Data event bus carrying `control-plane.rename.v1`. The workflow's\n * EventBridge rule lives on this bus and starts a state machine\n * execution per matching event.\n */\n readonly dataEventBus: IEventBus;\n /** Ops event bus the cascade finalize step publishes terminal events onto. */\n readonly opsEventBus: IEventBus;\n /** Data-store table the cascade reads from / writes rewrites into. */\n readonly dataStoreTable: ITable;\n /**\n * Distributed-Map max concurrency. Defaults to\n * {@link RENAME_CASCADE_DEFAULT_CONCURRENCY} (10) per the ADR-018\n * implementation guide section 5 — tunable per environment.\n *\n * NOTE: this is a **Distributed** Map (NOT inline — TR-022's\n * owning-delete cascade uses inline; TR-023's rename cascade uses\n * Distributed).\n */\n readonly cascadeMapConcurrency?: number;\n}\n\n/**\n * Control-plane workflow that fans out the TR-023 rename cascade.\n *\n * Pipeline (per the ADR-018 implementation guide section 5):\n *\n * 1. The Firehose transform Lambda publishes\n * `control-plane.rename.v1` on the data event bus when it observes\n * a stream record showing a display-name change on a canonical\n * Tenant / User / Role row.\n * 2. EventBridge rule (owned here) starts this state machine.\n * 3. State machine outer loop:\n * - `ListTargets` Lambda pages through the affected projection\n * partitions for the renamed entity and emits chunks of up to 50\n * rewrite targets.\n * - `RewriteChunks` Distributed Map (MaxConcurrency = 10) rewrites\n * each chunk in parallel via `executeMultiWrite`. Each target\n * maps to either a `delete oldKey` + `put newItem` pair (SK\n * rewrite) or a single `put newItem` overwrite (attr-only update).\n * - `IsExhausted` Choice loops back to `ListTargets` until every\n * per-stream cursor returns `null`.\n * 4. `Finalize` Lambda emits `control-plane.rename-complete.v1` on the\n * ops event bus.\n *\n * Idempotency: every Map iteration uses a per-chunk `ClientRequestToken`,\n * and the state machine's `Catch` block absorbs\n * `DynamoDB.TransactionCanceledException` as a no-op success — a\n * replayed chunk where every row is already at the new SK fails its\n * delete-old triple and the helper rolls back; the cascade keeps\n * draining the page until the outer loop terminates on exhaustion.\n * Lost-race writes (per the TR-023 idempotency rule) are accepted —\n * the renaming write loses to a later concurrent write on the same row.\n */\nexport class RenameCascadeWorkflow extends Construct {\n public readonly lambdas: RenameCascadeLambdas;\n public readonly stateMachine: StateMachine;\n public readonly rule: Rule;\n\n constructor(scope: Construct, props: RenameCascadeWorkflowProps) {\n super(scope, \"rename-cascade-workflow\");\n\n this.lambdas = new RenameCascadeLambdas(this, {\n dataStoreTable: props.dataStoreTable,\n opsEventBus: props.opsEventBus,\n });\n\n const concurrency =\n props.cascadeMapConcurrency ?? RENAME_CASCADE_DEFAULT_CONCURRENCY;\n\n // Step 1: Initialize cascade state from the EventBridge envelope.\n // Pulls `entityType`, `entityId`, `tenantId`, name/normalizedName\n // from the workflow event payload and seeds cursors / accumulators.\n const initState = new Pass(this, \"init-state\", {\n parameters: {\n \"entityType.$\": \"$.detail.payload.entityType\",\n \"entityId.$\": \"$.detail.payload.entityId\",\n \"tenantId.$\": \"$.detail.payload.tenantId\",\n \"oldName.$\": \"$.detail.payload.oldName\",\n \"newName.$\": \"$.detail.payload.newName\",\n \"oldNormalizedName.$\": \"$.detail.payload.oldNormalizedName\",\n \"newNormalizedName.$\": \"$.detail.payload.newNormalizedName\",\n cursors: {},\n itemsRewritten: 0,\n chunkCount: 0,\n \"startedAt.$\": \"$$.Execution.StartTime\",\n \"eventId.$\": \"$.detail.eventId\",\n \"correlationId.$\": \"$.detail.correlationId\",\n \"causationId.$\": \"$.detail.eventId\",\n },\n });\n\n // Step 2: Query one page of targets + split into chunks.\n const listTargets = new LambdaInvoke(this, \"list-targets\", {\n lambdaFunction: this.lambdas.listTargets,\n resultPath: \"$.listResult\",\n retryOnServiceExceptions: true,\n });\n\n // Reconstitute the cascade state from the page response.\n const updateAfterList = new Pass(this, \"update-after-list\", {\n parameters: {\n \"entityType.$\": \"$.entityType\",\n \"entityId.$\": \"$.entityId\",\n \"tenantId.$\": \"$.tenantId\",\n \"oldName.$\": \"$.oldName\",\n \"newName.$\": \"$.newName\",\n \"oldNormalizedName.$\": \"$.oldNormalizedName\",\n \"newNormalizedName.$\": \"$.newNormalizedName\",\n \"cursors.$\": \"$.listResult.Payload.cursors\",\n \"itemsRewritten.$\": \"$.listResult.Payload.itemsRewritten\",\n \"chunkCount.$\": \"$.listResult.Payload.chunkCount\",\n \"exhausted.$\": \"$.listResult.Payload.exhausted\",\n \"chunks.$\": \"$.listResult.Payload.chunks\",\n \"startedAt.$\": \"$.startedAt\",\n \"eventId.$\": \"$.eventId\",\n \"correlationId.$\": \"$.correlationId\",\n \"causationId.$\": \"$.causationId\",\n },\n });\n\n // Step 3: Distributed Map state — fan out chunk rewrites.\n //\n // Step Functions L2 `Map` does not surface Distributed-Map's\n // `ItemProcessor.ProcessorConfig.Mode: DISTRIBUTED` cleanly with\n // the L2 + `LambdaInvoke` combo. Drop to an ASL `CustomState` so\n // the shape matches the implementation guide exactly. The state\n // is DISTRIBUTED (per TR-023 — distinguishes the rename cascade\n // from TR-022's INLINE owning-delete cascade) with MaxConcurrency\n // = 10.\n const rewriteChunks = new CustomState(this, \"rewrite-chunks\", {\n stateJson: {\n Type: \"Map\",\n ItemsPath: \"$.chunks\",\n MaxConcurrency: concurrency,\n ResultPath: \"$.rewriteResults\",\n ItemSelector: {\n \"entityType.$\": \"$$.Map.Item.Value.entityType\",\n \"entityId.$\": \"$$.Map.Item.Value.entityId\",\n \"tenantId.$\": \"$$.Map.Item.Value.tenantId\",\n \"targets.$\": \"$$.Map.Item.Value.targets\",\n \"chunkToken.$\": \"$$.Map.Item.Value.chunkToken\",\n },\n ItemProcessor: {\n ProcessorConfig: {\n // DISTRIBUTED mode — per TR-023 (NOT INLINE; that is\n // TR-022's territory).\n Mode: \"DISTRIBUTED\",\n ExecutionType: \"STANDARD\",\n },\n StartAt: \"RewriteChunk\",\n States: {\n RewriteChunk: {\n Type: \"Task\",\n Resource: \"arn:aws:states:::lambda:invoke\",\n Parameters: {\n FunctionName: this.lambdas.rewriteChunk.functionArn,\n \"Payload.$\": \"$\",\n },\n Retry: [\n {\n ErrorEquals: [\n \"DynamoDB.ProvisionedThroughputExceededException\",\n \"DynamoDB.ThrottlingException\",\n \"DynamoDB.TransactionConflictException\",\n \"Lambda.ServiceException\",\n \"Lambda.AWSLambdaException\",\n \"Lambda.SdkClientException\",\n ],\n IntervalSeconds: 1,\n MaxAttempts: 5,\n BackoffRate: 2.0,\n MaxDelaySeconds: 30,\n },\n ],\n Catch: [\n {\n // Replay path: the rewrite race \"lost to a later\n // write\" per TR-023 idempotency. Treat as a no-op\n // success so the outer loop keeps draining the page.\n ErrorEquals: [\"DynamoDB.TransactionCanceledException\"],\n Next: \"ChunkAlreadyRewritten\",\n },\n ],\n End: true,\n },\n ChunkAlreadyRewritten: {\n Type: \"Succeed\",\n },\n },\n },\n },\n });\n\n // Step 4: Choice — keep draining until every per-stream cursor\n // returns null.\n const isExhausted = new Choice(this, \"is-exhausted\");\n\n // Step 5: Finalize — emit the terminal event.\n const finalize = new LambdaInvoke(this, \"finalize\", {\n lambdaFunction: this.lambdas.finalize,\n payload: TaskInput.fromObject({\n \"entityType.$\": \"$.entityType\",\n \"entityId.$\": \"$.entityId\",\n \"tenantId.$\": \"$.tenantId\",\n \"newName.$\": \"$.newName\",\n \"itemsRewritten.$\": \"$.itemsRewritten\",\n \"chunkCount.$\": \"$.chunkCount\",\n \"startedAt.$\": \"$.startedAt\",\n \"eventId.$\": \"$.eventId\",\n \"correlationId.$\": \"$.correlationId\",\n \"causationId.$\": \"$.causationId\",\n }),\n resultPath: \"$.finalizeResult\",\n retryOnServiceExceptions: true,\n });\n\n const success = new Succeed(this, \"success\");\n\n // Wire the state machine topology:\n // InitState\n // -> ListTargets\n // -> UpdateAfterList\n // -> RewriteChunks (Distributed Map, MaxConcurrency = 10)\n // -> IsExhausted\n // ├── (exhausted) -> Finalize -> Success\n // └── (more) -> ListTargets (loop)\n const definition = initState\n .next(listTargets)\n .next(updateAfterList)\n .next(rewriteChunks)\n .next(\n isExhausted\n .when(\n Condition.booleanEquals(\"$.exhausted\", true),\n finalize.next(success),\n )\n .otherwise(listTargets),\n );\n\n this.stateMachine = new StateMachine(this, \"state-machine\", {\n definitionBody: DefinitionBody.fromChainable(definition),\n // Long timeout — large renames may rewrite thousands of rows;\n // the `CascadeSlow` alarm fires at 300s p99 but the state\n // machine itself does not abort.\n timeout: Duration.hours(2),\n });\n\n // EventBridge rule — match the input detail-type on the data bus.\n this.rule = new Rule(this, \"rule\", {\n eventBus: props.dataEventBus,\n eventPattern: {\n source: [OPENHI_DATA_SOURCE],\n detailType: [ControlPlaneRenameV1.detailType],\n },\n targets: [\n new SfnStateMachine(this.stateMachine, {\n retryAttempts: 2,\n maxEventAge: Duration.hours(2),\n }),\n ],\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAca,YAAA,gBAAgB;;;;MAI3B,KAAK;;;;MAIL,OAAO;;;;MAIP,MAAM;;AAeK,YAAA,iCAAiC;;;;;MAK5C,SAAS;;;;;MAMT,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;ACpDb,iBAAA,0BAAA,OAAA;;;;;ACAA,IAAAA,iBAKO;AACP,SAAS,WAAqB;;;ACN9B,oBAGO;AACP,SAAS,aAAyB;AAWlC,IAAM,6BAA6B,uBAAO;AAAA,EACxC;AACF;AAoBO,IAAM,oBAAN,MAAM,2BAA0B,MAAM;AAAA;AAAA;AAAA;AAAA,EAoC3C,YAIS,SAIA,OACP;AAIA,QAAI,MAAM,OAAO,WAAW,MAAM,OAAO,QAAQ;AAC/C,cAAQ;AAAA,QACN,GAAG;AAAA,QACH,KAAK;AAAA,UACH,SAAS,MAAM,OAAO;AAAA,UACtB,QAAQ,MAAM,OAAO;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAKA,UAAM,YACJ,MAAM,yBAAyB,6CAA+B,UAC1D,MAAM,uBACN,CAAC,MAAM,sBAAsB,QAAQ,aAAa,MAAM,EAAE,KAAK,GAAG;AAExE,UAAM,SAAS,WAAW;AAAA,MACxB,KAAK,MAAM,OAAO,QAAQ,MAAM;AAAA,MAChC,GAAG;AAAA,IACL,CAAC;AA9BM;AAIA;AA6BP,WAAO,eAAe,MAAM,4BAA4B,EAAE,OAAO,KAAK,CAAC;AAEvE,SAAK,uBAAuB,MAAM;AAClC,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAxEA,OAAc,GAAG,WAAsD;AACrE,WAAO,UAAU,KAAK,OACnB,QAAQ,EACR,KAAK,mBAAkB,mBAAmB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,OAAc,oBAEZ,GACwB;AACxB,WACE,MAAM,QAAQ,OAAO,MAAM,YAAY,8BAA8B;AAAA,EAEzE;AAyDF;;;AClHA,SAAS,SAAAC,cAAyB;AAclC,IAAM,uBAAuB,uBAAO,IAAI,qCAAqC;AAetE,IAAM,cAAN,MAAM,qBAAoBC,OAAM;AAAA;AAAA;AAAA;AAAA,EAuBrC,YAMS,OAOA,OACP;AACA,UAAM,OAAO,MAAM,WAAW,KAAK;AAT5B;AAOA;AAIP,WAAO,eAAe,MAAM,sBAAsB,EAAE,OAAO,KAAK,CAAC;AAEjE,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAvCA,OAAc,GAAG,WAAgD;AAC/D,WAAO,UAAU,KAAK,OAAO,QAAQ,EAAE,KAAK,aAAY,aAAa;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAc,cAA0B,GAA0B;AAChE,WAAO,MAAM,QAAQ,OAAO,MAAM,YAAY,wBAAwB;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAmCA,IAAW,eAAyC;AAClD,WAAO,KAAK,KAAK,SAAS,OAAO,kBAAkB,mBAAmB;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,qBAAoD;AAC7D,WAAO,KAAK,aAAa;AAAA,MACvB,CAAC,QAAQ,IAAI,yBAAyB;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,wBAAkD;AAC3D,WAAO,KAAK,aAAa;AAAA,MACvB,CAAC,QAAQ,IAAI,yBAAyB;AAAA,IACxC;AAAA,EACF;AACF;;;AF/EA,IAAM,qBAAqB,uBAAO,IAAI,mCAAmC;AAsBlE,IAAM,YAAN,MAAM,mBAAkB,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAKjC,OAAc,GAAG,WAA8C;AAC7D,WAAO,UAAU,KAAK,OAAO,QAAQ,EAAE,KAAK,WAAU,WAAW;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAc,YAAwB,GAAwB;AAC5D,WAAO,MAAM,QAAQ,OAAO,MAAM,YAAY,sBAAsB;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAeA,YAAY,OAAuB;AACjC,UAAM,KAAK;AAGX,WAAO,eAAe,MAAM,oBAAoB,EAAE,OAAO,KAAK,CAAC;AAG/D,SAAK,UAAU,MAAM,WAAW;AAGhC,SAAK,SAAS,MAAM;AAIpB,WAAO,OAAO,4BAAa,EAAE,QAAQ,CAAC,cAAc;AAElD,UAAI,KAAK,OAAO,oBAAoB,SAAS,GAAG;AAC9C,cAAM,QAAQ,IAAI,YAAY,MAAM,EAAE,UAAU,CAAC;AAIjD,YACE,KAAK,OAAO,oBAAoB,SAAS,IACvC,8CAA+B,OACjC,GACA;AACA,gBAAM,YACJ,KAAK,OAAO,kBAAkB,SAAS,EACrC,8CAA+B,OACjC;AACF,cAAI,kBAAkB,OAAO;AAAA,YAC3B,sBAAsB,8CAA+B;AAAA,YACrD,QAAQ;AAAA,YACR,KAAK,EAAE,SAAS,UAAU,SAAS,QAAQ,UAAU,OAAO;AAAA,UAC9D,CAAC;AAAA,QACH;AAIA,YACE,KAAK,OAAO,oBAAoB,SAAS,IACvC,8CAA+B,SACjC,GACA;AACA,eAAK,OAAO,kBAAkB,SAAS,EACrC,8CAA+B,SACjC,EAAG,QAAQ,CAAC,cAAuC;AACjD,gBAAI,kBAAkB,OAAO;AAAA,cAC3B,sBAAsB,8CAA+B;AAAA,cACrD,QAAQ;AAAA,cACR,KAAK,EAAE,SAAS,UAAU,SAAS,QAAQ,UAAU,OAAO;AAAA,YAC9D,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAW,SAA6B;AACtC,WAAO,KAAK,KAAK,SAAS,OAAO,YAAY,aAAa;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,WAAoC;AAC7C,WAAO,KAAK,OAAO,KAAK,CAAC,UAAU,MAAM,cAAc,6BAAc,GAAG;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,aAAsC;AAC/C,WAAO,KAAK,OAAO,KAAK,CAAC,UAAU,MAAM,cAAc,6BAAc,KAAK;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,YAAqC;AAC9C,WAAO,KAAK,OAAO,KAAK,CAAC,UAAU,MAAM,cAAc,6BAAc,IAAI;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAW,eAAyC;AAClD,WAAO,KAAK,OAAO,QAAQ,CAAC,UAAU,MAAM,YAAY;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,sBAAgD;AACzD,WAAO,KAAK,aAAa;AAAA,MACvB,CAAC,QAAQ,IAAI,yBAAyB;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,wBAAkD;AAC3D,WAAO,KAAK,aAAa;AAAA,MACvB,CAAC,QAAQ,IAAI,yBAAyB;AAAA,IACxC;AAAA,EACF;AACF;;;AG7LA,IAAAC,iBAAuD;AALvD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,eAAe,OAAmB,YAAY;AACvD,SAAS,iBAAiB;AA4BnB,IAAM,8BAA8B;AAEpC,IAAM,gCAAgC;AAEtC,IAAM,iCAAiC;AAEvC,IAAM,+BAA+B;AAQrC,IAAM,eAAe,CAAC,SAAiB,WAC5C,GAAG,OAAO,IAAI,MAAM;AAgDf,IAAe,gBAAf,cAAqC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyEhD,YACS,OACP,IACO,QAA4B,CAAC,GACpC;AAGA,UAAM,EAAE,SAAS,OAAO,IAAI,MAAM,OAAO;AACzC,QAAI,CAAC,WAAW,CAAC,QAAQ;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,UAAM,UAAU,MAAM,WAAW,MAAM,QAAQ,MAAM,WAAW;AAKhE,UAAM,WAAW,MAAM,YAAY,gBAAgB;AAGnD,UAAM,uBAAuB,MAAM,wBAAwB;AAS3D,UAAM,aACJ,MAAM,eACL,QAAQ,IAAI,iBACT,gBACA,QAAQ,IAAI,iBAAiB,KAAK,MACjC,MAAM,QAAQ,cAAc,6BAAc,MACvC,cAAc,IACd;AAIV,UAAM,kBAAkB;AAAA,MACtB,CAAC,SAAS,MAAM,sBAAsB,SAAS,MAAM,EAAE,KAAK,GAAG;AAAA,MAC/D;AAAA,IACF;AAIA,UAAM,aAAa;AAAA,MACjB,CAAC,SAAS,MAAM,sBAAsB,SAAS,QAAQ,UAAU,EAAE;AAAA,QACjE;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAKA,UAAM,YAAY;AAAA,MAChB;AAAA,QACE;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,MACV;AAAA,IACF;AAIA,UAAM,gBACJ,MAAM,kBACL,MAAM,QAAQ,cAAc,6BAAc,OACvC,cAAc,SACd,cAAc;AACpB,WAAO,OAAO,OAAO,EAAE,cAAc,CAAC;AAItC,UAAM,cAAc,mBAAmB,EAAE,KAAK,UAAU,OAAO,UAAU;AAOzE,UAAM,OAAO,CAAC,YAAY,IAAI,SAAS,MAAM,EAAE,KAAK,GAAG,GAAG;AAAA,MACxD,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AA5FM;AAEA;AA6FP,SAAK,YAAY;AAGjB,SAAK,gBAAgB;AAKrB,SAAK,SAAS,MAAM,UAAU,MAAM,MAAM;AAG1C,SAAK,uBAAuB,MAAM;AAClC,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,uBAAuB;AAC5B,SAAK,aAAa;AAClB,SAAK,kBAAkB;AACvB,SAAK,aAAa;AAClB,SAAK,YAAY;AAWjB,SAAK,KAAK;AAAA,MACR,8BAA8B,OAAO,WAAW,MAAM;AAAA,MACtD,CAAC,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK,GAAG,MAAM,GAAG;AAAA,IAC3C;AAIA,SAAK,GAAG,IAAI,EAAE;AAAA,MACZ,aAAa,SAAS,2BAA2B;AAAA,MACjD,SAAS,MAAM,GAAG,GAAG;AAAA,IACvB;AACA,SAAK,GAAG,IAAI,EAAE;AAAA,MACZ,aAAa,SAAS,6BAA6B;AAAA,MACnD,WAAW,MAAM,GAAG,GAAG;AAAA,IACzB;AACA,SAAK,GAAG,IAAI,EAAE;AAAA,MACZ,aAAa,SAAS,8BAA8B;AAAA,MACpD,GAAG,MAAM,GAAG,GAAG;AAAA,IACjB;AACA,SAAK,GAAG,IAAI,EAAE;AAAA,MACZ,aAAa,SAAS,4BAA4B;AAAA,MAClD,MAAM,QAAQ,UAAU,MAAM,GAAG,GAAG;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,kBAA0B;AACnC,WAAO,UAAU,KAAK,UAAU,EAAE,MAAM,GAAG,GAAG;AAAA,EAChD;AACF;;;ACvUA;AAAA,EACE;AAAA,OAEK;AACP,SAAS,uBAAuB;AAOzB,IAAM,2BAAN,MAAM,iCAAgC,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,EAUvD,OAAc,mBAA2B;AACvC,WACE,MACA,CAAC,UAAU,yBAAwB,cAAc,EAAE,KAAK,GAAG,EAAE,YAAY;AAAA,EAE7E;AAAA,EAEA,YAAY,OAAkB,OAAyB;AACrD,UAAM,OAAO,6BAA6B,EAAE,GAAG,MAAM,CAAC;AAKtD,QAAI,gBAAgB,MAAM,uBAAuB;AAAA,MAC/C,eAAe,yBAAwB,iBAAiB;AAAA,MACxD,aAAa,KAAK;AAAA,IACpB,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AA5Ba,yBAIY,iBAAiB;AAJnC,IAAM,0BAAN;;;ACXP,SAAS,eAA6B;AAU/B,IAAM,cAAN,cAA0B,QAAQ;AAAA,EAMvC,YAAY,OAAkB,QAA0B,CAAC,GAAG;AAC1D,UAAM,QAAQ,cAAc,GAAG,KAAK;AAEpC,UAAM,UAAU,MAAM,eAAe;AACrC,QAAI,SAAS,QAAQ;AACnB,YAAM,oBAAoB,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,CAAC;AAC/D,UAAI,kBAAkB,SAAS,GAAG;AAChC,cAAM,IAAI;AAAA,UACR,wNAAwN,kBAAkB,KAAK,IAAI,CAAC;AAAA,QACtP;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,YAAY;AAAA;AAAA;AAAA;AAAA,MAIvB,GAAG;AAAA;AAAA;AAAA;AAAA,MAKH,SAAS,CAAC,QAAQ,QAAQ,OAAO,MAAM,UAAU,EAAE,KAAK,GAAG;AAAA,IAC7D,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AA/Ba,YAIY,iBAAiB;;;ACd1C;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,iBAAiB,aAAa,kBAAkB;;;ACNzD,SAAS,QAAAC,aAAY;AACrB;AAAA,EACE,mBAAAC;AAAA,OAEK;AAiEA,IAAM,+BAAN,MAAM,qCAAoCC,iBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA,EAY/D,OAAc,mBACZ,OACA,OACQ;AACR,UAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,WACE,MACA;AAAA,MACE,6BAA4B;AAAA,MAC5B,MAAM,cAAc,MAAM;AAAA,MAC1B,MAAM,eAAe,MAAM;AAAA,MAC3B,MAAM,WAAW,MAAM;AAAA,MACvB,MAAM,UAAU,MAAM;AAAA,MACtB,MAAM;AAAA,IACR,EACG,KAAK,GAAG,EACR,YAAY;AAAA,EAEnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAc,mBACZ,OACA,OACQ;AACR,UAAM,YAAY,6BAA4B;AAAA,MAC5C;AAAA,MACA;AAAA,IACF;AACA,WAAOA,iBAAgB,wBAAwB,OAAO,SAAS;AAAA,EACjE;AAAA,EAEA,YACE,OACA,IACA,OACA;AACA,UAAM,EAAE,cAAc,YAAY,aAAa,SAAS,QAAQ,GAAG,KAAK,IACtE;AAEF,UAAM,gBAAgB,6BAA4B;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,MAAM,6BAA4B,SAAS;AAAA,MAC3D,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AAED,UAAM,EAAE,QAAQ,IAAI,cAAc,GAAG,KAAK;AAC1C,IAAAC,MAAK,GAAG,IAAI,EAAE,IAAI,GAAG,OAAO,eAAe,YAAY;AAAA,EACzD;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AApEa,6BAMY,UAAU;AAN5B,IAAM,8BAAN;;;ADpDA,IAAM,kBAAN,MAAM,wBAAuB,WAAW;AAAA,EAM7C,OAAc,cAAc,OAA+B;AACzD,UAAM,eAAe,4BAA4B,mBAAmB,OAAO;AAAA,MACzE,cAAc,gBAAe;AAAA,MAC7B,aAAa;AAAA,IACf,CAAC;AAED,WAAO,WAAW,yBAAyB,OAAO,oBAAoB;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,OAAkB,OAA2C;AACvE,UAAM,QAAQ,cAAc,GAAG,KAAK;AAEpC,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO;AAAA,MACL,IAAI,WAAW,SAAS;AAAA,QACtB,YAAY,EAAE,YAAY,YAAY,OAAO,EAAE;AAAA,MACjD,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,oBAAoB;AAAA;AAAA;AAAA;AAAA,MAI/B,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,YAAY,WAAW,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA,MAKxC,GAAG;AAAA;AAAA;AAAA;AAAA,MAKH,MAAM,CAAC,QAAQ,WAAW,OAAO,MAAM,UAAU,EAAE,KAAK,GAAG;AAAA,IAC7D,CAAC;AAKD,QAAI,4BAA4B,MAAM,qBAAqB;AAAA,MACzD,cAAc,gBAAe;AAAA,MAC7B,aAAa;AAAA,MACb,aAAa,KAAK;AAAA,IACpB,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AAvDa,gBAIY,iBAAiB;AAJnC,IAAM,iBAAN;;;AEjBP,SAAS,gBAAgB;AACzB;AAAA,EAEE;AAAA,OAEK;AAoCA,IAAM,6BAAN,cAAyC,eAAe;AAAA,EAS7D,YAAY,OAAkB,OAAwC;AACpE,UAAM,EAAE,UAAU,GAAG,KAAK,IAAI;AAC9B,UAAM,OAAO,yBAAyB;AAAA,MACpC;AAAA,MACA,gBAAgB;AAAA,MAChB,WAAW;AAAA,QACT,cAAc;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,cAAc;AAAA;AAAA;AAAA;AAAA,MAId,qBAAqB,SAAS,MAAM,CAAC;AAAA,MACrC,iBAAiB,SAAS,MAAM,CAAC;AAAA,MACjC,sBAAsB,SAAS,KAAK,CAAC;AAAA,MACrC,4BAA4B;AAAA,MAC5B,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAlCa,2BAOY,iBAAiB;;;AChD1C;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AAQA,IAAM,kBAAN,cAA8B,SAAS;AAAA,EAM5C,YAAY,OAAkB,QAAuB,CAAC,GAAG;AACvD,UAAM,UAAU,cAAc,GAAG,KAAK;AAEtC,UAAM,OAAO,aAAa;AAAA;AAAA;AAAA;AAAA,MAIxB,mBAAmB;AAAA,MACnB,eAAe;AAAA,QACb,OAAO;AAAA,MACT;AAAA,MACA,kBAAkB;AAAA,QAChB,cAAc;AAAA,QACd,WAAW;AAAA,QACX,YAAY,uBAAuB;AAAA,MACrC;AAAA,MACA,eAAe,MAAM,iBAAiB,QAAQ;AAAA;AAAA;AAAA;AAAA,MAI9C,aAAa,YAAY;AAAA;AAAA;AAAA;AAAA,MAKzB,GAAG;AAAA;AAAA;AAAA;AAAA,MAKH,cAAc,CAAC,WAAW,QAAQ,QAAQ,QAAQ,UAAU,EAAE,KAAK,GAAG;AAAA,IACxE,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AAvCa,gBAIY,iBAAiB;;;ACjB1C,SAAS,kBAAAC,uBAA2C;AAO7C,IAAM,wBAAN,cAAoCA,gBAAe;AAAA,EAMxD,YAAY,OAAkB,OAA4B;AACxD,UAAM,OAAO,oBAAoB;AAAA;AAAA;AAAA;AAAA,MAI/B,gBAAgB;AAAA,MAChB,OAAO;AAAA,QACL,OAAO;AAAA,UACL,wBAAwB;AAAA,UACxB,mBAAmB;AAAA,QACrB;AAAA,QACA,cAAc,CAAC,uCAAuC;AAAA,MACxD;AAAA;AAAA;AAAA;AAAA,MAKA,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AA1Ba,sBAIY,iBAAiB;;;ACX1C,SAAS,sBAA2C;AAO7C,IAAM,wBAAN,cAAoC,eAAe;AAAA,EAMxD,YAAY,OAAkB,OAA4B;AAMxD,UAAM,KAAK,MAAM,eAAe,eAC5B,mBACA;AAEJ,UAAM,OAAO,IAAI;AAAA,MACf,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AApBa,sBAIY,iBAAiB;;;ACX1C,SAAS,WAAqB;AAQvB,IAAM,wBAAN,cAAoC,IAAI;AAAA,EAM7C,YAAY,OAAkB,QAAkB,CAAC,GAAG;AAClD,UAAM,UAAU,cAAc,GAAG,KAAK;AAEtC,UAAM,OAAO,WAAW;AAAA,MACtB,GAAG;AAAA;AAAA,MAEH,aAAa,mCAAmC,QAAQ,UAAU;AAAA,MAClE,eAAe,MAAM,iBAAiB,QAAQ;AAAA,IAChD,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AAhBa,sBAIY,iBAAiB;;;ACZ1C,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAM1B,IAAM,eAAe;AAKrB,SAAS,oBAAoB,SAAyB;AACpD,QAAM,UAAU,KAAK,KAAK,SAAS,YAAY;AAC/C,MAAI,GAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,KAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAO,YAAY;AACxE,SAAO;AACT;AAKO,IAAM,2BAAN,cAAuC,UAAU;AAAA,EAGtD,YAAY,OAAkB;AAC5B,UAAM,OAAO,4BAA4B;AAEzC,SAAK,SAAS,IAAI,eAAe,MAAM,WAAW;AAAA,MAChD,OAAO,oBAAoB,SAAS;AAAA,MACpC,SAAS,QAAQ;AAAA,MACjB,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AACF;;;ACxCA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,aAAAC,kBAAiB;AAM1B,IAAMC,gBAAe;AAKrB,IAAMC,uBAAsB,CAAC,YAA4B;AACvD,QAAM,UAAUL,MAAK,KAAK,SAASI,aAAY;AAC/C,MAAIL,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAOC,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAOI,aAAY;AACjE;AAcO,IAAM,yBAAN,cAAqCD,WAAU;AAAA,EAGpD,YAAY,OAAkB,OAAoC;AAChE,UAAM,OAAO,0BAA0B;AAEvC,SAAK,SAAS,IAAID,gBAAe,MAAM,WAAW;AAAA,MAChD,OAAOG,qBAAoB,SAAS;AAAA,MACpC,SAASJ,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,QACX,wBAAwB,MAAM;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACnDA,OAAOK,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,aAAAC,kBAAiB;AAM1B,IAAMC,gBAAe;AAKrB,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUL,MAAK,KAAK,SAASI,aAAY;AAC/C,MAAIL,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,UAAUC,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAOI,aAAY;AACxE,SAAO;AACT;AAiBO,IAAM,2BAAN,cAAuCD,WAAU;AAAA,EAGtD,YAAY,OAAkB,OAAsC;AAClE,UAAM,OAAO,6BAA6B;AAE1C,SAAK,SAAS,IAAID,gBAAe,MAAM,WAAW;AAAA,MAChD,OAAOG,qBAAoB,SAAS;AAAA,MACpC,SAASJ,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,QACX,mBAAmB,MAAM;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACvDA,OAAOK,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,YAAAC,WAAU,iBAAAC,gBAAe,YAAY;AAG9C,YAAY,qBAAqB;AACjC,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,YAAY,QAAQ;AACpB,SAAS,aAAAC,kBAAiB;AAE1B,IAAMC,gBAAe;AAErB,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUP,MAAK,KAAK,SAASM,aAAY;AAC/C,MAAIP,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,SAAOC,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAOM,aAAY;AACjE;AA4BO,IAAM,6BAAN,cAAyCD,WAAU;AAAA,EAUxD,YACE,OACA,IACA,OACA;AACA,UAAM,OAAO,EAAE;AAEf,SAAK,gBAAgB,IAAO,UAAO,MAAM,iBAAiB;AAAA,MACxD,mBAAsB,qBAAkB;AAAA,MACxC,YAAe,oBAAiB;AAAA,MAChC,YAAY;AAAA,MACZ,eAAe,MAAM;AAAA,MACrB,mBAAmB,MAAM,kBAAkBH,eAAc;AAAA,MACzD,WAAW;AAAA,IACb,CAAC;AAED,UAAM,4BAA4B,MAAM,eACpC,IAAO,UAAO,MAAM,uBAAuB;AAAA,MACzC,mBAAsB,qBAAkB;AAAA,MACxC,YAAe,oBAAiB;AAAA,MAChC,YAAY;AAAA,MACZ,eAAe,MAAM;AAAA,MACrB,mBAAmB,MAAM,kBAAkBA,eAAc;AAAA,MACzD,WAAW;AAAA,IACb,CAAC,IACD;AACJ,SAAK,4BAA4B;AAEjC,SAAK,oBAAoB,IAAIE,gBAAe,MAAM,qBAAqB;AAAA,MACrE,OAAOG,qBAAoB,SAAS;AAAA,MACpC,SAASJ,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASF,UAAS,QAAQ,CAAC;AAAA,MAC3B,aACE;AAAA,MACF,aACE,MAAM,gBAAgB,4BAClB;AAAA,QACE,qBAAqB,MAAM,aAAa;AAAA,QACxC,kCACE,0BAA0B;AAAA,MAC9B,IACA;AAAA,MACN,UAAU;AAAA,QACR,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAED,UAAM,cAAc,iBAAiB,KAAK,iBAAiB;AAC3D,+BAA2B,SAAS,KAAK,iBAAiB;AAE1D,UAAM,YAAY,IAAoB;AAAA,MACpC,KAAK;AAAA,MACL;AAAA,QACE,gBAAgBA,UAAS,QAAQ,EAAE;AAAA,QACnC,YAAY,KAAK,UAAU,CAAC;AAAA,QAC5B,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,cAAc,IAAoB,yBAAS,KAAK,eAAe;AAAA,MACnE,aAA6B,4BAAY;AAAA,MACzC,mBAAmBA,UAAS,QAAQ,GAAG;AAAA;AAAA,MAEvC,eAAe,KAAK,UAAU,EAAE;AAAA,MAChC,YAAY,CAAC,SAAS;AAAA,MACtB,mBACE;AAAA,MACF,eAAe,IAAoB,8BAAc;AAAA,IACnD,CAAC;AAED,SAAK,iBAAiB,IAAoB;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,QACE,oBAAoB,sBAAsB,MAAM,SAAS;AAAA,QACzD,QAAQ,IAAoB,oCAAoB,MAAM,aAAa;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,KAAK,eAAe,KAC7B;AACH,QAAI;AAAA,MACF;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,cAAc,EAAE,mBAAmB,IAAI;AAAA,MACzC;AAAA,IACF;AACA,QAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;ACxJA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAYA,SAAS,8BAA8B,OAA0B;AACtE,QAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,SAAO,cAAc,MAAM,UAAU;AACvC;AAqCO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACE,OACA,IACA,QAAgC,CAAC,GACjC;AACA,UAAM,UAAU,cAAc,GAAG,KAAK;AAEtC,UAAM,OAAO,IAAI;AAAA,MACf,GAAG;AAAA,MACH,WAAW,8BAA8B,KAAK;AAAA,MAC9C,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,MACtB;AAAA,MACA,aAAa,YAAY;AAAA,MACzB,eAAe,MAAM,iBAAiB,QAAQ;AAAA,IAChD,CAAC;AAGD,SAAK,wBAAwB;AAAA,MAC3B,WAAW;AAAA,MACX,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,MACtB;AAAA,MACA,gBAAgB,eAAe;AAAA,MAC/B,kBAAkB;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,wBAAwB;AAAA,MAC3B,WAAW;AAAA,MACX,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,MACtB;AAAA,MACA,gBAAgB,eAAe;AAAA,MAC/B,kBAAkB;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACzIA,IAAAO,oBAGO;AACP,SAAS,mBAAkC;AAC3C,SAAS,iBAAAC,gBAAe,eAAAC,cAAa,SAAAC,cAAa;AAClD,SAAS,QAAQ,uBAAuB;AAExC,SAAS,aAAAC,kBAAiB;AAYnB,SAAS,0BAA0B,OAA0B;AAClE,QAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,SAAO,kBAAkB,MAAM,UAAU;AAC3C;AAkCO,IAAM,sBAAN,MAAM,4BAA2BC,WAAU;AAAA,EAiHhD,YACE,OACA,IACA,QAAiC,CAAC,GAClC;AACA,UAAM,OAAO,EAAE;AAPjB,SAAiB,sBAAsB,oBAAI,IAAY;AASrD,UAAM,UAAU,cAAc,GAAG,KAAK;AAStC,UAAM,SAAS,QAAQ,KACpB,QAAQ,EACR;AAAA,MACC,CAAC,MACC,aAAa,uBAAsB,MAAM;AAAA,IAC7C;AACF,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI;AAAA,QACR,wCAAwC,OAAO,CAAC,EAAE,KAAK,IAAI;AAAA,MAE7D;AAAA,IACF;AAEA,SAAK,QAAQ,IAAIC,OAAM,MAAM,SAAS;AAAA,MACpC,WAAW,0BAA0B,KAAK;AAAA,MAC1C,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,MAAMC,eAAc;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,MAAMA,eAAc;AAAA,MACtB;AAAA,MACA,aAAaC,aAAY;AAAA,MACzB,qBAAqB;AAAA,MACrB,eAAe,MAAM,iBAAiB,QAAQ;AAAA,IAChD,CAAC;AAID,QAAI,4BAA4B,MAAM,oBAAoB;AAAA,MACxD,cAAc,oBAAmB;AAAA,MACjC,aAAa,KAAK,MAAM;AAAA,IAC1B,CAAC;AACD,QAAI,4BAA4B,MAAM,mBAAmB;AAAA,MACvD,cAAc,oBAAmB;AAAA,MACjC,aAAa,KAAK,MAAM;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA;AAAA,EA/JA,OAAc,oBAAoB,OAA0B;AAC1D,WAAO,4BAA4B,mBAAmB,OAAO;AAAA,MAC3D,cAAc,oBAAmB;AAAA,MACjC,aAAa,oBAAmB;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,OAAc,mBAAmB,OAA0B;AACzD,WAAO,4BAA4B,mBAAmB,OAAO;AAAA,MAC3D,cAAc,oBAAmB;AAAA,MACjC,aAAa,oBAAmB;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,OAAc,wBACZ,OACA,IACA,cACA,UAAgC,CAAC,GAC3B;AACN,wBAAmB,yBAAyB,YAAY;AACxD,UAAM,YAAY,oBAAmB,oBAAoB,KAAK;AAC9D,UAAM,WAAW,oBAAmB,mBAAmB,KAAK;AAE5D,OAAG,eAAe,qDAAmC,SAAS;AAC9D,QAAI,QAAQ,sBAAsB,QAAW;AAC3C,SAAG;AAAA,QACD;AAAA,QACA,OAAO,QAAQ,iBAAiB;AAAA,MAClC;AAAA,IACF;AAEA,OAAG;AAAA,MACD,IAAI,gBAAgB;AAAA,QAClB,QAAQ,OAAO;AAAA,QACf,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,WAAW,CAAC,QAAQ;AAAA,QACpB,YAAY;AAAA,UACV,6BAA6B;AAAA,YAC3B,wBAAwB,CAAC,YAAY;AAAA,UACvC;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,OAAe,yBAAyB,cAA4B;AAClE,QAAI,aAAa,WAAW,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,SAAS,2DAAyC;AACjE,YAAM,IAAI;AAAA,QACR,gCAAgC,yDAAuC,eAAe,aAAa,MAAM;AAAA,MAC3G;AAAA,IACF;AACA,QAAI,KAAK,KAAK,YAAY,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqEO,cACL,IACA,cACA,UAAgC,CAAC,GAC3B;AACN,SAAK,mBAAmB,YAAY;AAEpC,QAAI,KAAK,oBAAoB,IAAI,YAAY,GAAG;AAC9C,kBAAY,GAAG,IAAI,EAAE;AAAA,QACnB,qCAAqC,YAAY;AAAA,MAEnD;AAAA,IACF;AACA,SAAK,oBAAoB,IAAI,YAAY;AAEzC,OAAG,eAAe,qDAAmC,KAAK,MAAM,SAAS;AACzE,QAAI,QAAQ,sBAAsB,QAAW;AAC3C,SAAG;AAAA,QACD;AAAA,QACA,OAAO,QAAQ,iBAAiB;AAAA,MAClC;AAAA,IACF;AAEA,OAAG;AAAA,MACD,IAAI,gBAAgB;AAAA,QAClB,QAAQ,OAAO;AAAA,QACf,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,WAAW,CAAC,KAAK,MAAM,QAAQ;AAAA,QAC/B,YAAY;AAAA,UACV,6BAA6B;AAAA,YAC3B,wBAAwB,CAAC,YAAY;AAAA,UACvC;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,mBAAmB,cAA4B;AACrD,wBAAmB,yBAAyB,YAAY;AAAA,EAC1D;AACF;AAAA;AA5Na,oBAEY,4BACrB;AAAA;AAHS,oBAKY,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AALvC,oBAmFa,yBAA4C;AAnF/D,IAAM,qBAAN;AA+NA,IAAM,mCAAN,cAA+C,MAAM;AAAA;AAAA,EAE1D,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,wCAAN,cAAoD,MAAM;AAAA;AAAA,EAE/D,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ACvSA,SAAS,gBAA+B;AAQjC,IAAM,eAAN,MAAM,sBAAqB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzC,OAAc,gBAAgB,OAA0B;AACtD,UAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,WAAO,SAAS,MAAM,UAAU;AAAA,EAClC;AAAA,EAEA,YAAY,OAAkB,OAAuB;AACnD,UAAM,OAAO,qBAAqB;AAAA,MAChC,GAAG;AAAA,MACH,cAAc,cAAa,gBAAgB,KAAK;AAAA,IAClD,CAAC;AAAA,EACH;AACF;;;AC5BA,SAAS,YAAAC,iBAA+B;AAQjC,IAAM,cAAN,MAAM,qBAAoBC,UAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASxC,OAAc,gBAAgB,OAA0B;AACtD,UAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,WAAO,QAAQ,MAAM,UAAU;AAAA,EACjC;AAAA,EAEA,YAAY,OAAkB,OAAuB;AACnD,UAAM,OAAO,oBAAoB;AAAA,MAC/B,GAAG;AAAA,MACH,cAAc,aAAY,gBAAgB,KAAK;AAAA,IACjD,CAAC;AAAA,EACH;AACF;;;AC5BA,SAAS,YAAAC,iBAA+B;AAQjC,IAAM,kBAAN,MAAM,yBAAwBC,UAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS5C,OAAc,gBAAgB,OAA0B;AACtD,UAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,WAAO,YAAY,MAAM,UAAU;AAAA,EACrC;AAAA,EAEA,YAAY,OAAkB,OAAuB;AACnD,UAAM,OAAO,wBAAwB;AAAA,MACnC,GAAG;AAAA,MACH,cAAc,iBAAgB,gBAAgB,KAAK;AAAA,IACrD,CAAC;AAAA,EACH;AACF;;;AC5BA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,YAAAC,WAAyB,SAAAC,cAAa;AAC/C,YAAY,SAAS;AAErB,SAAS,WAAAC,UAAS,wBAAwB;AAC1C,SAAS,0BAA0B;AACnC,SAAS,kBAAAC,uBAAsB;AAC/B,YAAY,SAAS;AACrB,SAAS,aAAAC,kBAAiB;AAG1B,IAAMC,gBAAe;AACrB,IAAM,wBAAwB;AAC9B,IAAM,sBAAsB;AASrB,IAAM,wCACX;AACK,IAAM,uCACX;AACK,IAAM,0CACX;AAEF,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUC,MAAK,KAAK,SAASF,aAAY;AAC/C,MAAIG,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,SAAOD,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAOF,aAAY;AACjE;AAQO,SAAS,6BAA6B,YAA4B;AACvE,QAAM,YAAY,KAAK,WAAW,YAAY,CAAC;AAC/C,MAAI,CAAC,oBAAoB,KAAK,SAAS,GAAG;AACxC,UAAM,IAAI;AAAA,MACR,eAAe,KAAK,UAAU,UAAU,CAAC,6CACxB,KAAK,UAAU,SAAS,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,SAAO;AACT;AA2DO,IAAM,2BAAN,cAAuCI,WAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMtD,OAAc,wBAAwB,OAA0B;AAC9D,WAAO,4BAA4B,mBAAmB,OAAO;AAAA,MAC3D,cAAc;AAAA,MACd,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAc,uBAAuB,OAA0B;AAC7D,WAAO,4BAA4B,mBAAmB,OAAO;AAAA,MAC3D,cAAc;AAAA,MACd,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAc,0BAA0B,OAA0B;AAChE,WAAO,4BAA4B,mBAAmB,OAAO;AAAA,MAC3D,cAAc;AAAA,MACd,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAQA,YACE,OACA,IACA,OACA;AACA,UAAM,OAAO,EAAE;AAEf,SAAK,eAAe,MAAM,gBAAgB;AAC1C,SAAK,aAAa,6BAA6B,MAAM,UAAU;AAQ/D,UAAM,SAASC,OAAM,GAAG,IAAI,EAAE;AAC9B,SAAK,MACH,MAAM,OACN,IAAQ,QAAI,MAAM,OAAO;AAAA,MACvB,mBAAmB,CAAC,GAAG,MAAM,KAAK,GAAG,MAAM,GAAG;AAAA,MAC9C,aAAa;AAAA,MACb,qBAAqB;AAAA,QACnB;AAAA,UACE,MAAM;AAAA,UACN,YAAgB,eAAW;AAAA,UAC3B,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF,CAAC;AAEH,SAAK,UAAU,IAAQ,oBAAgB,MAAM,WAAW;AAAA,MACtD,mBAAmB,oBAAoB,MAAM,SAAS;AAAA,MACtD,QAAY,0BAAsB,eAAe;AAAA,QAC/C,SAAa,gCAA4B;AAAA,MAC3C,CAAC;AAAA,MACD,KAAK,KAAK;AAAA,MACV,YAAY,EAAE,YAAgB,eAAW,iBAAiB;AAAA,MAC1D,QAAY,oBAAgB,aAAa,QAAQ;AAAA,MACjD,yBAAyB,MAAM,eAAe;AAAA,MAC9C,yBAAyB,MAAM,eAAe;AAAA,MAC9C,qBAAqB,KAAK;AAAA,MAC1B,aAAiB,gBAAY,oBAAoB,cAAc;AAAA,MAC/D,kBAAkB;AAAA,MAClB,eAAe,MAAM;AAAA;AAAA;AAAA;AAAA,MAIrB,eAAe;AAAA,IACjB,CAAC;AAED,SAAK,wBAAwB;AAE7B,SAAK,sBAAsB,IAAIC,gBAAe,MAAM,uBAAuB;AAAA,MACzE,OAAOL,qBAAoB,SAAS;AAAA,MACpC,SAASM,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,UAAS,QAAQ,CAAC;AAAA,MAC3B,KAAK,KAAK;AAAA,MACV,YAAY,EAAE,YAAgB,eAAW,iBAAiB;AAAA,MAC1D,aACE;AAAA,MACF,aAAa;AAAA,QACX,gBAAgB,KAAK,QAAQ,gBAAgB;AAAA,QAC7C,gBAAgB,KAAK,QAAQ,gBAAgB,KAAK,SAAS;AAAA,QAC3D,oBAAoB,KAAK;AAAA,QACzB,kBAAkB,KAAK;AAAA,QACvB,sBAAsB,KAAK,QAAQ,OAAQ;AAAA,QAC3C,eAAe;AAAA,MACjB;AAAA,MACA,UAAU;AAAA,QACR,QAAQ;AAAA,QACR,WAAW;AAAA;AAAA;AAAA;AAAA,QAIX,aAAa,CAAC,IAAI;AAAA,MACpB;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,OAAQ,UAAU,KAAK,mBAAmB;AACvD,SAAK,QAAQ,YAAY,qBAAqB,KAAK,mBAAmB;AAEtE,SAAK,oBAAoB;AAAA,MACvB,IAAI,mBAAmB,MAAM,eAAe;AAAA,QAC1C,kBAAkB,iBAAiB;AAAA,QACnC,WAAW;AAAA,QACX,mBAAmBA,UAAS,QAAQ,CAAC;AAAA,QACrC,eAAe;AAAA,QACf,oBAAoB;AAAA,QACpB,uBAAuB;AAAA,QACvB,yBAAyB;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,0BAAgC;AACtC,QAAI,4BAA4B,MAAM,qBAAqB;AAAA,MACzD,cAAc;AAAA,MACd,aAAa,KAAK,QAAQ;AAAA,MAC1B,aACE;AAAA,IACJ,CAAC;AACD,QAAI,4BAA4B,MAAM,oBAAoB;AAAA,MACxD,cAAc;AAAA,MACd,aAAa,KAAK,QAAQ,OAAQ;AAAA,MAClC,aACE;AAAA,IACJ,CAAC;AACD,QAAI,4BAA4B,MAAM,uBAAuB;AAAA,MAC3D,cAAc;AAAA,MACd,aAAa,KAAK;AAAA,MAClB,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;;;AClRA,SAAS,YAAAC,iBAAgB;AACzB;AAAA,EACE;AAAA,EAGA;AAAA,OACK;AAcA,IAAM,kBAAN,cAA8B,WAAW;AAAA,EAM9C,YAAY,OAAkB,IAAY,OAA6B;AACrE,UAAM,OAAO,IAAI,EAAE,GAAG,MAAM,CAAC;AAK7B,QAAI,SAAS,MAAM,mBAAmB;AAAA,MACpC,MAAM,MAAM;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,QAAQ,KAAK,yBAAyB,CAAC;AAAA,MACvC,KAAKA,UAAS,QAAQ,CAAC;AAAA,IACzB,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AAnBa,gBAIY,iBAAiB;;;ACxB1C,SAAS,aAAAC,kBAAiB;AAWnB,IAAM,iBAAN,cAA6BA,WAAU;AAAC;;;ACX/C;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,sBAAsB;AAC/B,SAAS,UAAAC,eAA8C;AACvD,SAAS,YAAAC,iBAAgB;AACzB,SAAS,aAAAC,kBAAiB;AAQnB,IAAM,8BAA8B;AAiCpC,IAAM,iBAAN,MAAM,uBAAsBC,WAAU;AAAA,EAgB3C,YAAY,OAAkB,IAAY,QAA4B,CAAC,GAAG;AACxE,UAAM,OAAO,EAAE;AAEf,UAAM,QAAQ,cAAc,GAAG,KAAK;AACpC,UAAM,cAAc,MAAM,eAAe;AAEzC,SAAK,SAAS,IAAIC,QAAO,MAAM,UAAU;AAAA,MACvC,mBAAmB;AAAA,QACjB,iBAAiB;AAAA,QACjB,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,uBAAuB;AAAA,MACzB;AAAA,MACA,GAAG,MAAM;AAAA,IACX,CAAC;AAED,UAAM,SAAS,eAAe,wBAAwB,KAAK,MAAM;AAEjE,UAAM,cAAc,IAAI,YAAY,MAAM,gBAAgB;AAAA,MACxD,iBAAiB,sBAAsB,MAAM,UAAU;AAAA,MACvD,SAAS;AAAA,MACT,YAAYC,UAAS,QAAQ,EAAE;AAAA,MAC/B,QAAQA,UAAS,QAAQ,CAAC;AAAA,MAC1B,QAAQA,UAAS,QAAQ,EAAE;AAAA,IAC7B,CAAC;AAED,SAAK,eAAe,IAAI,aAAa,MAAM,gBAAgB;AAAA,MACzD,iBAAiB;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAAA,MACA,GAAG,MAAM;AAAA,IACX,CAAC;AAED,QAAI,4BAA4B,MAAM,oBAAoB;AAAA,MACxD,cAAc,eAAc;AAAA,MAC5B;AAAA,MACA,aAAa,KAAK,OAAO;AAAA,IAC3B,CAAC;AAED,QAAI,4BAA4B,MAAM,0BAA0B;AAAA,MAC9D,cAAc,eAAc;AAAA,MAC5B;AAAA,MACA,aAAa,KAAK,aAAa;AAAA,IACjC,CAAC;AAAA,EACH;AACF;AAAA;AAAA;AAAA;AA9Da,eAIY,4BACrB;AAAA;AAAA;AAAA;AALS,eAUY,kCACrB;AAXG,IAAM,gBAAN;;;ACjDP,IAAAC,iBAA8B;AAC9B;AAAA,EAIE;AAAA,EACA,YAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAe,OAAAC,YAAW;AAE1B,SAAS,SAAAC,cAAa;;;AChBtB,IAAAC,iBAA8B;AAC9B,SAAS,gBAAwB,SAAAC,cAAa;AAE9C,YAAY,aAAa;;;ACHzB;AAAA,EACE,eAAAC;AAAA,EACA;AAAA,OAEK;AACP,SAAS,YAAAC,iBAA2B;AACpC;AAAA,EACE,cAAAC;AAAA,OAGK;AACP,SAAS,mBAAAC,wBAAuB;;;ACVhC,SAAS,aAAAC,mBAAiB;;;ACD1B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,YAAAC,WAAU,SAAAC,cAAa;AAChC,SAAoB,YAAY;AAChC,SAAS,sBAAsB;AAC/B,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,aAAAC,kBAAiB;AAmB1B,IAAMC,gBAAe;AAKrB,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUC,MAAK,KAAK,SAASF,aAAY;AAC/C,MAAIG,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,SAAOD,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,OAAOF,aAAY;AACvE;AAqBO,IAAM,6BAAN,cAAyCI,WAAU;AAAA,EAIxD,YAAY,OAAkB,OAAwC;AACpE,UAAM,OAAO,+BAA+B;AAI5C,UAAM,UAAU,cAAc,GAAG,IAAI;AACrC,UAAM,aAAa;AAAA,MACjB,QAAQ;AAAA,MACR;AAAA,IACF;AACA,UAAM,eAAe,GAAG,QAAQ,OAAO;AAUvC,UAAM,eAAeC,OAAM,GAAG,IAAI,EAAE;AACpC,UAAM,YAAY,IAAI,QAAQ,SAAS,IAAIA,OAAM,GAAG,IAAI,EAAE,OAAO,IAC/DA,OAAM,GAAG,IAAI,EAAE,MACjB;AACA,UAAM,eAAe,aAAa,SAAS,SAAS,IAChD,aAAa,MAAM,GAAG,CAAC,UAAU,MAAM,IACvC,QAAQ;AACZ,UAAM,gBAAgB,0BAA0BA,OAAM,GAAG,IAAI,EAAE,MAAM,IACnEA,OAAM,GAAG,IAAI,EAAE,OACjB,UAAU,YAAY;AAEtB,SAAK,SAAS,IAAIC,gBAAe,MAAM,WAAW;AAAA,MAChD,OAAOL,qBAAoB,SAAS;AAAA,MACpC,SAASM,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,UAAS,QAAQ,EAAE;AAAA,MAC5B,aAAa;AAAA,QACX,CAAC,8BAA8B,GAAG,MAAM,gBAAgB;AAAA,QACxD,CAAC,2BAA2B,GAAG;AAAA,QAC/B,CAAC,6BAA6B,GAAG;AAAA,MACnC;AAAA,IACF,CAAC;AAID,SAAK,OAAO;AAAA,MACV,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,+BAA+B;AAAA,QACzC,WAAW;AAAA,UACT,0BAA0BL,OAAM,GAAG,IAAI,EAAE,MAAM,IAC7CA,OAAM,GAAG,IAAI,EAAE,OACjB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,gBAAgB,iBAAiB,KAAK,MAAM;AAUlD,SAAK,OAAO,IAAI,KAAK,MAAM,QAAQ;AAAA,MACjC,cAAc;AAAA,QACZ,QAAQ,CAAC,2BAA2B;AAAA,QACpC,YAAY,CAAC,8CAA8C;AAAA,QAC3D,QAAQ;AAAA,UACN,YAAY,CAAC,EAAE,QAAQ,cAAc,CAAC;AAAA,UACtC,kBAAkB;AAAA,YAChB,QAAQ,CAAC,GAAG,gBAAgB;AAAA,UAC9B;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,IAAI,eAAe,KAAK,QAAQ;AAAA,UAC9B,eAAe;AAAA,UACf,aAAaG,UAAS,MAAM,CAAC;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AD/HO,IAAM,uBAAN,cAAmCG,YAAU;AAAA,EAGlD,YAAY,OAAkB,OAAkC;AAC9D,UAAM,OAAO,wBAAwB;AAErC,SAAK,eAAe,IAAI,2BAA2B,MAAM;AAAA,MACvD,iBAAiB,MAAM;AAAA,IACzB,CAAC;AAAA,EACH;AACF;;;ADOO,IAAM,uBAAN,MAAM,6BAA4B,cAAc;AAAA;AAAA;AAAA;AAAA,EAMrD,OAAO,4BACL,OACA,OACa;AACb,WAAOC,YAAW,yBAAyB,OAAO,aAAa,KAAK;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,qCAAqC,OAAgC;AAC1E,UAAM,iBAAiBC,iBAAgB;AAAA,MACrC;AAAA,MACA,wBAAwB,iBAAiB;AAAA,IAC3C;AACA,WAAOC,aAAY;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,6BACL,OACA,OACa;AACb,UAAM,eAAe,4BAA4B,mBAAmB,OAAO;AAAA,MACzE,cAAc,gBAAgB;AAAA,MAC9B,aAAa,MAAM,eAAe,qBAAoB;AAAA,IACxD,CAAC;AACD,WAAOF,YAAW,yBAAyB,OAAO,cAAc;AAAA,MAC9D;AAAA,MACA,UAAU,MAAM;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,0BAA0B,OAA6B;AAC5D,WAAOG,UAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA,aAAa,gBAAgB,KAAK;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,yBAAyB,OAA6B;AAC3D,WAAOA,UAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA,YAAY,gBAAgB,KAAK;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,6BAA6B,OAA6B;AAC/D,WAAOA,UAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA,gBAAgB,gBAAgB,KAAK;AAAA,IACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,iCAAiC,OAA0B;AAChE,WAAO,mBAAmB,oBAAoB,KAAK;AAAA,EACrD;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,qBAAoB;AAAA,EAC7B;AAAA,EAyCA,YAAY,OAA0B,QAAkC,CAAC,GAAG;AAC1E,UAAM,OAAO,qBAAoB,cAAc,KAAK;AACpD,SAAK,QAAQ;AAEb,SAAK,eAAe,KAAK;AAEzB,SAAK,iBAAiB,KAAK,qBAAqB;AAChD,SAAK,kBAAkB,KAAK,sBAAsB;AAClD,SAAK,0BAA0B,KAAK,8BAA8B;AAClE,SAAK,eAAe,KAAK,mBAAmB;AAC5C,SAAK,cAAc,KAAK,kBAAkB;AAC1C,SAAK,kBAAkB,KAAK,sBAAsB;AAClD,SAAK,qBAAqB,KAAK,yBAAyB;AACxD,SAAK,uBAAuB,KAAK,2BAA2B;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKU,eAAe,OAAuC;AAC9D,UAAM,EAAE,OAAO,IAAI;AACnB,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AACA,QAAI,CAAC,OAAO,cAAc;AACxB,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,uBAAoC;AAC5C,WAAO,qBAAoB,4BAA4B,MAAM;AAAA,MAC3D,UAAU,KAAK,OAAO;AAAA,MACtB,cAAc,KAAK,OAAO;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,wBAAiD;AACzD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,gCAA8C;AACtD,QAAI,KAAK,eAAe,QAAQ;AAC9B,aAAO,IAAI,wBAAwB,MAAM;AAAA,QACvC,YAAY,KAAK,KAAK,eAAe,QAAQ;AAAA,QAC7C,yBAAyB,CAAC,KAAK,eAAe,QAAQ;AAAA,QACtD,YAAY,sBAAsB,QAAQ,KAAK,cAAc;AAAA,MAC/D,CAAC;AAAA,IACH;AACA,WAAO,qBAAoB,qCAAqC,IAAI;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,qBAAgC;AACxC,WAAO,IAAI,aAAa,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,oBAA+B;AACvC,WAAO,IAAI,YAAY,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,wBAAmC;AAC3C,WAAO,IAAI,gBAAgB,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,6BAAmD;AAC3D,WAAO,IAAI,qBAAqB,MAAM;AAAA,MACpC,iBAAiB,KAAK;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,2BAA+C;AACvD,WAAO,IAAI,mBAAmB,MAAM,sBAAsB;AAAA,EAC5D;AACF;AApPa,qBACK,eAAe;AAD1B,IAAM,sBAAN;;;AGxCP,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,yBAAyB;AAClC,SAAS,YAAAC,WAAU,SAAAC,cAAa;AAGhC,SAAoB,QAAAC,aAAY;AAChC,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAc1B,IAAMC,gBAAe;AAOrB,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUC,MAAK,KAAK,SAASF,aAAY;AAC/C,MAAIG,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAOD,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,OAAOF,aAAY;AACvE;AAyCO,IAAM,qBAAN,cAAiCI,YAAU;AAAA,EAIhD,YAAY,OAAkB,OAAgC;AAC5D,UAAM,OAAO,uBAAuB;AAEpC,SAAK,SAAS,IAAIC,gBAAe,MAAM,WAAW;AAAA,MAChD,OAAOJ,qBAAoB,SAAS;AAAA,MACpC,SAASK,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,UAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,QACxC,CAAC,mCAAmC,GAAG,MAAM,SAAS;AAAA,MACxD;AAAA,IACF,CAAC;AAKD,UAAM,eAAe,OAAO,OAAO,iBAAiB,EAAE,IAAI,gBAAgB;AAC1E,SAAK,OAAO;AAAA,MACV,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,kBAAkB;AAAA,QAC5B,WAAW,CAAC,MAAM,eAAe,QAAQ;AAAA,QACzC,YAAY;AAAA,UACV,6BAA6B;AAAA,YAC3B,wBAAwB;AAAA,UAC1B;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAMA,UAAM,YAAsB;AAAA,MAC1B,GAAG,sBAAsB;AAAA,MACzB,GAAG,yBAAyB,SAAS;AAAA,IACvC;AACA,SAAK,OAAO;AAAA,MACV,IAAID,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,oBAAoB,qBAAqB;AAAA,QACnD,WAAW,CAAC,MAAM,eAAe,QAAQ;AAAA,QACzC,YAAY;AAAA,UACV,6BAA6B;AAAA,YAC3B,wBAAwB;AAAA,UAC1B;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAOA,SAAK,OAAO;AAAA,MACV,IAAID,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,WAAW;AAAA,UACTC,OAAM,GAAG,IAAI,EAAE,UAAU;AAAA,YACvB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,cAAc,MAAM,SAAS;AAAA,UAC/B,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,OAAO,IAAIC,MAAK,MAAM,QAAQ;AAAA,MACjC,UAAU,MAAM;AAAA,MAChB,cAAc;AAAA,QACZ,QAAQ,CAAC,4CAA2B,MAAM;AAAA,QAC1C,YAAY,CAAC,4CAA2B,UAAU;AAAA,MACpD;AAAA,MACA,SAAS;AAAA,QACP,IAAIC,gBAAe,KAAK,QAAQ;AAAA,UAC9B,eAAe;AAAA,UACf,aAAaL,UAAS,MAAM,CAAC;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AC1KA,SAAS,aAAAM,mBAAiB;AAsCnB,IAAM,uBAAN,cAAmCC,YAAU;AAAA,EAGlD,YAAY,OAAkB,OAAkC;AAC9D,UAAM,OAAO,yBAAyB;AAEtC,SAAK,eAAe,IAAI,mBAAmB,MAAM;AAAA,MAC/C,iBAAiB,MAAM;AAAA,MACvB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,IAClB,CAAC;AAMD,uBAAmB;AAAA,MACjB;AAAA,MACA,KAAK,aAAa;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;;;AC/DA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,qBAAAC,0BAAyB;AAClC,SAAS,YAAAC,WAAU,SAAAC,cAAa;AAEhC,SAAoB,QAAAC,aAAY;AAChC,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAU1B,IAAMC,gBAAe;AAOrB,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUC,MAAK,KAAK,SAASF,aAAY;AAC/C,MAAIG,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAOD,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,OAAOF,aAAY;AACvE;AA0BO,IAAM,uBAAN,cAAmCI,YAAU;AAAA,EAIlD,YAAY,OAAkB,OAAkC;AAC9D,UAAM,OAAO,yBAAyB;AAEtC,SAAK,SAAS,IAAIC,gBAAe,MAAM,WAAW;AAAA,MAChD,OAAOJ,qBAAoB,SAAS;AAAA,MACpC,SAASK,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,UAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,QACxC,CAAC,oCAAoC,GACnC,MAAM,gBAAgB;AAAA,MAC1B;AAAA,IACF,CAAC;AAiBD,UAAM,WAAW,OAAO,OAAOC,kBAAiB,EAAE;AAAA,MAChD,CAAC,OAAO,WAAW,EAAE;AAAA,IACvB;AACA,SAAK,OAAO;AAAA,MACV,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,oBAAoB,qBAAqB;AAAA,QACnD,WAAW,CAAC,MAAM,eAAe,QAAQ;AAAA,QACzC,YAAY;AAAA,UACV,6BAA6B;AAAA,YAC3B,wBAAwB;AAAA,UAC1B;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAQA,UAAM,gBAAgB,iBAAiB,KAAK,MAAM;AAclD,UAAM,gBAAgBC,OAAM,GAAG,IAAI,EAAE;AAErC,SAAK,OAAO,IAAIC,MAAK,MAAM,QAAQ;AAAA,MACjC,UAAU,MAAM;AAAA,MAChB,cAAc;AAAA,QACZ,QAAQ,CAAC,gDAA8B,MAAM;AAAA,QAC7C,YAAY,CAAC,gDAA8B,UAAU;AAAA,QACrD,QAAQ;AAAA,UACN,SAAS;AAAA,YACP,WAAW,CAAC,aAAa;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,IAAIC,gBAAe,KAAK,QAAQ;AAAA,UAC9B,eAAe;AAAA,UACf,aAAaN,UAAS,MAAM,CAAC;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACrJA,SAAS,aAAAO,mBAAiB;AA4BnB,IAAM,yBAAN,cAAqCC,YAAU;AAAA,EAGpD,YAAY,OAAkB,OAAoC;AAChE,UAAM,OAAO,2BAA2B;AAExC,SAAK,iBAAiB,IAAI,qBAAqB,MAAM;AAAA,MACnD,iBAAiB,MAAM;AAAA,MACvB,gBAAgB,MAAM;AAAA,IACxB,CAAC;AAMD,uBAAmB;AAAA,MACjB;AAAA,MACA,KAAK,eAAe;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACF;;;APhBO,IAAM,qBAAN,MAAM,2BAA0B,cAAc;AAAA,EA6EnD,YAAY,OAA0B,QAAgC,CAAC,GAAG;AACxE,UAAM,OAAO,mBAAkB,cAAc,KAAK;AAHpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,mBAAqC;AAI3C,SAAK,QAAQ;AAEb,SAAK,wBAAwB,IAAY;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,QACE,YAAY,qBAAqB,KAAK,UAAU;AAAA,QAChD,YAAoB,mBAAW;AAAA;AAAA;AAAA;AAAA,QAI/B,eAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAEA,SAAK,YAAY,KAAK,gBAAgB;AAEtC,SAAK,6BAA6B,IAAI;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,QACE,eAAe,KAAK;AAAA,QACpB,eAAe,KAAK;AAAA,QACpB,WAAW,KAAK;AAAA,QAChB,cAAc,oBAAoB,0BAA0B,IAAI;AAAA,MAClE;AAAA,IACF;AAEA,SAAK,2BAA2B,IAAI;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,QACE,eAAe,KAAK;AAAA,QACpB,eAAe,KAAK;AAAA,QACpB,WAAW,KAAK;AAAA,QAChB,YAAY,KAAK;AAAA,MACnB;AAAA,IACF;AAEA,SAAK,yBAAyB,KAAK,6BAA6B;AAChE,SAAK,uBAAuB,KAAK,2BAA2B;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAlHA,OAAO,+BACL,OACA,KAAK,wBACG;AACR,WAAOC,OAAM,cAAc,OAAO,IAAI,8BAA8B,KAAK,CAAC;AAAA,EAC5E;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,mBAAkB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiHQ,kBAA6B;AACnC,QAAI,KAAK,qBAAqB,MAAM;AAClC,WAAK,mBACH,oBAAoB,6BAA6B,IAAI;AAAA,IACzD;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKU,+BAAuD;AAC/D,WAAO,IAAI,uBAAuB,MAAM;AAAA,MACtC,iBAAiB,KAAK,gBAAgB;AAAA,MACtC,gBAAgB,KAAK;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,6BAA+D;AACvE,QAAI,KAAK,MAAM,QAAQ,cAAc,6BAAc,MAAM;AACvD,aAAO;AAAA,IACT;AACA,WAAO,IAAI,qBAAqB,MAAM;AAAA,MACpC,iBAAiB,KAAK,gBAAgB;AAAA,MACtC,gBAAgB,KAAK;AAAA,MACrB,UAAU,kBAAkB,sBAAsB,IAAI;AAAA,IACxD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,kBAA0B;AAClC,WAAO,IAAI,kBAAkB,MAAM,wBAAwB;AAAA,MACzD,eAAe,KAAK;AAAA,MACpB,QAAQ,eAAe;AAAA,IACzB,CAAC;AAAA,EACH;AACF;AA5Ka,mBACK,eAAe;AAD1B,IAAM,oBAAN;;;AQnCP,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,YAAAC,iBAAgB;AAEzB,SAAoB,QAAAC,aAAY;AAChC,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,kBAAAC,uBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAU1B,IAAMC,gBAAe;AAKrB,SAASC,qBAAoB,SAAyB;AACpD,QAAM,UAAUC,MAAK,KAAK,SAASF,aAAY;AAC/C,MAAIG,IAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAOD,MAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,OAAOF,aAAY;AACvE;AAwBO,IAAM,kCAAN,cAA8CI,YAAU;AAAA,EAI7D,YAAY,OAAkB,OAA6C;AACzE,UAAM,OAAO,oCAAoC;AAEjD,SAAK,SAAS,IAAIC,gBAAe,MAAM,WAAW;AAAA,MAChD,OAAOJ,qBAAoB,SAAS;AAAA,MACpC,SAASK,SAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,MAC1C;AAAA,IACF,CAAC;AAGD,UAAM,eAAe;AAAA,MACnB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAIA,SAAK,OAAO;AAAA,MACV,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,gBAAgB;AAAA,QAC1B,WAAW,CAAC,GAAG,MAAM,eAAe,QAAQ,UAAU;AAAA,MACxD,CAAC;AAAA,IACH;AAGA,SAAK,OAAO,IAAIC,MAAK,MAAM,QAAQ;AAAA,MACjC,UAAU,MAAM;AAAA,MAChB,cAAc;AAAA,QACZ,QAAQ,CAAC,4BAA4B;AAAA,QACrC,YAAY,CAAC,uCAAuC;AAAA,MACtD;AAAA,MACA,SAAS;AAAA,QACP,IAAIC,gBAAe,KAAK,QAAQ;AAAA,UAC9B,eAAe;AAAA,UACf,aAAaC,UAAS,MAAM,CAAC;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACrGA,SAAS,aAAAC,mBAAiB;AAenB,IAAM,yBAAN,cAAqCC,YAAU;AAAA,EAGpD,YAAY,OAAkB,OAAoC;AAChE,UAAM,OAAO,0BAA0B;AAEvC,SAAK,4BAA4B,IAAI,gCAAgC,MAAM;AAAA,MACzE,gBAAgB,MAAM;AAAA,MACtB,iBAAiB,MAAM;AAAA,IACzB,CAAC;AAAA,EACH;AACF;;;AVwCO,IAAM,qBAAN,MAAM,2BAA0B,cAAc;AAAA,EA6GnD,YAAY,OAA0B,QAAgC,CAAC,GAAG;AACxE,UAAM,OAAO,mBAAkB,cAAc,KAAK;AANpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,kBAEG;AACX,SAAQ,mBAAqC;AAI3C,SAAK,QAAQ;AAEb,SAAK,iBAAiB,KAAK,qBAAqB;AAChD,SAAK,2BAA2B,KAAK,+BAA+B;AACpE,SAAK,2BAA2B,KAAK,+BAA+B;AACpE,SAAK,yBAAyB,KAAK,6BAA6B;AAChE,SAAK,yBAAyB,KAAK,6BAA6B;AAChE,SAAK,WAAW,KAAK,eAAe;AACpC,SAAK,mCAAmC;AACxC,SAAK,mCAAmC;AACxC,SAAK,iCAAiC;AACtC,SAAK,iBAAiB,KAAK,qBAAqB;AAChD,SAAK,iBAAiB,KAAK,qBAAqB;AAChD,SAAK,sBAAsB,KAAK,0BAA0B;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAvHA,OAAO,sBAAsB,OAA6B;AACxD,UAAM,aAAa,4BAA4B,mBAAmB,OAAO;AAAA,MACvE,cAAc,gBAAgB;AAAA,MAC9B,aAAa,mBAAkB;AAAA,IACjC,CAAC;AACD,WAAOC,UAAS,eAAe,OAAO,aAAa,UAAU;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,4BAA4B,OAAmC;AACpE,UAAM,mBAAmB,4BAA4B;AAAA,MACnD;AAAA,MACA;AAAA,QACE,cAAc,sBAAsB;AAAA,QACpC,aAAa,mBAAkB;AAAA,MACjC;AAAA,IACF;AACA,WAAOC,gBAAe;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,iCAAiC,OAAmC;AACzE,UAAM,WAAW,4BAA4B,mBAAmB,OAAO;AAAA,MACrE,cAAc,2BAA2B;AAAA,MACzC,aAAa,mBAAkB;AAAA,IACjC,CAAC;AACD,WAAOA,gBAAe;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,4BAA4B,OAAmC;AACpE,UAAM,aAAa,4BAA4B,mBAAmB,OAAO;AAAA,MACvE,cAAc,sBAAsB;AAAA,MACpC,aAAa,mBAAkB;AAAA,IACjC,CAAC;AACD,WAAOC,gBAAe,eAAe,OAAO,oBAAoB,UAAU;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,4BAA4B,OAAwB;AACzD,UAAM,SAAS,4BAA4B,mBAAmB,OAAO;AAAA,MACnE,cAAc,sBAAsB;AAAA,MACpC,aAAa,mBAAkB;AAAA,IACjC,CAAC;AACD,WAAOC,KAAI,WAAW,OAAO,WAAW,MAAM;AAAA,EAChD;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,mBAAkB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsDU,uBAA6B;AACrC,UAAM,MAAM,IAAI,sBAAsB,IAAI;AAC1C,QAAI,4BAA4B,MAAM,iBAAiB;AAAA,MACrD,cAAc,sBAAsB;AAAA,MACpC,aAAa,IAAI;AAAA,MACjB,aACE;AAAA,IACJ,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,iCAA4C;AACpD,UAAM,YAAY,IAAI,yBAAyB,MAAM;AAAA,MACnD,iBAAiB,KAAK,eAAe,EAAE;AAAA,IACzC,CAAC;AACD,WAAO,UAAU;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,iCAA4C;AACpD,UAAM,YAAY,IAAI,yBAAyB,IAAI;AACnD,WAAO,UAAU;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,+BAA0C;AAClD,UAAM,YAAY,IAAI,uBAAuB,MAAM;AAAA,MACjD,qBAAqB,KAAK,gBAAgB,EAAE;AAAA,IAC9C,CAAC;AACD,WAAO,UAAU;AAAA,EACnB;AAAA,EAEU,+BAAuD;AAC/D,WAAO,IAAI,uBAAuB,MAAM;AAAA,MACtC,iBAAiB,KAAK,gBAAgB;AAAA,MACtC,gBAAgB,KAAK,eAAe;AAAA,IACtC,CAAC;AAAA,EACH;AAAA,EAEQ,iBAAiB;AACvB,QAAI,KAAK,oBAAoB,MAAM;AACjC,WAAK,kBACH,kBAAkB,+BAA+B,IAAI;AAAA,IACzD;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,kBAAkB;AACxB,QAAI,KAAK,qBAAqB,MAAM;AAClC,WAAK,mBACH,oBAAoB,6BAA6B,IAAI;AAAA,IACzD;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,iBAA4B;AACpC,UAAM,WAAW,IAAI,gBAAgB,MAAM;AAAA,MACzC,GAAG,KAAK,MAAM;AAAA,MACd,oBAAoB,KAAK;AAAA,IAC3B,CAAC;AAED,aAAS;AAAA,MACP,kBAAkB;AAAA,MAClB,KAAK;AAAA,MACL,cAAc;AAAA,IAChB;AACA,aAAS;AAAA,MACP,kBAAkB;AAAA,MAClB,KAAK;AAAA,IACP;AACA,aAAS;AAAA,MACP,kBAAkB;AAAA,MAClB,KAAK;AAAA,IACP;AACA,QAAI,4BAA4B,MAAM,mBAAmB;AAAA,MACvD,cAAc,gBAAgB;AAAA,MAC9B,aAAa,SAAS;AAAA,MACtB,aACE;AAAA,IACJ,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWU,qCAA2C;AACnD,UAAM,iBAAiB,KAAK,eAAe;AAC3C,UAAM,gBAAgB,CAAC,oBAAoB,gBAAgB;AAC3D,mBAAe,MAAM,KAAK,0BAA0B,GAAG,aAAa;AACpE,SAAK,yBAAyB;AAAA,MAC5B,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,GAAG,aAAa;AAAA,QAC1B,WAAW,CAAC,GAAG,eAAe,QAAQ,UAAU;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeU,qCAA2C;AACnD,SAAK,yBAAyB;AAAA,MAC5B,IAAID,iBAAgB;AAAA,QAClB,SAAS,CAAC,oCAAoC;AAAA,QAC9C,WAAW;AAAA,UACTE,OAAM,GAAG,IAAI,EAAE,UAAU;AAAA,YACvB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,cAAc;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,mCAAyC;AACjD,SAAK,gBAAgB,EAAE,iBAAiB,KAAK,sBAAsB;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,uBAAwC;AAChD,UAAM,SAAS,IAAI,sBAAsB,MAAM;AAAA,MAC7C,UAAU,KAAK;AAAA,IACjB,CAAC;AACD,QAAI,4BAA4B,MAAM,0BAA0B;AAAA,MAC9D,cAAc,sBAAsB;AAAA,MACpC,aAAa,OAAO;AAAA,MACpB,aACE;AAAA,IACJ,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaU,4BAAyD;AACjE,QAAI,KAAK,MAAM,QAAQ,cAAc,6BAAc,MAAM;AACvD,aAAO;AAAA,IACT;AACA,UAAM,SAAS,IAAI,2BAA2B,MAAM;AAAA,MAClD,UAAU,KAAK;AAAA,IACjB,CAAC;AACD,QAAI,4BAA4B,MAAM,+BAA+B;AAAA,MACnE,cAAc,2BAA2B;AAAA,MACzC,aAAa,OAAO;AAAA,MACpB,aACE;AAAA,IAEJ,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,uBAAwC;AAChD,UAAM,SAAS,IAAI,sBAAsB,MAAM;AAAA,MAC7C,UAAU,KAAK;AAAA,MACf,eAAe;AAAA,QACb,cAAc,QAAQ,KAAK,UAAU;AAAA,MACvC;AAAA,IACF,CAAC;AACD,QAAI,4BAA4B,MAAM,0BAA0B;AAAA,MAC9D,cAAc,sBAAsB;AAAA,MACpC,aAAa,OAAO;AAAA,MACpB,aACE;AAAA,IACJ,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAtWa,mBACK,eAAe;AAD1B,IAAM,oBAAN;;;AWpEP,IAAAC,iBAA8B;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,8BAA8B;AACvC,SAAS,6BAA6B;AAEtC,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC;AAAA,EACE;AAAA,EACA,cAAAC;AAAA,EAEA;AAAA,OACK;AACP,SAAS,oCAAoC;AAC7C,SAAS,YAAAC,kBAAgB;;;ACtBzB,OAAOC,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,WAAAC,iBAAe;AACxB,SAAS,kBAAAC,wBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAQ1B,IAAMC,iBAAe;AAKrB,SAASC,sBAAoB,SAAyB;AACpD,QAAM,UAAUL,OAAK,KAAK,SAASI,cAAY;AAC/C,MAAIL,KAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,UAAUC,OAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAOI,cAAY;AACxE,SAAO;AACT;AAEO,IAAM,oBAAN,cAAgCD,YAAU;AAAA,EAG/C,YAAY,OAAkB,KAAa,uBAAuB;AAChE,UAAM,OAAO,EAAE;AAEf,SAAK,SAAS,IAAID,iBAAe,MAAM,WAAW;AAAA,MAChD,OAAOG,sBAAoB,SAAS;AAAA,MACpC,SAASJ,UAAQ;AAAA,MACjB,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AACF;;;ACvCA,OAAOK,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,WAAAC,iBAAe;AACxB,SAAS,kBAAAC,wBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAM1B,IAAMC,iBAAe;AAKrB,SAASC,sBAAoB,SAAyB;AACpD,QAAM,UAAUL,OAAK,KAAK,SAASI,cAAY;AAC/C,MAAIL,KAAG,WAAW,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,UAAUC,OAAK,KAAK,SAAS,MAAM,MAAM,MAAM,OAAOI,cAAY;AACxE,SAAO;AACT;AA6CO,IAAM,gBAAN,cAA4BD,YAAU;AAAA,EAG3C,YAAY,OAAkB,OAA2B;AACvD,UAAM,OAAO,iBAAiB;AAK9B,SAAK,SAAS,IAAID,iBAAe,MAAM,WAAW;AAAA,MAChD,OAAOG,sBAAoB,SAAS;AAAA,MACpC,SAASJ,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,QACX,mBAAmB,MAAM;AAAA,QACzB,kBAAkB,MAAM;AAAA,QACxB,oBAAoB,MAAM;AAAA,QAC1B,uBAAuB,MAAM;AAAA,QAC7B,sBAAsB,MAAM;AAAA,QAC5B,oBAAoB,MAAM;AAAA,QAC1B,kBAAkB,MAAM;AAAA,MAC1B;AAAA,MACA,UAAU;AAAA,QACR,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AFnCO,IAAM,6BAA6B;AAMnC,IAAM,wBAAN,MAAM,8BAA6B,cAAc;AAAA;AAAA;AAAA;AAAA,EAOtD,OAAO,yBAAyB,OAA4B;AAC1D,UAAM,YAAY,4BAA4B,mBAAmB,OAAO;AAAA,MACtE,cAAc,YAAY;AAAA,MAC1B,aAAa,sBAAqB;AAAA,IACpC,CAAC;AACD,WAAOK,SAAQ,sBAAsB,OAAO,YAAY,EAAE,UAAU,CAAC;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,4BAA4B,OAA0B;AAC3D,WAAO,4BAA4B,mBAAmB,OAAO;AAAA,MAC3D,cAAc;AAAA,MACd,aAAa,sBAAqB;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,sBAAqB;AAAA,EAC9B;AAAA,EAOA,YAAY,OAA0B,QAAmC,CAAC,GAAG;AAC3E,UAAM,OAAO,sBAAqB,cAAc,KAAK;AACrD,SAAK,QAAQ;AAEb,SAAK,eAAe,KAAK;AAEzB,UAAM,aAAa,KAAK,iBAAiB;AACzC,UAAM,cAAc,KAAK,kBAAkB;AAC3C,UAAM,gBAAgB,KAAK,0BAA0B,UAAU;AAC/D,SAAK,8BAA8B,aAAa;AAChD,UAAM,aAAa,KAAK,iBAAiB,YAAY,WAAW;AAChE,SAAK,cAAc,KAAK,kBAAkB,UAAU;AACpD,SAAK,6BAA6B,YAAY,UAAU;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKU,eAAe,OAAwC;AAC/D,UAAM,EAAE,OAAO,IAAI;AACnB,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,QAAI,CAAC,OAAO,cAAc;AACxB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AACA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,mBAAgC;AACxC,UAAM,EAAE,OAAO,IAAI,KAAK;AACxB,WAAOC,YAAW,yBAAyB,MAAM,aAAa;AAAA,MAC5D,cAAc,OAAQ;AAAA,MACtB,UAAU,OAAQ;AAAA,IACpB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,oBAAoB;AAC5B,WAAO,oBAAoB,qCAAqC,IAAI;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,0BAA0B,YAAiC;AACnE,UAAM,YACJ,KAAK,eAAe,SAAS,QAAQ,OAAO,KAAK,eAAe;AAClE,WAAO,CAAC,WAAW,WAAW,QAAQ,EAAE,KAAK,GAAG;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,8BAA8B,eAA6B;AACnE,UAAM,iBAAiB,WAAW,aAAa;AAC/C,QAAI,4BAA4B,MAAM,2BAA2B;AAAA,MAC/D,cAAc;AAAA,MACd,aAAa;AAAA,MACb,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,iBACR,aACA,aACY;AACZ,UAAM,gBAAgB,KAAK,0BAA0B,WAAW;AAChE,WAAO,IAAI,WAAW,MAAM,UAAU;AAAA,MACpC,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,6BACR,YACA,YACM;AACN,UAAM,iBACJ,kBAAkB,+BAA+B,IAAI;AAMvD,UAAM,qBACJ,yBAAyB,wBAAwB,IAAI;AACvD,UAAM,oBACJ,yBAAyB,uBAAuB,IAAI;AACtD,UAAM,mBACJ,yBAAyB,0BAA0B,IAAI;AACzD,UAAM,iBAAiB,6BAA6B,KAAK,UAAU;AAEnE,UAAM,EAAE,OAAO,IAAI,IAAI,cAAc,MAAM;AAAA,MACzC,iBAAiB,eAAe;AAAA,MAChC,gBAAgB,KAAK;AAAA,MACrB,iBAAiB,YAAY;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAKD,WAAO;AAAA,MACL,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS;AAAA,UACP;AAAA,UACA;AAAA,QACF;AAAA,QACA,WAAW,CAAC,kBAAkB;AAAA,MAChC,CAAC;AAAA,IACH;AACA,WAAO;AAAA,MACL,IAAID,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,+BAA+B;AAAA,QACzC,WAAW,CAAC,iBAAiB;AAAA,MAC/B,CAAC;AAAA,IACH;AACA,UAAM,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,mBAAe,MAAM,QAAQ,GAAG,aAAa;AAE7C,WAAO;AAAA,MACL,IAAID,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,GAAG,aAAa;AAAA,QAC1B,WAAW,CAAC,GAAG,eAAe,QAAQ,UAAU;AAAA,MAClD,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,IAAID,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,WAAW,CAAC,GAAG;AAAA,MACjB,CAAC;AAAA,IACH;AACA,UAAM,cAAc,IAAI,sBAAsB,sBAAsB,MAAM;AAC1E,UAAM,EAAE,QAAQ,cAAc,IAAI,IAAI,kBAAkB,IAAI;AAC5D,UAAM,qBAAqB,IAAI;AAAA,MAC7B;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,IAAI,mBAAmB;AAEtC,QAAI,UAAU,MAAM,sBAAsB;AAAA,MACxC,SAAS,KAAK;AAAA,MACd,UAAU,aAAa,KAAK,KAAK,WAAW,OAAO;AAAA,MACnD,aAAa;AAAA,MACb,YAAY;AAAA,IACd,CAAC;AACD,QAAI,UAAU,MAAM,uBAAuB;AAAA,MACzC,SAAS,KAAK;AAAA,MACd,UAAU,aAAa,KAAK,aAAa,WAAW,OAAO;AAAA,MAC3D,aAAa;AAAA,MACb,YAAY;AAAA,IACd,CAAC;AACD,QAAI,UAAU,MAAM,oBAAoB;AAAA,MACtC,SAAS,KAAK;AAAA,MACd,UAAU,aAAa,KAAK,KAAK,WAAW,GAAG;AAAA,MAC/C;AAAA,IACF,CAAC;AACD,QAAI,UAAU,MAAM,eAAe;AAAA,MACjC,SAAS,KAAK;AAAA,MACd,UAAU,aAAa,KAAK,aAAa,WAAW,GAAG;AAAA,MACvD;AAAA,IACF,CAAC;AACD,UAAM,YACJ,KAAK,eAAe,SAAS,QAAQ,OAAO,KAAK,eAAe;AAClE,QAAI,QAAQ,MAAM,gBAAgB;AAAA,MAChC,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,QAAQ,aAAa;AAAA,QACnB,IAAI;AAAA,UACF,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,kBAAkB,YAAqC;AAC/D,UAAM,WAAW,kBAAkB,sBAAsB,IAAI;AAC7D,UAAM,iBAAiB,kBAAkB,4BAA4B,IAAI;AAOzE,UAAM,kBAAkB,CAAC,cAAc;AACvC,QAAI,KAAK,MAAM,QAAQ,cAAc,6BAAc,MAAM;AACvD,sBAAgB;AAAA,QACd,kBAAkB,iCAAiC,IAAI;AAAA,MACzD;AAAA,IACF;AACA,UAAM,oBAAoB,IAAI;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,EAAE,gBAAgB;AAAA,IACpB;AACA,UAAM,EAAE,eAAe,MAAM,GAAG,qBAAqB,IACnD,KAAK,MAAM,oBAAoB,CAAC;AAClC,UAAM,gBACJ,SAAS,SACL;AAAA,MACE,cAAc,KAAK;AAAA,MACnB,cAAc,KAAK,gBAAgB;AAAA,QACjC,eAAe;AAAA,QACf,eAAe;AAAA,QACf,eAAe;AAAA,QACf,eAAe;AAAA,QACf,eAAe;AAAA,QACf,eAAe;AAAA,QACf,eAAe;AAAA,MACjB;AAAA,MACA,cAAc,KAAK,gBAAgB;AAAA,QACjC;AAAA,QACA;AAAA,MACF;AAAA,MACA,kBAAkB,KAAK,oBAAoB;AAAA,MAC3C,QAAQ,KAAK,UAAUC,WAAS,KAAK,CAAC;AAAA,MACtC,GAAI,KAAK,kBAAkB,UAAa;AAAA,QACtC,eAAe,KAAK;AAAA,MACtB;AAAA,IACF,IACA;AACN,UAAM,cAAc,IAAI,YAAY,MAAM;AAAA,MACxC,GAAG;AAAA,MACH,GAAI,kBAAkB,UAAa,EAAE,cAAc;AAAA,MACnD,sBAAsB;AAAA,QACpB;AAAA,QACA,YAAY;AAAA,MACd;AAAA,MACA,mBAAmB;AAAA,IACrB,CAAC;AACD,QAAI,4BAA4B,MAAM,sBAAsB;AAAA,MAC1D,cAAc,YAAY;AAAA,MAC1B,aAAa,YAAY;AAAA,MACzB,aACE;AAAA,IACJ,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAlUa,sBACK,eACd;AAFG,IAAM,uBAAN;;;AGnEP;AAAA,EACE;AAAA,EAEA;AAAA,OACK;AAkBA,IAAM,wBAAN,MAAM,8BAA6B,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtD,OAAO,wBAAwB,OAA+B;AAC5D,WAAO,eAAe,cAAc,KAAK;AAAA,EAC3C;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,sBAAqB;AAAA,EAC9B;AAAA,EAOA,YAAY,OAA0B,QAAmC,CAAC,GAAG;AAC3E,UAAM,OAAO,sBAAqB,cAAc,KAAK;AACrD,SAAK,QAAQ;AACb,SAAK,iBAAiB,KAAK,qBAAqB;AAAA,EAClD;AAAA;AAAA,EAGU,uBAAuC;AAC/C,UAAM,WAAW,kBAAkB,sBAAsB,IAAI;AAC7D,WAAO,IAAI,eAAe,MAAM;AAAA,MAC9B,qBAAqB;AAAA,QACnB,sBAAsB;AAAA,UACpB,mBAAmB,kBAAkB;AAAA,UACrC,gBAAgB;AAAA,YACd;AAAA,YACA,eAAe,sBAAsB;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AA1Ca,sBACK,eACd;AAFG,IAAM,uBAAN;;;ACtBP,OAAOC,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,YAAAC,kBAAgB;AAGzB,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAS,WAAAC,iBAAe;AACxB,SAAS,kBAAAC,wBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAiB1B,SAASC,sBACP,SACA,aACiB;AACjB,QAAM,UAAUC,OAAK,KAAK,SAAS,WAAW;AAC9C,MAAIC,KAAG,WAAW,OAAO,GAAG;AAC1B,WAAO,EAAE,OAAO,SAAS,SAAS,UAAU;AAAA,EAC9C;AACA,QAAM,SAASD,OAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,OAAO,WAAW;AAC5E,SAAO,EAAE,OAAO,QAAQ,SAAS,UAAU;AAC7C;AAgCO,IAAM,6BAAN,cAAyCE,YAAU;AAAA,EAKxD,YAAY,OAAkB,OAAwC;AACpE,UAAM,OAAO,+BAA+B;AAE5C,UAAM,eAAeH;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AACA,SAAK,aAAa,IAAII,iBAAe,MAAM,uBAAuB;AAAA,MAChE,OAAO,aAAa;AAAA,MACpB,SAASC,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,WAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,MAC1C;AAAA,IACF,CAAC;AACD,UAAM,eAAe,MAAM,KAAK,YAAY,gBAAgB;AAE5D,UAAM,iBAAiBN;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACA,SAAK,cAAc,IAAII,iBAAe,MAAM,wBAAwB;AAAA,MAClE,OAAO,eAAe;AAAA,MACtB,SAASC,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,WAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,MAC1C;AAAA,IACF,CAAC;AAKD,UAAM,eAAe;AAAA,MACnB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,mBAAmBN;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AACA,SAAK,WAAW,IAAII,iBAAe,MAAM,oBAAoB;AAAA,MAC3D,OAAO,iBAAiB;AAAA,MACxB,SAASC,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,WAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,QACxC,CAAC,mCAAmC,GAAG,MAAM,YAAY;AAAA,MAC3D;AAAA,IACF,CAAC;AACD,UAAM,eAAe,MAAM,KAAK,UAAU,qBAAqB;AAC/D,SAAK,SAAS;AAAA,MACZ,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,kBAAkB;AAAA,QAC5B,WAAW,CAAC,MAAM,YAAY,WAAW;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ACzIA,SAAS,YAAAC,kBAAgB;AAEzB,SAAoB,QAAAC,aAAY;AAChC,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,aAAAC,mBAAiB;AA6DnB,IAAM,8BAAN,cAA0CC,YAAU;AAAA,EAKzD,YAAY,OAAkB,OAAyC;AACrE,UAAM,OAAO,gCAAgC;AAE7C,SAAK,UAAU,IAAI,2BAA2B,MAAM;AAAA,MAClD,gBAAgB,MAAM;AAAA,MACtB,aAAa,MAAM;AAAA,IACrB,CAAC;AAED,UAAM,cACJ,MAAM,yBAAyB;AAKjC,UAAM,YAAY,IAAI,KAAK,MAAM,cAAc;AAAA,MAC7C,YAAY;AAAA,QACV,eAAe;AAAA,QACf,aAAa;AAAA,QACb,cAAc;AAAA,QACd,SAAS,CAAC;AAAA,QACV,oBAAoB;AAAA,QACpB,YAAY;AAAA;AAAA,QAEZ,eAAe;AAAA;AAAA,QAEf,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB;AAAA,IACF,CAAC;AAKD,UAAM,aAAa,IAAI,aAAa,MAAM,eAAe;AAAA,MACvD,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,YAAY;AAAA,MACZ,0BAA0B;AAAA,IAC5B,CAAC;AAKD,UAAM,kBAAkB,IAAI,KAAK,MAAM,qBAAqB;AAAA,MAC1D,YAAY;AAAA,QACV,eAAe;AAAA,QACf,aAAa;AAAA,QACb,cAAc;AAAA,QACd,aAAa;AAAA,QACb,wBAAwB;AAAA,QACxB,gBAAgB;AAAA,QAChB,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB;AAAA,IACF,CAAC;AAYD,UAAM,gBAAgB,IAAI,YAAY,MAAM,kBAAkB;AAAA,MAC5D,WAAW;AAAA,QACT,MAAM;AAAA,QACN,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,YAAY;AAAA,QACZ,cAAc;AAAA;AAAA;AAAA,UAGZ,eAAe;AAAA,UACf,aAAa;AAAA,UACb,cAAc;AAAA,UACd,UAAU;AAAA,UACV,gBAAgB;AAAA,QAClB;AAAA,QACA,eAAe;AAAA,UACb,iBAAiB;AAAA;AAAA,YAEf,MAAM;AAAA,UACR;AAAA,UACA,SAAS;AAAA,UACT,QAAQ;AAAA,YACN,aAAa;AAAA,cACX,MAAM;AAAA,cACN,UAAU;AAAA,cACV,YAAY;AAAA,gBACV,cAAc,KAAK,QAAQ,YAAY;AAAA,gBACvC,aAAa;AAAA,cACf;AAAA,cACA,OAAO;AAAA,gBACL;AAAA,kBACE,aAAa;AAAA,oBACX;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,kBACA,iBAAiB;AAAA,kBACjB,aAAa;AAAA,kBACb,aAAa;AAAA,kBACb,iBAAiB;AAAA,gBACnB;AAAA,cACF;AAAA,cACA,OAAO;AAAA,gBACL;AAAA;AAAA;AAAA;AAAA,kBAIE,aAAa,CAAC,uCAAuC;AAAA,kBACrD,MAAM;AAAA,gBACR;AAAA,cACF;AAAA,cACA,KAAK;AAAA,YACP;AAAA,YACA,qBAAqB;AAAA,cACnB,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAID,UAAM,gBAAgB,IAAI,KAAK,MAAM,mBAAmB;AAAA,MACtD,MAAM,SAAS,SAASC,WAAS,QAAQ,CAAC,CAAC;AAAA,IAC7C,CAAC;AAID,UAAM,cAAc,IAAI,OAAO,MAAM,cAAc;AAInD,UAAM,WAAW,IAAI,aAAa,MAAM,YAAY;AAAA,MAClD,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,SAAS,UAAU,WAAW;AAAA,QAC5B,eAAe;AAAA,QACf,aAAa;AAAA,QACb,cAAc;AAAA,QACd,wBAAwB;AAAA,QACxB,gBAAgB;AAAA,QAChB,eAAe;AAAA,QACf,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB,CAAC;AAAA,MACD,YAAY;AAAA,MACZ,0BAA0B;AAAA,IAC5B,CAAC;AAED,UAAM,UAAU,IAAI,QAAQ,MAAM,SAAS;AAW3C,UAAM,aAAa,UAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB;AAAA,MACC,YACG;AAAA,QACC,UAAU,cAAc,eAAe,IAAI;AAAA,QAC3C,SAAS,KAAK,OAAO;AAAA,MACvB,EACC,UAAU,UAAU;AAAA,IACzB;AAEF,SAAK,eAAe,IAAI,aAAa,MAAM,iBAAiB;AAAA,MAC1D,gBAAgB,eAAe,cAAc,UAAU;AAAA;AAAA;AAAA;AAAA,MAIvD,SAASA,WAAS,MAAM,CAAC;AAAA,IAC3B,CAAC;AAID,SAAK,OAAO,IAAIC,MAAK,MAAM,QAAQ;AAAA,MACjC,UAAU,MAAM;AAAA,MAChB,cAAc;AAAA,QACZ,QAAQ,CAAC,oCAAkB;AAAA,QAC3B,YAAY,CAAC,6CAA2B,UAAU;AAAA,MACpD;AAAA,MACA,SAAS;AAAA,QACP,IAAI,gBAAgB,KAAK,cAAc;AAAA,UACrC,eAAe;AAAA,UACf,aAAaD,WAAS,MAAM,CAAC;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACvSA,OAAOE,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,YAAAC,kBAAgB;AAGzB,SAAS,UAAAC,SAAQ,mBAAAC,wBAAuB;AACxC,SAAS,WAAAC,iBAAe;AACxB,SAAS,kBAAAC,wBAAsB;AAC/B,SAAS,aAAAC,mBAAiB;AAa1B,SAASC,sBACP,SACA,aACiB;AACjB,QAAM,UAAUC,OAAK,KAAK,SAAS,WAAW;AAC9C,MAAIC,KAAG,WAAW,OAAO,GAAG;AAC1B,WAAO,EAAE,OAAO,SAAS,SAAS,UAAU;AAAA,EAC9C;AACA,QAAM,SAASD,OAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,OAAO,WAAW;AAC5E,SAAO,EAAE,OAAO,QAAQ,SAAS,UAAU;AAC7C;AAyBO,IAAM,uBAAN,cAAmCE,YAAU;AAAA,EAKlD,YAAY,OAAkB,OAAkC;AAC9D,UAAM,OAAO,wBAAwB;AAErC,UAAM,eAAeH;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AACA,SAAK,cAAc,IAAII,iBAAe,MAAM,wBAAwB;AAAA,MAClE,OAAO,aAAa;AAAA,MACpB,SAASC,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,WAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,MAC1C;AAAA,IACF,CAAC;AACD,UAAM,eAAe,MAAM,KAAK,aAAa,gBAAgB;AAE7D,UAAM,kBAAkBN;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AACA,SAAK,eAAe,IAAII,iBAAe,MAAM,yBAAyB;AAAA,MACpE,OAAO,gBAAgB;AAAA,MACvB,SAASC,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,WAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,mBAAmB,MAAM,eAAe;AAAA,MAC1C;AAAA,IACF,CAAC;AAGD,UAAM,eAAe;AAAA,MACnB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,mBAAmBN;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AACA,SAAK,WAAW,IAAII,iBAAe,MAAM,oBAAoB;AAAA,MAC3D,OAAO,iBAAiB;AAAA,MACxB,SAASC,UAAQ;AAAA,MACjB,YAAY;AAAA,MACZ,SAASC,WAAS,QAAQ,CAAC;AAAA,MAC3B,aAAa;AAAA,QACX,CAAC,oCAAoC,GAAG,MAAM,YAAY;AAAA,MAC5D;AAAA,IACF,CAAC;AACD,SAAK,SAAS;AAAA,MACZ,IAAIC,iBAAgB;AAAA,QAClB,QAAQC,QAAO;AAAA,QACf,SAAS,CAAC,kBAAkB;AAAA,QAC5B,WAAW,CAAC,MAAM,YAAY,WAAW;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC1HA,SAAS,YAAAC,kBAAgB;AAEzB,SAAoB,QAAAC,aAAY;AAChC,SAAS,mBAAAC,wBAAuB;AAChC;AAAA,EACE,UAAAC;AAAA,EACA,aAAAC;AAAA,EACA,eAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,QAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AAAA,OACK;AACP,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,aAAAC,mBAAiB;AA+DnB,IAAM,wBAAN,cAAoCC,YAAU;AAAA,EAKnD,YAAY,OAAkB,OAAmC;AAC/D,UAAM,OAAO,yBAAyB;AAEtC,SAAK,UAAU,IAAI,qBAAqB,MAAM;AAAA,MAC5C,gBAAgB,MAAM;AAAA,MACtB,aAAa,MAAM;AAAA,IACrB,CAAC;AAED,UAAM,cACJ,MAAM,yBAAyB;AAKjC,UAAM,YAAY,IAAIC,MAAK,MAAM,cAAc;AAAA,MAC7C,YAAY;AAAA,QACV,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,aAAa;AAAA,QACb,aAAa;AAAA,QACb,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,QACvB,SAAS,CAAC;AAAA,QACV,gBAAgB;AAAA,QAChB,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,IAAIC,cAAa,MAAM,gBAAgB;AAAA,MACzD,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,YAAY;AAAA,MACZ,0BAA0B;AAAA,IAC5B,CAAC;AAGD,UAAM,kBAAkB,IAAID,MAAK,MAAM,qBAAqB;AAAA,MAC1D,YAAY;AAAA,QACV,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,aAAa;AAAA,QACb,aAAa;AAAA,QACb,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,QACvB,aAAa;AAAA,QACb,oBAAoB;AAAA,QACpB,gBAAgB;AAAA,QAChB,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB;AAAA,IACF,CAAC;AAWD,UAAM,gBAAgB,IAAIE,aAAY,MAAM,kBAAkB;AAAA,MAC5D,WAAW;AAAA,QACT,MAAM;AAAA,QACN,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,YAAY;AAAA,QACZ,cAAc;AAAA,UACZ,gBAAgB;AAAA,UAChB,cAAc;AAAA,UACd,cAAc;AAAA,UACd,aAAa;AAAA,UACb,gBAAgB;AAAA,QAClB;AAAA,QACA,eAAe;AAAA,UACb,iBAAiB;AAAA;AAAA;AAAA,YAGf,MAAM;AAAA,YACN,eAAe;AAAA,UACjB;AAAA,UACA,SAAS;AAAA,UACT,QAAQ;AAAA,YACN,cAAc;AAAA,cACZ,MAAM;AAAA,cACN,UAAU;AAAA,cACV,YAAY;AAAA,gBACV,cAAc,KAAK,QAAQ,aAAa;AAAA,gBACxC,aAAa;AAAA,cACf;AAAA,cACA,OAAO;AAAA,gBACL;AAAA,kBACE,aAAa;AAAA,oBACX;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,kBACA,iBAAiB;AAAA,kBACjB,aAAa;AAAA,kBACb,aAAa;AAAA,kBACb,iBAAiB;AAAA,gBACnB;AAAA,cACF;AAAA,cACA,OAAO;AAAA,gBACL;AAAA;AAAA;AAAA;AAAA,kBAIE,aAAa,CAAC,uCAAuC;AAAA,kBACrD,MAAM;AAAA,gBACR;AAAA,cACF;AAAA,cACA,KAAK;AAAA,YACP;AAAA,YACA,uBAAuB;AAAA,cACrB,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAID,UAAM,cAAc,IAAIC,QAAO,MAAM,cAAc;AAGnD,UAAM,WAAW,IAAIF,cAAa,MAAM,YAAY;AAAA,MAClD,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,SAASG,WAAU,WAAW;AAAA,QAC5B,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,aAAa;AAAA,QACb,oBAAoB;AAAA,QACpB,gBAAgB;AAAA,QAChB,eAAe;AAAA,QACf,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB,CAAC;AAAA,MACD,YAAY;AAAA,MACZ,0BAA0B;AAAA,IAC5B,CAAC;AAED,UAAM,UAAU,IAAIC,SAAQ,MAAM,SAAS;AAU3C,UAAM,aAAa,UAChB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB;AAAA,MACC,YACG;AAAA,QACCC,WAAU,cAAc,eAAe,IAAI;AAAA,QAC3C,SAAS,KAAK,OAAO;AAAA,MACvB,EACC,UAAU,WAAW;AAAA,IAC1B;AAEF,SAAK,eAAe,IAAIC,cAAa,MAAM,iBAAiB;AAAA,MAC1D,gBAAgBC,gBAAe,cAAc,UAAU;AAAA;AAAA;AAAA;AAAA,MAIvD,SAASC,WAAS,MAAM,CAAC;AAAA,IAC3B,CAAC;AAGD,SAAK,OAAO,IAAIC,MAAK,MAAM,QAAQ;AAAA,MACjC,UAAU,MAAM;AAAA,MAChB,cAAc;AAAA,QACZ,QAAQ,CAAC,oCAAkB;AAAA,QAC3B,YAAY,CAAC,uCAAqB,UAAU;AAAA,MAC9C;AAAA,MACA,SAAS;AAAA,QACP,IAAIC,iBAAgB,KAAK,cAAc;AAAA,UACrC,eAAe;AAAA,UACf,aAAaF,WAAS,MAAM,CAAC;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":["import_config","Stage","Stage","import_config","Tags","StringParameter","StringParameter","Tags","UserPoolClient","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","fs","path","Duration","RemovalPolicy","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","import_workflows","AttributeType","BillingMode","Table","Construct","Construct","Table","AttributeType","BillingMode","EventBus","EventBus","EventBus","EventBus","fs","path","Duration","Stack","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","Stack","NodejsFunction","Runtime","Duration","Duration","Construct","Bucket","Duration","Construct","Construct","Bucket","Duration","import_config","UserPool","UserPoolClient","UserPoolDomain","Effect","PolicyStatement","Key","Stack","import_config","Table","Certificate","EventBus","HostedZone","StringParameter","Construct","fs","path","Duration","Stack","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","Stack","NodejsFunction","Runtime","Duration","PolicyStatement","Effect","Construct","HostedZone","StringParameter","Certificate","EventBus","fs","path","Duration","Stack","Rule","LambdaFunction","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","Duration","PolicyStatement","Effect","Stack","Rule","LambdaFunction","Construct","Construct","fs","path","PLATFORM_ROLE_IDS","Duration","Stack","Rule","LambdaFunction","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","Duration","PLATFORM_ROLE_IDS","PolicyStatement","Effect","Stack","Rule","LambdaFunction","Construct","Construct","Table","fs","path","Duration","Rule","LambdaFunction","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","PolicyStatement","Effect","Rule","LambdaFunction","Duration","Construct","Construct","UserPool","UserPoolClient","UserPoolDomain","Key","PolicyStatement","Effect","Stack","import_config","HttpApi","Effect","PolicyStatement","HostedZone","Duration","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","fs","path","Runtime","NodejsFunction","Construct","HANDLER_NAME","resolveHandlerEntry","HttpApi","HostedZone","PolicyStatement","Effect","Duration","fs","path","Duration","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","Duration","PolicyStatement","Effect","Duration","Rule","Construct","Construct","Duration","Rule","fs","path","Duration","Effect","PolicyStatement","Runtime","NodejsFunction","Construct","resolveHandlerEntry","path","fs","Construct","NodejsFunction","Runtime","Duration","PolicyStatement","Effect","Duration","Rule","SfnStateMachine","Choice","Condition","CustomState","DefinitionBody","Pass","StateMachine","Succeed","TaskInput","LambdaInvoke","Construct","Construct","Pass","LambdaInvoke","CustomState","Choice","TaskInput","Succeed","Condition","StateMachine","DefinitionBody","Duration","Rule","SfnStateMachine"]}
|