@openhi/constructs 0.0.105 → 0.0.107

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/lib/chunk-36UPY7YQ.mjs +529 -0
  2. package/lib/chunk-36UPY7YQ.mjs.map +1 -0
  3. package/lib/chunk-AGF3RAAZ.mjs +20 -0
  4. package/lib/chunk-AGF3RAAZ.mjs.map +1 -0
  5. package/lib/{chunk-BXEG7IOZ.mjs → chunk-AO3E22CS.mjs} +2 -2
  6. package/lib/{chunk-WNUH2WDZ.mjs → chunk-CHPEQRXU.mjs} +2 -2
  7. package/lib/chunk-JUNL76HF.mjs +428 -0
  8. package/lib/chunk-JUNL76HF.mjs.map +1 -0
  9. package/lib/chunk-L6UAP4KP.mjs +27 -0
  10. package/lib/chunk-L6UAP4KP.mjs.map +1 -0
  11. package/lib/{chunk-3QS3WKRC.mjs → chunk-LZOMFHX3.mjs} +9 -2
  12. package/lib/chunk-SYBADQXI.mjs +607 -0
  13. package/lib/chunk-SYBADQXI.mjs.map +1 -0
  14. package/lib/chunk-VXX4I3EF.mjs +19 -0
  15. package/lib/chunk-VXX4I3EF.mjs.map +1 -0
  16. package/lib/{chunk-36YCDLLA.mjs → chunk-VYDIGFIX.mjs} +75 -481
  17. package/lib/chunk-VYDIGFIX.mjs.map +1 -0
  18. package/lib/chunk-YU2HRNUP.mjs +33 -0
  19. package/lib/chunk-YU2HRNUP.mjs.map +1 -0
  20. package/lib/chunk-YZZDUJHI.mjs +37 -0
  21. package/lib/chunk-YZZDUJHI.mjs.map +1 -0
  22. package/lib/cors-options-lambda.handler.mjs +1 -1
  23. package/lib/data-store-postgres-replication.handler.mjs +1 -1
  24. package/lib/events-BfrkMoBD.d.mts +44 -0
  25. package/lib/events-BfrkMoBD.d.ts +44 -0
  26. package/lib/events-DPodvl07.d.mts +207 -0
  27. package/lib/events-DPodvl07.d.ts +207 -0
  28. package/lib/firehose-archive-transform.handler.mjs +1 -1
  29. package/lib/index.d.mts +417 -9
  30. package/lib/index.d.ts +663 -10
  31. package/lib/index.js +2398 -111
  32. package/lib/index.js.map +1 -1
  33. package/lib/index.mjs +779 -104
  34. package/lib/index.mjs.map +1 -1
  35. package/lib/openhi-context-CaBH8SFo.d.mts +39 -0
  36. package/lib/openhi-context-CaBH8SFo.d.ts +39 -0
  37. package/lib/platform-deploy-bridge.handler.d.mts +14 -0
  38. package/lib/platform-deploy-bridge.handler.d.ts +14 -0
  39. package/lib/platform-deploy-bridge.handler.js +762 -0
  40. package/lib/platform-deploy-bridge.handler.js.map +1 -0
  41. package/lib/platform-deploy-bridge.handler.mjs +134 -0
  42. package/lib/platform-deploy-bridge.handler.mjs.map +1 -0
  43. package/lib/post-authentication.handler.mjs +1 -1
  44. package/lib/post-confirmation.handler.mjs +1 -1
  45. package/lib/pre-token-generation.handler.js +76 -31
  46. package/lib/pre-token-generation.handler.js.map +1 -1
  47. package/lib/pre-token-generation.handler.mjs +5 -3
  48. package/lib/pre-token-generation.handler.mjs.map +1 -1
  49. package/lib/provision-default-workspace.handler.js +86 -41
  50. package/lib/provision-default-workspace.handler.js.map +1 -1
  51. package/lib/provision-default-workspace.handler.mjs +6 -4
  52. package/lib/provision-default-workspace.handler.mjs.map +1 -1
  53. package/lib/rest-api-lambda.handler.js +114 -59
  54. package/lib/rest-api-lambda.handler.js.map +1 -1
  55. package/lib/rest-api-lambda.handler.mjs +40 -61
  56. package/lib/rest-api-lambda.handler.mjs.map +1 -1
  57. package/lib/seed-demo-data.handler.d.mts +107 -0
  58. package/lib/seed-demo-data.handler.d.ts +107 -0
  59. package/lib/seed-demo-data.handler.js +2037 -0
  60. package/lib/seed-demo-data.handler.js.map +1 -0
  61. package/lib/seed-demo-data.handler.mjs +23 -0
  62. package/lib/seed-demo-data.handler.mjs.map +1 -0
  63. package/lib/seed-system-data.handler.d.mts +64 -0
  64. package/lib/seed-system-data.handler.d.ts +64 -0
  65. package/lib/seed-system-data.handler.js +1631 -0
  66. package/lib/seed-system-data.handler.js.map +1 -0
  67. package/lib/seed-system-data.handler.mjs +135 -0
  68. package/lib/seed-system-data.handler.mjs.map +1 -0
  69. package/package.json +4 -2
  70. package/lib/chunk-36YCDLLA.mjs.map +0 -1
  71. /package/lib/{chunk-BXEG7IOZ.mjs.map → chunk-AO3E22CS.mjs.map} +0 -0
  72. /package/lib/{chunk-WNUH2WDZ.mjs.map → chunk-CHPEQRXU.mjs.map} +0 -0
  73. /package/lib/{chunk-3QS3WKRC.mjs.map → chunk-LZOMFHX3.mjs.map} +0 -0
package/lib/index.mjs CHANGED
@@ -1,18 +1,66 @@
1
1
  import {
2
- PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,
3
- USER_ONBOARDING_EVENT_SOURCE,
4
- buildProvisionDefaultWorkspaceRequestedDetail
5
- } from "./chunk-2PM2NGXI.mjs";
2
+ SEED_SYSTEM_DATA_ACTOR_SYSTEM,
3
+ SEED_SYSTEM_DATA_CONSUMER_NAME,
4
+ SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR,
5
+ import_workflows as import_workflows2
6
+ } from "./chunk-AGF3RAAZ.mjs";
7
+ import {
8
+ DEMO_PERIOD,
9
+ DEMO_TENANT_SPECS,
10
+ DEMO_URN_SYSTEM,
11
+ DEV_USERS,
12
+ OPENHI_RESOURCE_URN_SYSTEM,
13
+ PLACEHOLDER_TENANT_ID,
14
+ PLACEHOLDER_WORKSPACE_ID,
15
+ PLATFORM_SCOPE_TENANT_ID,
16
+ SEED_DEMO_DATA_CONSUMER_NAME,
17
+ SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR,
18
+ demoBasePartitionKeys,
19
+ demoDevUserPartitionKeys,
20
+ demoMembershipId,
21
+ demoMembershipPartitionKey,
22
+ demoRoleAssignmentId,
23
+ demoRoleAssignmentPartitionKey,
24
+ demoRolesForUserInTenant,
25
+ demoScenarioIdentifier,
26
+ demoTenantPartitionKey,
27
+ demoUserPartitionKey,
28
+ demoWorkspacePartitionKey,
29
+ import_workflows,
30
+ openhiResourceIdentifier,
31
+ rolePartitionKey
32
+ } from "./chunk-36UPY7YQ.mjs";
6
33
  import {
7
34
  DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES,
8
35
  DATA_STORE_CHANGE_DETAIL_TYPE,
9
36
  DATA_STORE_CHANGE_EVENT_SOURCE,
10
37
  buildFhirCurrentResourceChangeDetail
11
38
  } from "./chunk-CEOAGPYY.mjs";
39
+ import "./chunk-L6UAP4KP.mjs";
40
+ import {
41
+ PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,
42
+ USER_ONBOARDING_EVENT_SOURCE,
43
+ buildProvisionDefaultWorkspaceRequestedDetail
44
+ } from "./chunk-2PM2NGXI.mjs";
45
+ import {
46
+ BRIDGED_STATUSES,
47
+ CLOUDFORMATION_EVENT_SOURCE,
48
+ CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE,
49
+ CONTROL_EVENT_BUS_NAME_ENV_VAR,
50
+ OPENHI_REPO_TAG_KEY_ENV_VAR,
51
+ OPENHI_TAG_KEY_PREFIX_ENV_VAR,
52
+ PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM
53
+ } from "./chunk-VXX4I3EF.mjs";
54
+ import {
55
+ require_lib
56
+ } from "./chunk-SYBADQXI.mjs";
57
+ import "./chunk-AO3E22CS.mjs";
58
+ import "./chunk-YZZDUJHI.mjs";
59
+ import "./chunk-VYDIGFIX.mjs";
12
60
  import {
13
61
  __commonJS,
14
62
  __toESM
15
- } from "./chunk-3QS3WKRC.mjs";
63
+ } from "./chunk-LZOMFHX3.mjs";
16
64
 
17
65
  // ../config/lib/open-hi-config.js
18
66
  var require_open_hi_config = __commonJS({
@@ -50,7 +98,7 @@ var require_open_hi_config = __commonJS({
50
98
  });
51
99
 
52
100
  // ../config/lib/index.js
53
- var require_lib = __commonJS({
101
+ var require_lib2 = __commonJS({
54
102
  "../config/lib/index.js"(exports) {
55
103
  "use strict";
56
104
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
@@ -75,11 +123,11 @@ var require_lib = __commonJS({
75
123
  });
76
124
 
77
125
  // src/app/open-hi-app.ts
78
- var import_config2 = __toESM(require_lib());
126
+ var import_config2 = __toESM(require_lib2());
79
127
  import { App } from "aws-cdk-lib";
80
128
 
81
129
  // src/app/open-hi-environment.ts
82
- var import_config = __toESM(require_lib());
130
+ var import_config = __toESM(require_lib2());
83
131
  import { Stage } from "aws-cdk-lib";
84
132
  var OPEN_HI_ENVIRONMENT_SYMBOL = /* @__PURE__ */ Symbol.for(
85
133
  "@openhi/constructs/core.OpenHiEnvironment"
@@ -281,7 +329,7 @@ var OpenHiApp = class _OpenHiApp extends App {
281
329
  };
282
330
 
283
331
  // src/app/open-hi-service.ts
284
- var import_config3 = __toESM(require_lib());
332
+ var import_config3 = __toESM(require_lib2());
285
333
  import {
286
334
  findGitBranch,
287
335
  findGitRepoName,
@@ -289,6 +337,11 @@ import {
289
337
  } from "@codedrifters/utils";
290
338
  import { RemovalPolicy, Stack, Tags } from "aws-cdk-lib";
291
339
  import { paramCase } from "change-case";
340
+ var OPENHI_TAG_SUFFIX_REPO_NAME = "repo-name";
341
+ var OPENHI_TAG_SUFFIX_BRANCH_NAME = "branch-name";
342
+ var OPENHI_TAG_SUFFIX_SERVICE_TYPE = "service-type";
343
+ var OPENHI_TAG_SUFFIX_STAGE_TYPE = "stage-type";
344
+ var openHiTagKey = (appName, suffix) => `${appName}:${suffix}`;
292
345
  var OpenHiService = class extends Stack {
293
346
  /**
294
347
  * Creates a new OpenHI service stack.
@@ -356,11 +409,20 @@ var OpenHiService = class extends Stack {
356
409
  `availability-zones:account=${account}:region=${region}`,
357
410
  [`${region}a`, `${region}b`, `${region}c`]
358
411
  );
359
- Tags.of(this).add(`${appName}:repo-name`, repoName.slice(0, 255));
360
- Tags.of(this).add(`${appName}:branch-name`, branchName.slice(0, 255));
361
- Tags.of(this).add(`${appName}:service-type`, id.slice(0, 255));
362
412
  Tags.of(this).add(
363
- `${appName}:stage-type`,
413
+ openHiTagKey(appName, OPENHI_TAG_SUFFIX_REPO_NAME),
414
+ repoName.slice(0, 255)
415
+ );
416
+ Tags.of(this).add(
417
+ openHiTagKey(appName, OPENHI_TAG_SUFFIX_BRANCH_NAME),
418
+ branchName.slice(0, 255)
419
+ );
420
+ Tags.of(this).add(
421
+ openHiTagKey(appName, OPENHI_TAG_SUFFIX_SERVICE_TYPE),
422
+ id.slice(0, 255)
423
+ );
424
+ Tags.of(this).add(
425
+ openHiTagKey(appName, OPENHI_TAG_SUFFIX_STAGE_TYPE),
364
426
  ohEnv.ohStage.stageType.slice(0, 255)
365
427
  );
366
428
  }
@@ -943,6 +1005,204 @@ var DynamoDbDataStore = class extends Table {
943
1005
  }
944
1006
  };
945
1007
 
1008
+ // src/components/dynamodb/workflow-dedup-table.ts
1009
+ var import_workflows3 = __toESM(require_lib());
1010
+ import { Annotations } from "aws-cdk-lib";
1011
+ import { AttributeType as AttributeType2, BillingMode as BillingMode2, Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
1012
+ import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
1013
+ import { Construct as Construct5 } from "constructs";
1014
+ function getWorkflowDedupTableName(scope) {
1015
+ const stack = OpenHiService.of(scope);
1016
+ return `workflow-dedup-${stack.branchHash}`;
1017
+ }
1018
+ var _WorkflowDedupTable = class _WorkflowDedupTable extends Construct5 {
1019
+ constructor(scope, id, props = {}) {
1020
+ super(scope, id);
1021
+ this.registeredConsumers = /* @__PURE__ */ new Set();
1022
+ const service = OpenHiService.of(scope);
1023
+ const others = service.node.findAll().filter(
1024
+ (c) => c instanceof _WorkflowDedupTable && c !== this
1025
+ );
1026
+ if (others.length > 0) {
1027
+ throw new WorkflowDedupTableDuplicateError(
1028
+ `WorkflowDedupTable already exists at ${others[0].node.path}; only one shared dedup table is allowed per service stack (TR-015).`
1029
+ );
1030
+ }
1031
+ this.table = new Table2(this, "Table", {
1032
+ tableName: getWorkflowDedupTableName(scope),
1033
+ partitionKey: {
1034
+ name: "consumerName",
1035
+ type: AttributeType2.STRING
1036
+ },
1037
+ sortKey: {
1038
+ name: "sk",
1039
+ type: AttributeType2.STRING
1040
+ },
1041
+ billingMode: BillingMode2.PAY_PER_REQUEST,
1042
+ timeToLiveAttribute: "expiresAt",
1043
+ removalPolicy: props.removalPolicy ?? service.removalPolicy
1044
+ });
1045
+ new DiscoverableStringParameter(this, "table-name-param", {
1046
+ ssmParamName: _WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME,
1047
+ stringValue: this.table.tableName
1048
+ });
1049
+ new DiscoverableStringParameter(this, "table-arn-param", {
1050
+ ssmParamName: _WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME,
1051
+ stringValue: this.table.tableArn
1052
+ });
1053
+ }
1054
+ /** Cross-stack lookup for the table name. */
1055
+ static tableNameFromLookup(scope) {
1056
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1057
+ ssmParamName: _WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME,
1058
+ serviceType: _WorkflowDedupTable.PUBLISHER_SERVICE_TYPE
1059
+ });
1060
+ }
1061
+ /** Cross-stack lookup for the table ARN. */
1062
+ static tableArnFromLookup(scope) {
1063
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1064
+ ssmParamName: _WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME,
1065
+ serviceType: _WorkflowDedupTable.PUBLISHER_SERVICE_TYPE
1066
+ });
1067
+ }
1068
+ /**
1069
+ * Cross-stack equivalent of {@link grantConsumer}. Use when the dedup
1070
+ * table is on a different stack than the consumer Lambda — the
1071
+ * grant resolves the table name + ARN via SSM at synth time, so the
1072
+ * consumer stack does not pick up a CloudFormation export dependency
1073
+ * on the global stack.
1074
+ *
1075
+ * Inverts the singleton-guard semantics of `grantConsumer`: there is
1076
+ * no synth-time check that the same `consumerName` was registered
1077
+ * twice across stacks. Consumer names are agreed by convention
1078
+ * (see TR-015); double-registration is operator error caught at
1079
+ * design time, not synth time.
1080
+ */
1081
+ static grantConsumerFromLookup(scope, fn, consumerName, options = {}) {
1082
+ _WorkflowDedupTable.assertConsumerNameStatic(consumerName);
1083
+ const tableName = _WorkflowDedupTable.tableNameFromLookup(scope);
1084
+ const tableArn = _WorkflowDedupTable.tableArnFromLookup(scope);
1085
+ fn.addEnvironment(import_workflows3.WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR, tableName);
1086
+ if (options.defaultTtlSeconds !== void 0) {
1087
+ fn.addEnvironment(
1088
+ "OPENHI_WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS",
1089
+ String(options.defaultTtlSeconds)
1090
+ );
1091
+ }
1092
+ fn.addToRolePolicy(
1093
+ new PolicyStatement({
1094
+ effect: Effect.ALLOW,
1095
+ actions: [
1096
+ "dynamodb:PutItem",
1097
+ "dynamodb:UpdateItem",
1098
+ "dynamodb:GetItem",
1099
+ "dynamodb:Query"
1100
+ ],
1101
+ resources: [tableArn],
1102
+ conditions: {
1103
+ "ForAllValues:StringEquals": {
1104
+ "dynamodb:LeadingKeys": [consumerName]
1105
+ }
1106
+ }
1107
+ })
1108
+ );
1109
+ }
1110
+ /**
1111
+ * Standalone consumer-name validator shared by the instance method
1112
+ * and `grantConsumerFromLookup` so the two grants enforce identical
1113
+ * invariants.
1114
+ */
1115
+ static assertConsumerNameStatic(consumerName) {
1116
+ if (consumerName.length === 0) {
1117
+ throw new WorkflowDedupConsumerNameInvalidError(
1118
+ "consumerName must be non-empty."
1119
+ );
1120
+ }
1121
+ if (consumerName.length > import_workflows3.WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH) {
1122
+ throw new WorkflowDedupConsumerNameInvalidError(
1123
+ `consumerName must be at most ${import_workflows3.WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH} chars; got ${consumerName.length}.`
1124
+ );
1125
+ }
1126
+ if (/\s/.test(consumerName)) {
1127
+ throw new WorkflowDedupConsumerNameInvalidError(
1128
+ "consumerName must not contain whitespace."
1129
+ );
1130
+ }
1131
+ }
1132
+ /**
1133
+ * Wire a Lambda consumer to this table. Injects the table-name env var
1134
+ * so the runtime `WorkflowDedupClient` can resolve it, then attaches a
1135
+ * per-consumer IAM grant scoped by `dynamodb:LeadingKeys` so the
1136
+ * consumer can only read/write its own partition.
1137
+ */
1138
+ grantConsumer(fn, consumerName, options = {}) {
1139
+ this.assertConsumerName(consumerName);
1140
+ if (this.registeredConsumers.has(consumerName)) {
1141
+ Annotations.of(this).addWarning(
1142
+ `WorkflowDedupTable: consumerName "${consumerName}" registered more than once; subsequent grantConsumer calls add policy statements but do not re-inject the env var.`
1143
+ );
1144
+ }
1145
+ this.registeredConsumers.add(consumerName);
1146
+ fn.addEnvironment(import_workflows3.WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR, this.table.tableName);
1147
+ if (options.defaultTtlSeconds !== void 0) {
1148
+ fn.addEnvironment(
1149
+ "OPENHI_WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS",
1150
+ String(options.defaultTtlSeconds)
1151
+ );
1152
+ }
1153
+ fn.addToRolePolicy(
1154
+ new PolicyStatement({
1155
+ effect: Effect.ALLOW,
1156
+ actions: [
1157
+ "dynamodb:PutItem",
1158
+ "dynamodb:UpdateItem",
1159
+ "dynamodb:GetItem",
1160
+ "dynamodb:Query"
1161
+ ],
1162
+ resources: [this.table.tableArn],
1163
+ conditions: {
1164
+ "ForAllValues:StringEquals": {
1165
+ "dynamodb:LeadingKeys": [consumerName]
1166
+ }
1167
+ }
1168
+ })
1169
+ );
1170
+ }
1171
+ assertConsumerName(consumerName) {
1172
+ _WorkflowDedupTable.assertConsumerNameStatic(consumerName);
1173
+ }
1174
+ };
1175
+ /** SSM param name (short) used by `DiscoverableStringParameter` for the table name lookup. */
1176
+ _WorkflowDedupTable.TABLE_NAME_SSM_PARAM_NAME = "workflow-dedup-table-name";
1177
+ /** SSM param name (short) used by `DiscoverableStringParameter` for the table ARN lookup. */
1178
+ _WorkflowDedupTable.TABLE_ARN_SSM_PARAM_NAME = "workflow-dedup-table-arn";
1179
+ /**
1180
+ * Service-type the publishing stack runs under. The cross-stack lookups
1181
+ * pin to this value so consumer stacks on a different service-type
1182
+ * (e.g. `data`, `auth`) resolve the parameter at the publisher's SSM
1183
+ * path instead of their own. Typed against `OpenHiServiceType` so a
1184
+ * future rename of the literal triggers a compile error; not pulled
1185
+ * from `OpenHiGlobalService.SERVICE_TYPE` because
1186
+ * `OpenHiGlobalService` already imports `WorkflowDedupTable` — a
1187
+ * back-import would create a circular dependency.
1188
+ */
1189
+ _WorkflowDedupTable.PUBLISHER_SERVICE_TYPE = "global";
1190
+ var WorkflowDedupTable = _WorkflowDedupTable;
1191
+ var WorkflowDedupTableDuplicateError = class extends Error {
1192
+ /** @param message - human-readable description of the duplicate. */
1193
+ constructor(message) {
1194
+ super(message);
1195
+ this.name = "WorkflowDedupTableDuplicateError";
1196
+ }
1197
+ };
1198
+ var WorkflowDedupConsumerNameInvalidError = class extends Error {
1199
+ /** @param message - human-readable description of the invariant violation. */
1200
+ constructor(message) {
1201
+ super(message);
1202
+ this.name = "WorkflowDedupConsumerNameInvalidError";
1203
+ }
1204
+ };
1205
+
946
1206
  // src/components/event-bridge/data-event-bus.ts
947
1207
  import { EventBus } from "aws-cdk-lib/aws-events";
948
1208
  var DataEventBus = class _DataEventBus extends EventBus {
@@ -1018,7 +1278,7 @@ import { Runtime as Runtime5, StartingPosition } from "aws-cdk-lib/aws-lambda";
1018
1278
  import { KinesisEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
1019
1279
  import { NodejsFunction as NodejsFunction5 } from "aws-cdk-lib/aws-lambda-nodejs";
1020
1280
  import * as rds from "aws-cdk-lib/aws-rds";
1021
- import { Construct as Construct5 } from "constructs";
1281
+ import { Construct as Construct6 } from "constructs";
1022
1282
  var HANDLER_NAME5 = "data-store-postgres-replication.handler.js";
1023
1283
  var DEFAULT_DATABASE_NAME = "openhi";
1024
1284
  var SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;
@@ -1041,7 +1301,7 @@ function getPostgresReplicaSchemaName(branchHash) {
1041
1301
  }
1042
1302
  return candidate;
1043
1303
  }
1044
- var DataStorePostgresReplica = class extends Construct5 {
1304
+ var DataStorePostgresReplica = class extends Construct6 {
1045
1305
  /**
1046
1306
  * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.
1047
1307
  * Use from any stack that needs to grant `rds-data:ExecuteStatement` against
@@ -1196,8 +1456,8 @@ var ChildHostedZone = class extends HostedZone {
1196
1456
  ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
1197
1457
 
1198
1458
  // src/components/route-53/root-hosted-zone.ts
1199
- import { Construct as Construct6 } from "constructs";
1200
- var RootHostedZone = class extends Construct6 {
1459
+ import { Construct as Construct7 } from "constructs";
1460
+ var RootHostedZone = class extends Construct7 {
1201
1461
  };
1202
1462
 
1203
1463
  // src/components/static-hosting/static-hosting.ts
@@ -1208,9 +1468,9 @@ import {
1208
1468
  import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
1209
1469
  import { Bucket as Bucket2 } from "aws-cdk-lib/aws-s3";
1210
1470
  import { Duration as Duration5 } from "aws-cdk-lib/core";
1211
- import { Construct as Construct7 } from "constructs";
1471
+ import { Construct as Construct8 } from "constructs";
1212
1472
  var STATIC_HOSTING_SERVICE_TYPE = "website";
1213
- var _StaticHosting = class _StaticHosting extends Construct7 {
1473
+ var _StaticHosting = class _StaticHosting extends Construct8 {
1214
1474
  constructor(scope, id, props = {}) {
1215
1475
  super(scope, id);
1216
1476
  const stack = OpenHiService.of(scope);
@@ -1262,7 +1522,7 @@ _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN = "STATIC_HOSTING_DISTRIBUTION_AR
1262
1522
  var StaticHosting = _StaticHosting;
1263
1523
 
1264
1524
  // src/services/open-hi-auth-service.ts
1265
- var import_config4 = __toESM(require_lib());
1525
+ var import_config5 = __toESM(require_lib2());
1266
1526
  import {
1267
1527
  LambdaVersion,
1268
1528
  UserPool as UserPool2,
@@ -1270,12 +1530,13 @@ import {
1270
1530
  UserPoolDomain as UserPoolDomain2,
1271
1531
  UserPoolOperation
1272
1532
  } from "aws-cdk-lib/aws-cognito";
1273
- import { Effect as Effect2, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1533
+ import { Effect as Effect6, PolicyStatement as PolicyStatement6 } from "aws-cdk-lib/aws-iam";
1274
1534
  import { Key as Key2 } from "aws-cdk-lib/aws-kms";
1275
- import { Stack as Stack3 } from "aws-cdk-lib/core";
1535
+ import { Stack as Stack6 } from "aws-cdk-lib/core";
1276
1536
 
1277
1537
  // src/services/open-hi-data-service.ts
1278
- import { StreamViewType, Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
1538
+ var import_config4 = __toESM(require_lib2());
1539
+ import { StreamViewType, Table as Table3 } from "aws-cdk-lib/aws-dynamodb";
1279
1540
  import * as kinesis from "aws-cdk-lib/aws-kinesis";
1280
1541
 
1281
1542
  // src/services/open-hi-global-service.ts
@@ -1288,6 +1549,94 @@ import {
1288
1549
  HostedZone as HostedZone2
1289
1550
  } from "aws-cdk-lib/aws-route53";
1290
1551
  import { StringParameter as StringParameter3 } from "aws-cdk-lib/aws-ssm";
1552
+
1553
+ // src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge.ts
1554
+ import { Construct as Construct10 } from "constructs";
1555
+
1556
+ // src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge-lambda.ts
1557
+ import fs6 from "fs";
1558
+ import path6 from "path";
1559
+ import { Duration as Duration6, Stack as Stack3 } from "aws-cdk-lib";
1560
+ import { Rule } from "aws-cdk-lib/aws-events";
1561
+ import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
1562
+ import { Effect as Effect2, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1563
+ import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1564
+ import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1565
+ import { Construct as Construct9 } from "constructs";
1566
+ var HANDLER_NAME6 = "platform-deploy-bridge.handler.js";
1567
+ function resolveHandlerEntry6(dirname) {
1568
+ const sameDir = path6.join(dirname, HANDLER_NAME6);
1569
+ if (fs6.existsSync(sameDir)) {
1570
+ return sameDir;
1571
+ }
1572
+ return path6.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME6);
1573
+ }
1574
+ var PlatformDeployBridgeLambda = class extends Construct9 {
1575
+ constructor(scope, props) {
1576
+ super(scope, "platform-deploy-bridge-lambda");
1577
+ const service = OpenHiService.of(this);
1578
+ const repoTagKey = openHiTagKey(
1579
+ service.appName,
1580
+ OPENHI_TAG_SUFFIX_REPO_NAME
1581
+ );
1582
+ const tagKeyPrefix = `${service.appName}:`;
1583
+ const ownStackName = Stack3.of(this).stackName;
1584
+ const ownSuffix = `-${service.serviceId}-${Stack3.of(this).account}-${Stack3.of(this).region}`;
1585
+ const sharedPrefix = ownStackName.endsWith(ownSuffix) ? ownStackName.slice(0, -ownSuffix.length) : service.branchHash;
1586
+ const stackIdPrefix = `arn:aws:cloudformation:${Stack3.of(this).region}:${Stack3.of(this).account}:stack/${sharedPrefix}-`;
1587
+ this.lambda = new NodejsFunction6(this, "handler", {
1588
+ entry: resolveHandlerEntry6(__dirname),
1589
+ runtime: Runtime6.NODEJS_LATEST,
1590
+ memorySize: 256,
1591
+ timeout: Duration6.seconds(30),
1592
+ environment: {
1593
+ [CONTROL_EVENT_BUS_NAME_ENV_VAR]: props.controlEventBus.eventBusName,
1594
+ [OPENHI_REPO_TAG_KEY_ENV_VAR]: repoTagKey,
1595
+ [OPENHI_TAG_KEY_PREFIX_ENV_VAR]: tagKeyPrefix
1596
+ }
1597
+ });
1598
+ this.lambda.addToRolePolicy(
1599
+ new PolicyStatement2({
1600
+ effect: Effect2.ALLOW,
1601
+ actions: ["cloudformation:DescribeStacks"],
1602
+ resources: [
1603
+ `arn:aws:cloudformation:${Stack3.of(this).region}:${Stack3.of(this).account}:stack/*`
1604
+ ]
1605
+ })
1606
+ );
1607
+ props.controlEventBus.grantPutEventsTo(this.lambda);
1608
+ this.rule = new Rule(this, "rule", {
1609
+ eventPattern: {
1610
+ source: [CLOUDFORMATION_EVENT_SOURCE],
1611
+ detailType: [CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE],
1612
+ detail: {
1613
+ "stack-id": [{ prefix: stackIdPrefix }],
1614
+ "status-details": {
1615
+ status: [...BRIDGED_STATUSES]
1616
+ }
1617
+ }
1618
+ },
1619
+ targets: [
1620
+ new LambdaFunction(this.lambda, {
1621
+ retryAttempts: 2,
1622
+ maxEventAge: Duration6.hours(2)
1623
+ })
1624
+ ]
1625
+ });
1626
+ }
1627
+ };
1628
+
1629
+ // src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge.ts
1630
+ var PlatformDeployBridge = class extends Construct10 {
1631
+ constructor(scope, props) {
1632
+ super(scope, "platform-deploy-bridge");
1633
+ this.bridgeLambda = new PlatformDeployBridgeLambda(this, {
1634
+ controlEventBus: props.controlEventBus
1635
+ });
1636
+ }
1637
+ };
1638
+
1639
+ // src/services/open-hi-global-service.ts
1291
1640
  var _OpenHiGlobalService = class _OpenHiGlobalService extends OpenHiService {
1292
1641
  /**
1293
1642
  * Returns an IHostedZone from the given attributes (no SSM). Use when the zone is imported from config.
@@ -1352,6 +1701,17 @@ var _OpenHiGlobalService = class _OpenHiGlobalService extends OpenHiService {
1352
1701
  ControlEventBus.getEventBusName(scope)
1353
1702
  );
1354
1703
  }
1704
+ /**
1705
+ * Returns the workflow dedup table by name (deterministic per branch).
1706
+ * Use from other stacks to obtain an ITable reference. Consumer Lambdas
1707
+ * are typically wired via `WorkflowDedupTable.grantConsumer(fn, name)`
1708
+ * on the owning service's `workflowDedupTable` reference; the
1709
+ * `tableNameFromLookup` / `tableArnFromLookup` SSM helpers on the
1710
+ * construct cover cross-stack consumers that need only the name/ARN.
1711
+ */
1712
+ static workflowDedupTableNameFromLookup(scope) {
1713
+ return WorkflowDedupTable.tableNameFromLookup(scope);
1714
+ }
1355
1715
  get serviceType() {
1356
1716
  return _OpenHiGlobalService.SERVICE_TYPE;
1357
1717
  }
@@ -1365,6 +1725,8 @@ var _OpenHiGlobalService = class _OpenHiGlobalService extends OpenHiService {
1365
1725
  this.dataEventBus = this.createDataEventBus();
1366
1726
  this.opsEventBus = this.createOpsEventBus();
1367
1727
  this.controlEventBus = this.createControlEventBus();
1728
+ this.workflowDedupTable = this.createWorkflowDedupTable();
1729
+ this.platformDeployBridge = this.createPlatformDeployBridge();
1368
1730
  }
1369
1731
  /**
1370
1732
  * Validates that config required for the Global stack is present.
@@ -1436,23 +1798,240 @@ var _OpenHiGlobalService = class _OpenHiGlobalService extends OpenHiService {
1436
1798
  createControlEventBus() {
1437
1799
  return new ControlEventBus(this);
1438
1800
  }
1801
+ /**
1802
+ * Creates the platform deploy bridge that republishes CloudFormation
1803
+ * Stack Status Change events onto the control event bus.
1804
+ * Override to customize.
1805
+ */
1806
+ createPlatformDeployBridge() {
1807
+ return new PlatformDeployBridge(this, {
1808
+ controlEventBus: this.controlEventBus
1809
+ });
1810
+ }
1811
+ /**
1812
+ * Creates the shared workflow dedup table (TR-015 singleton).
1813
+ * Override to customize.
1814
+ */
1815
+ createWorkflowDedupTable() {
1816
+ return new WorkflowDedupTable(this, "workflow-dedup-table");
1817
+ }
1439
1818
  };
1440
1819
  _OpenHiGlobalService.SERVICE_TYPE = "global";
1441
1820
  var OpenHiGlobalService = _OpenHiGlobalService;
1442
1821
 
1443
- // src/services/open-hi-data-service.ts
1444
- var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1445
- /**
1446
- * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
1447
- */
1448
- static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1449
- return Table2.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1822
+ // src/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.ts
1823
+ import fs7 from "fs";
1824
+ import path7 from "path";
1825
+ import { PLATFORM_ROLE_IDS } from "@openhi/types";
1826
+ import { Duration as Duration7, Stack as Stack4 } from "aws-cdk-lib";
1827
+ import { Rule as Rule2 } from "aws-cdk-lib/aws-events";
1828
+ import { LambdaFunction as LambdaFunction2 } from "aws-cdk-lib/aws-events-targets";
1829
+ import { Effect as Effect3, PolicyStatement as PolicyStatement3 } from "aws-cdk-lib/aws-iam";
1830
+ import { Runtime as Runtime7 } from "aws-cdk-lib/aws-lambda";
1831
+ import { NodejsFunction as NodejsFunction7 } from "aws-cdk-lib/aws-lambda-nodejs";
1832
+ import { Construct as Construct11 } from "constructs";
1833
+ var HANDLER_NAME7 = "seed-demo-data.handler.js";
1834
+ function resolveHandlerEntry7(dirname) {
1835
+ const sameDir = path7.join(dirname, HANDLER_NAME7);
1836
+ if (fs7.existsSync(sameDir)) {
1837
+ return sameDir;
1450
1838
  }
1451
- get serviceType() {
1452
- return _OpenHiDataService.SERVICE_TYPE;
1839
+ return path7.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME7);
1840
+ }
1841
+ var SeedDemoDataLambda = class extends Construct11 {
1842
+ constructor(scope, props) {
1843
+ super(scope, "seed-demo-data-lambda");
1844
+ this.lambda = new NodejsFunction7(this, "handler", {
1845
+ entry: resolveHandlerEntry7(__dirname),
1846
+ runtime: Runtime7.NODEJS_LATEST,
1847
+ memorySize: 512,
1848
+ timeout: Duration7.minutes(2),
1849
+ environment: {
1850
+ DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
1851
+ [SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR]: props.userPool.userPoolId
1852
+ }
1853
+ });
1854
+ const roleReadKeys = Object.values(PLATFORM_ROLE_IDS).map(rolePartitionKey);
1855
+ this.lambda.addToRolePolicy(
1856
+ new PolicyStatement3({
1857
+ effect: Effect3.ALLOW,
1858
+ actions: ["dynamodb:GetItem"],
1859
+ resources: [props.dataStoreTable.tableArn],
1860
+ conditions: {
1861
+ "ForAllValues:StringEquals": {
1862
+ "dynamodb:LeadingKeys": roleReadKeys
1863
+ }
1864
+ }
1865
+ })
1866
+ );
1867
+ const writeKeys = [
1868
+ ...demoBasePartitionKeys(),
1869
+ ...demoDevUserPartitionKeys(DEV_USERS)
1870
+ ];
1871
+ this.lambda.addToRolePolicy(
1872
+ new PolicyStatement3({
1873
+ effect: Effect3.ALLOW,
1874
+ actions: ["dynamodb:PutItem", "dynamodb:UpdateItem"],
1875
+ resources: [props.dataStoreTable.tableArn],
1876
+ conditions: {
1877
+ "ForAllValues:StringEquals": {
1878
+ "dynamodb:LeadingKeys": writeKeys
1879
+ }
1880
+ }
1881
+ })
1882
+ );
1883
+ this.lambda.addToRolePolicy(
1884
+ new PolicyStatement3({
1885
+ effect: Effect3.ALLOW,
1886
+ actions: [
1887
+ "cognito-idp:AdminCreateUser",
1888
+ "cognito-idp:AdminGetUser",
1889
+ "cognito-idp:AdminSetUserPassword"
1890
+ ],
1891
+ resources: [
1892
+ Stack4.of(this).formatArn({
1893
+ service: "cognito-idp",
1894
+ resource: "userpool",
1895
+ resourceName: props.userPool.userPoolId
1896
+ })
1897
+ ]
1898
+ })
1899
+ );
1900
+ this.rule = new Rule2(this, "rule", {
1901
+ eventBus: props.controlEventBus,
1902
+ eventPattern: {
1903
+ source: [import_workflows.PlatformSystemDataSeededV1.source],
1904
+ detailType: [import_workflows.PlatformSystemDataSeededV1.detailType]
1905
+ },
1906
+ targets: [
1907
+ new LambdaFunction2(this.lambda, {
1908
+ retryAttempts: 2,
1909
+ maxEventAge: Duration7.hours(2)
1910
+ })
1911
+ ]
1912
+ });
1913
+ }
1914
+ };
1915
+
1916
+ // src/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.ts
1917
+ import { Construct as Construct12 } from "constructs";
1918
+ var SeedDemoDataWorkflow = class extends Construct12 {
1919
+ constructor(scope, props) {
1920
+ super(scope, "seed-demo-data-workflow");
1921
+ this.seedDemoData = new SeedDemoDataLambda(this, {
1922
+ controlEventBus: props.controlEventBus,
1923
+ dataStoreTable: props.dataStoreTable,
1924
+ userPool: props.userPool
1925
+ });
1926
+ WorkflowDedupTable.grantConsumerFromLookup(
1927
+ this,
1928
+ this.seedDemoData.lambda,
1929
+ SEED_DEMO_DATA_CONSUMER_NAME
1930
+ );
1931
+ }
1932
+ };
1933
+
1934
+ // src/workflows/control-plane/seed-system-data/seed-system-data-lambda.ts
1935
+ import fs8 from "fs";
1936
+ import path8 from "path";
1937
+ import { PLATFORM_ROLE_IDS as PLATFORM_ROLE_IDS2 } from "@openhi/types";
1938
+ import { Duration as Duration8, Stack as Stack5 } from "aws-cdk-lib";
1939
+ import { Rule as Rule3 } from "aws-cdk-lib/aws-events";
1940
+ import { LambdaFunction as LambdaFunction3 } from "aws-cdk-lib/aws-events-targets";
1941
+ import { Effect as Effect4, PolicyStatement as PolicyStatement4 } from "aws-cdk-lib/aws-iam";
1942
+ import { Runtime as Runtime8 } from "aws-cdk-lib/aws-lambda";
1943
+ import { NodejsFunction as NodejsFunction8 } from "aws-cdk-lib/aws-lambda-nodejs";
1944
+ import { Construct as Construct13 } from "constructs";
1945
+ var HANDLER_NAME8 = "seed-system-data.handler.js";
1946
+ function resolveHandlerEntry8(dirname) {
1947
+ const sameDir = path8.join(dirname, HANDLER_NAME8);
1948
+ if (fs8.existsSync(sameDir)) {
1949
+ return sameDir;
1950
+ }
1951
+ return path8.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME8);
1952
+ }
1953
+ var SeedSystemDataLambda = class extends Construct13 {
1954
+ constructor(scope, props) {
1955
+ super(scope, "seed-system-data-lambda");
1956
+ this.lambda = new NodejsFunction8(this, "handler", {
1957
+ entry: resolveHandlerEntry8(__dirname),
1958
+ runtime: Runtime8.NODEJS_LATEST,
1959
+ memorySize: 512,
1960
+ timeout: Duration8.minutes(1),
1961
+ environment: {
1962
+ DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
1963
+ [SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR]: props.controlEventBus.eventBusName
1964
+ }
1965
+ });
1966
+ const roleArns = Object.values(PLATFORM_ROLE_IDS2).map(
1967
+ (id) => `role#id#${id}`
1968
+ );
1969
+ this.lambda.addToRolePolicy(
1970
+ new PolicyStatement4({
1971
+ effect: Effect4.ALLOW,
1972
+ actions: ["dynamodb:PutItem", "dynamodb:UpdateItem"],
1973
+ resources: [props.dataStoreTable.tableArn],
1974
+ conditions: {
1975
+ "ForAllValues:StringEquals": {
1976
+ "dynamodb:LeadingKeys": roleArns
1977
+ }
1978
+ }
1979
+ })
1980
+ );
1981
+ props.controlEventBus.grantPutEventsTo(this.lambda);
1982
+ const hostStackName = Stack5.of(this).stackName;
1983
+ this.rule = new Rule3(this, "rule", {
1984
+ eventBus: props.controlEventBus,
1985
+ eventPattern: {
1986
+ source: [import_workflows2.PlatformDeploymentCompletedV1.source],
1987
+ detailType: [import_workflows2.PlatformDeploymentCompletedV1.detailType],
1988
+ detail: {
1989
+ payload: {
1990
+ stackName: [hostStackName]
1991
+ }
1992
+ }
1993
+ },
1994
+ targets: [
1995
+ new LambdaFunction3(this.lambda, {
1996
+ retryAttempts: 2,
1997
+ maxEventAge: Duration8.hours(2)
1998
+ })
1999
+ ]
2000
+ });
2001
+ }
2002
+ };
2003
+
2004
+ // src/workflows/control-plane/seed-system-data/seed-system-data-workflow.ts
2005
+ import { Construct as Construct14 } from "constructs";
2006
+ var SeedSystemDataWorkflow = class extends Construct14 {
2007
+ constructor(scope, props) {
2008
+ super(scope, "seed-system-data-workflow");
2009
+ this.seedSystemData = new SeedSystemDataLambda(this, {
2010
+ controlEventBus: props.controlEventBus,
2011
+ dataStoreTable: props.dataStoreTable
2012
+ });
2013
+ WorkflowDedupTable.grantConsumerFromLookup(
2014
+ this,
2015
+ this.seedSystemData.lambda,
2016
+ SEED_SYSTEM_DATA_CONSUMER_NAME
2017
+ );
1453
2018
  }
2019
+ };
2020
+
2021
+ // src/services/open-hi-data-service.ts
2022
+ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1454
2023
  constructor(ohEnv, props = {}) {
1455
2024
  super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
2025
+ /**
2026
+ * Cached control-event-bus lookup. `OpenHiGlobalService.controlEventBusFromConstruct`
2027
+ * registers a child `EventBus.fromEventBusName` construct with a
2028
+ * fixed id under the scope it is passed, so calling it twice on the
2029
+ * same `OpenHiDataService` instance collides. The cache mirrors the
2030
+ * `private controlEventBus()` pattern already used in
2031
+ * `OpenHiAuthService`. Use {@link controlEventBus} from this class
2032
+ * — never call the static lookup from inside `OpenHiDataService`.
2033
+ */
2034
+ this._controlEventBus = null;
1456
2035
  this.props = props;
1457
2036
  this.dataStoreChangeStream = new kinesis.Stream(
1458
2037
  this,
@@ -1487,6 +2066,53 @@ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1487
2066
  branchHash: this.branchHash
1488
2067
  }
1489
2068
  );
2069
+ this.seedSystemDataWorkflow = this.createSeedSystemDataWorkflow();
2070
+ this.seedDemoDataWorkflow = this.createSeedDemoDataWorkflow();
2071
+ }
2072
+ /**
2073
+ * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
2074
+ */
2075
+ static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
2076
+ return Table3.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
2077
+ }
2078
+ get serviceType() {
2079
+ return _OpenHiDataService.SERVICE_TYPE;
2080
+ }
2081
+ /**
2082
+ * Lazily looks up the control event bus exactly once per
2083
+ * `OpenHiDataService` instance and caches the reference. Every
2084
+ * workflow that consumes the bus must read it through this method
2085
+ * — see {@link _controlEventBus} for the underlying collision risk.
2086
+ */
2087
+ controlEventBus() {
2088
+ if (this._controlEventBus === null) {
2089
+ this._controlEventBus = OpenHiGlobalService.controlEventBusFromConstruct(this);
2090
+ }
2091
+ return this._controlEventBus;
2092
+ }
2093
+ /**
2094
+ * Creates the seed-system-data workflow. Override to customize.
2095
+ */
2096
+ createSeedSystemDataWorkflow() {
2097
+ return new SeedSystemDataWorkflow(this, {
2098
+ controlEventBus: this.controlEventBus(),
2099
+ dataStoreTable: this.dataStore
2100
+ });
2101
+ }
2102
+ /**
2103
+ * Creates the seed-demo-data workflow — but only on non-prod
2104
+ * stages. Returns `undefined` on prod so the workflow literally
2105
+ * does not exist in prod stacks. Override to customize.
2106
+ */
2107
+ createSeedDemoDataWorkflow() {
2108
+ if (this.ohEnv.ohStage.stageType === import_config4.OPEN_HI_STAGE.PROD) {
2109
+ return void 0;
2110
+ }
2111
+ return new SeedDemoDataWorkflow(this, {
2112
+ controlEventBus: this.controlEventBus(),
2113
+ dataStoreTable: this.dataStore,
2114
+ userPool: OpenHiAuthService.userPoolFromConstruct(this)
2115
+ });
1490
2116
  }
1491
2117
  /**
1492
2118
  * Creates the single-table DynamoDB data store.
@@ -1503,29 +2129,29 @@ _OpenHiDataService.SERVICE_TYPE = "data";
1503
2129
  var OpenHiDataService = _OpenHiDataService;
1504
2130
 
1505
2131
  // src/workflows/control-plane/user-onboarding/provision-default-workspace-lambda.ts
1506
- import fs6 from "fs";
1507
- import path6 from "path";
1508
- import { Duration as Duration6 } from "aws-cdk-lib";
1509
- import { Rule } from "aws-cdk-lib/aws-events";
1510
- import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
1511
- import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
1512
- import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1513
- import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1514
- import { Construct as Construct8 } from "constructs";
1515
- var HANDLER_NAME6 = "provision-default-workspace.handler.js";
1516
- function resolveHandlerEntry6(dirname) {
1517
- const sameDir = path6.join(dirname, HANDLER_NAME6);
1518
- if (fs6.existsSync(sameDir)) {
2132
+ import fs9 from "fs";
2133
+ import path9 from "path";
2134
+ import { Duration as Duration9 } from "aws-cdk-lib";
2135
+ import { Rule as Rule4 } from "aws-cdk-lib/aws-events";
2136
+ import { LambdaFunction as LambdaFunction4 } from "aws-cdk-lib/aws-events-targets";
2137
+ import { Effect as Effect5, PolicyStatement as PolicyStatement5 } from "aws-cdk-lib/aws-iam";
2138
+ import { Runtime as Runtime9 } from "aws-cdk-lib/aws-lambda";
2139
+ import { NodejsFunction as NodejsFunction9 } from "aws-cdk-lib/aws-lambda-nodejs";
2140
+ import { Construct as Construct15 } from "constructs";
2141
+ var HANDLER_NAME9 = "provision-default-workspace.handler.js";
2142
+ function resolveHandlerEntry9(dirname) {
2143
+ const sameDir = path9.join(dirname, HANDLER_NAME9);
2144
+ if (fs9.existsSync(sameDir)) {
1519
2145
  return sameDir;
1520
2146
  }
1521
- return path6.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME6);
2147
+ return path9.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME9);
1522
2148
  }
1523
- var ProvisionDefaultWorkspaceLambda = class extends Construct8 {
2149
+ var ProvisionDefaultWorkspaceLambda = class extends Construct15 {
1524
2150
  constructor(scope, props) {
1525
2151
  super(scope, "provision-default-workspace-lambda");
1526
- this.lambda = new NodejsFunction6(this, "handler", {
1527
- entry: resolveHandlerEntry6(__dirname),
1528
- runtime: Runtime6.NODEJS_LATEST,
2152
+ this.lambda = new NodejsFunction9(this, "handler", {
2153
+ entry: resolveHandlerEntry9(__dirname),
2154
+ runtime: Runtime9.NODEJS_LATEST,
1529
2155
  memorySize: 1024,
1530
2156
  environment: {
1531
2157
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
@@ -1537,22 +2163,22 @@ var ProvisionDefaultWorkspaceLambda = class extends Construct8 {
1537
2163
  "dynamodb:UpdateItem"
1538
2164
  );
1539
2165
  this.lambda.addToRolePolicy(
1540
- new PolicyStatement({
1541
- effect: Effect.ALLOW,
2166
+ new PolicyStatement5({
2167
+ effect: Effect5.ALLOW,
1542
2168
  actions: ["dynamodb:Query"],
1543
2169
  resources: [`${props.dataStoreTable.tableArn}/index/*`]
1544
2170
  })
1545
2171
  );
1546
- this.rule = new Rule(this, "rule", {
2172
+ this.rule = new Rule4(this, "rule", {
1547
2173
  eventBus: props.controlEventBus,
1548
2174
  eventPattern: {
1549
2175
  source: [USER_ONBOARDING_EVENT_SOURCE],
1550
2176
  detailType: [PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE]
1551
2177
  },
1552
2178
  targets: [
1553
- new LambdaFunction(this.lambda, {
2179
+ new LambdaFunction4(this.lambda, {
1554
2180
  retryAttempts: 2,
1555
- maxEventAge: Duration6.hours(2)
2181
+ maxEventAge: Duration9.hours(2)
1556
2182
  })
1557
2183
  ]
1558
2184
  });
@@ -1560,8 +2186,8 @@ var ProvisionDefaultWorkspaceLambda = class extends Construct8 {
1560
2186
  };
1561
2187
 
1562
2188
  // src/workflows/control-plane/user-onboarding/user-onboarding-workflow.ts
1563
- import { Construct as Construct9 } from "constructs";
1564
- var UserOnboardingWorkflow = class extends Construct9 {
2189
+ import { Construct as Construct16 } from "constructs";
2190
+ var UserOnboardingWorkflow = class extends Construct16 {
1565
2191
  constructor(scope, props) {
1566
2192
  super(scope, "user-onboarding-workflow");
1567
2193
  this.provisionDefaultWorkspace = new ProvisionDefaultWorkspaceLambda(this, {
@@ -1776,8 +2402,8 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1776
2402
  const dynamoActions = ["dynamodb:GetItem", "dynamodb:Query"];
1777
2403
  dataStoreTable.grant(this.preTokenGenerationLambda, ...dynamoActions);
1778
2404
  this.preTokenGenerationLambda.addToRolePolicy(
1779
- new PolicyStatement2({
1780
- effect: Effect2.ALLOW,
2405
+ new PolicyStatement6({
2406
+ effect: Effect6.ALLOW,
1781
2407
  actions: [...dynamoActions],
1782
2408
  resources: [`${dataStoreTable.tableArn}/index/*`]
1783
2409
  })
@@ -1798,10 +2424,10 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1798
2424
  */
1799
2425
  grantPostAuthenticationPermissions() {
1800
2426
  this.postAuthenticationLambda.addToRolePolicy(
1801
- new PolicyStatement2({
2427
+ new PolicyStatement6({
1802
2428
  actions: ["cognito-idp:AdminUserGlobalSignOut"],
1803
2429
  resources: [
1804
- Stack3.of(this).formatArn({
2430
+ Stack6.of(this).formatArn({
1805
2431
  service: "cognito-idp",
1806
2432
  resource: "userpool",
1807
2433
  resourceName: "*"
@@ -1845,7 +2471,7 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1845
2471
  * via env vars to drive `InitiateAuth`.
1846
2472
  */
1847
2473
  createFixtureSeederClient() {
1848
- if (this.ohEnv.ohStage.stageType === import_config4.OPEN_HI_STAGE.PROD) {
2474
+ if (this.ohEnv.ohStage.stageType === import_config5.OPEN_HI_STAGE.PROD) {
1849
2475
  return void 0;
1850
2476
  }
1851
2477
  const client = new CognitoFixtureSeederClient(this, {
@@ -1882,7 +2508,7 @@ _OpenHiAuthService.SERVICE_TYPE = "auth";
1882
2508
  var OpenHiAuthService = _OpenHiAuthService;
1883
2509
 
1884
2510
  // src/services/open-hi-rest-api-service.ts
1885
- var import_config5 = __toESM(require_lib());
2511
+ var import_config6 = __toESM(require_lib2());
1886
2512
  import {
1887
2513
  CorsHttpMethod,
1888
2514
  DomainName,
@@ -1894,62 +2520,62 @@ import {
1894
2520
  } from "aws-cdk-lib/aws-apigatewayv2";
1895
2521
  import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers";
1896
2522
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
1897
- import { Effect as Effect3, PolicyStatement as PolicyStatement3 } from "aws-cdk-lib/aws-iam";
2523
+ import { Effect as Effect7, PolicyStatement as PolicyStatement7 } from "aws-cdk-lib/aws-iam";
1898
2524
  import {
1899
2525
  ARecord,
1900
2526
  HostedZone as HostedZone3,
1901
2527
  RecordTarget
1902
2528
  } from "aws-cdk-lib/aws-route53";
1903
2529
  import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
1904
- import { Duration as Duration7 } from "aws-cdk-lib/core";
2530
+ import { Duration as Duration10 } from "aws-cdk-lib/core";
1905
2531
 
1906
2532
  // src/data/lambda/cors-options-lambda.ts
1907
- import fs7 from "fs";
1908
- import path7 from "path";
1909
- import { Runtime as Runtime7 } from "aws-cdk-lib/aws-lambda";
1910
- import { NodejsFunction as NodejsFunction7 } from "aws-cdk-lib/aws-lambda-nodejs";
1911
- import { Construct as Construct10 } from "constructs";
1912
- var HANDLER_NAME7 = "cors-options-lambda.handler.js";
1913
- function resolveHandlerEntry7(dirname) {
1914
- const sameDir = path7.join(dirname, HANDLER_NAME7);
1915
- if (fs7.existsSync(sameDir)) {
2533
+ import fs10 from "fs";
2534
+ import path10 from "path";
2535
+ import { Runtime as Runtime10 } from "aws-cdk-lib/aws-lambda";
2536
+ import { NodejsFunction as NodejsFunction10 } from "aws-cdk-lib/aws-lambda-nodejs";
2537
+ import { Construct as Construct17 } from "constructs";
2538
+ var HANDLER_NAME10 = "cors-options-lambda.handler.js";
2539
+ function resolveHandlerEntry10(dirname) {
2540
+ const sameDir = path10.join(dirname, HANDLER_NAME10);
2541
+ if (fs10.existsSync(sameDir)) {
1916
2542
  return sameDir;
1917
2543
  }
1918
- const fromLib = path7.join(dirname, "..", "..", "..", "lib", HANDLER_NAME7);
2544
+ const fromLib = path10.join(dirname, "..", "..", "..", "lib", HANDLER_NAME10);
1919
2545
  return fromLib;
1920
2546
  }
1921
- var CorsOptionsLambda = class extends Construct10 {
2547
+ var CorsOptionsLambda = class extends Construct17 {
1922
2548
  constructor(scope, id = "cors-options-lambda") {
1923
2549
  super(scope, id);
1924
- this.lambda = new NodejsFunction7(this, "handler", {
1925
- entry: resolveHandlerEntry7(__dirname),
1926
- runtime: Runtime7.NODEJS_LATEST,
2550
+ this.lambda = new NodejsFunction10(this, "handler", {
2551
+ entry: resolveHandlerEntry10(__dirname),
2552
+ runtime: Runtime10.NODEJS_LATEST,
1927
2553
  memorySize: 128
1928
2554
  });
1929
2555
  }
1930
2556
  };
1931
2557
 
1932
2558
  // src/data/lambda/rest-api-lambda.ts
1933
- import fs8 from "fs";
1934
- import path8 from "path";
1935
- import { Runtime as Runtime8 } from "aws-cdk-lib/aws-lambda";
1936
- import { NodejsFunction as NodejsFunction8 } from "aws-cdk-lib/aws-lambda-nodejs";
1937
- import { Construct as Construct11 } from "constructs";
1938
- var HANDLER_NAME8 = "rest-api-lambda.handler.js";
1939
- function resolveHandlerEntry8(dirname) {
1940
- const sameDir = path8.join(dirname, HANDLER_NAME8);
1941
- if (fs8.existsSync(sameDir)) {
2559
+ import fs11 from "fs";
2560
+ import path11 from "path";
2561
+ import { Runtime as Runtime11 } from "aws-cdk-lib/aws-lambda";
2562
+ import { NodejsFunction as NodejsFunction11 } from "aws-cdk-lib/aws-lambda-nodejs";
2563
+ import { Construct as Construct18 } from "constructs";
2564
+ var HANDLER_NAME11 = "rest-api-lambda.handler.js";
2565
+ function resolveHandlerEntry11(dirname) {
2566
+ const sameDir = path11.join(dirname, HANDLER_NAME11);
2567
+ if (fs11.existsSync(sameDir)) {
1942
2568
  return sameDir;
1943
2569
  }
1944
- const fromLib = path8.join(dirname, "..", "..", "..", "lib", HANDLER_NAME8);
2570
+ const fromLib = path11.join(dirname, "..", "..", "..", "lib", HANDLER_NAME11);
1945
2571
  return fromLib;
1946
2572
  }
1947
- var RestApiLambda = class extends Construct11 {
2573
+ var RestApiLambda = class extends Construct18 {
1948
2574
  constructor(scope, props) {
1949
2575
  super(scope, "rest-api-lambda");
1950
- this.lambda = new NodejsFunction8(this, "handler", {
1951
- entry: resolveHandlerEntry8(__dirname),
1952
- runtime: Runtime8.NODEJS_LATEST,
2576
+ this.lambda = new NodejsFunction11(this, "handler", {
2577
+ entry: resolveHandlerEntry11(__dirname),
2578
+ runtime: Runtime11.NODEJS_LATEST,
1953
2579
  memorySize: 1024,
1954
2580
  environment: {
1955
2581
  DYNAMO_TABLE_NAME: props.dynamoTableName,
@@ -2091,8 +2717,8 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2091
2717
  postgresSchema
2092
2718
  });
2093
2719
  lambda.addToRolePolicy(
2094
- new PolicyStatement3({
2095
- effect: Effect3.ALLOW,
2720
+ new PolicyStatement7({
2721
+ effect: Effect7.ALLOW,
2096
2722
  actions: [
2097
2723
  "rds-data:ExecuteStatement",
2098
2724
  "rds-data:BatchExecuteStatement"
@@ -2101,8 +2727,8 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2101
2727
  })
2102
2728
  );
2103
2729
  lambda.addToRolePolicy(
2104
- new PolicyStatement3({
2105
- effect: Effect3.ALLOW,
2730
+ new PolicyStatement7({
2731
+ effect: Effect7.ALLOW,
2106
2732
  actions: ["secretsmanager:GetSecretValue"],
2107
2733
  resources: [postgresSecretArn]
2108
2734
  })
@@ -2120,15 +2746,15 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2120
2746
  ];
2121
2747
  dataStoreTable.grant(lambda, ...dynamoActions);
2122
2748
  lambda.addToRolePolicy(
2123
- new PolicyStatement3({
2124
- effect: Effect3.ALLOW,
2749
+ new PolicyStatement7({
2750
+ effect: Effect7.ALLOW,
2125
2751
  actions: [...dynamoActions],
2126
2752
  resources: [`${dataStoreTable.tableArn}/index/*`]
2127
2753
  })
2128
2754
  );
2129
2755
  lambda.addToRolePolicy(
2130
- new PolicyStatement3({
2131
- effect: Effect3.ALLOW,
2756
+ new PolicyStatement7({
2757
+ effect: Effect7.ALLOW,
2132
2758
  actions: [
2133
2759
  "ssm:GetParameter",
2134
2760
  "ssm:GetParameters",
@@ -2187,7 +2813,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2187
2813
  const userPool = OpenHiAuthService.userPoolFromConstruct(this);
2188
2814
  const userPoolClient = OpenHiAuthService.userPoolClientFromConstruct(this);
2189
2815
  const userPoolClients = [userPoolClient];
2190
- if (this.ohEnv.ohStage.stageType !== import_config5.OPEN_HI_STAGE.PROD) {
2816
+ if (this.ohEnv.ohStage.stageType !== import_config6.OPEN_HI_STAGE.PROD) {
2191
2817
  userPoolClients.push(
2192
2818
  OpenHiAuthService.fixtureSeederClientFromConstruct(this)
2193
2819
  );
@@ -2214,7 +2840,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2214
2840
  "Authorization"
2215
2841
  ],
2216
2842
  allowCredentials: cors.allowCredentials ?? true,
2217
- maxAge: cors.maxAge ?? Duration7.days(1),
2843
+ maxAge: cors.maxAge ?? Duration10.days(1),
2218
2844
  ...cors.exposeHeaders !== void 0 && {
2219
2845
  exposeHeaders: cors.exposeHeaders
2220
2846
  }
@@ -2278,7 +2904,12 @@ var _OpenHiGraphqlService = class _OpenHiGraphqlService extends OpenHiService {
2278
2904
  };
2279
2905
  _OpenHiGraphqlService.SERVICE_TYPE = "graphql-api";
2280
2906
  var OpenHiGraphqlService = _OpenHiGraphqlService;
2907
+ var export_PlatformDeploymentCompletedV1 = import_workflows2.PlatformDeploymentCompletedV1;
2281
2908
  export {
2909
+ BRIDGED_STATUSES,
2910
+ CLOUDFORMATION_EVENT_SOURCE,
2911
+ CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE,
2912
+ CONTROL_EVENT_BUS_NAME_ENV_VAR,
2282
2913
  ChildHostedZone,
2283
2914
  CognitoFixtureSeederClient,
2284
2915
  CognitoUserPool,
@@ -2289,11 +2920,22 @@ export {
2289
2920
  DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES,
2290
2921
  DATA_STORE_CHANGE_DETAIL_TYPE,
2291
2922
  DATA_STORE_CHANGE_EVENT_SOURCE,
2923
+ DEMO_PERIOD,
2924
+ DEMO_TENANT_SPECS,
2925
+ DEMO_URN_SYSTEM,
2926
+ DEV_USERS,
2292
2927
  DataEventBus,
2293
2928
  DataStoreHistoricalArchive,
2294
2929
  DataStorePostgresReplica,
2295
2930
  DiscoverableStringParameter,
2296
2931
  DynamoDbDataStore,
2932
+ OPENHI_REPO_TAG_KEY_ENV_VAR,
2933
+ OPENHI_RESOURCE_URN_SYSTEM,
2934
+ OPENHI_TAG_KEY_PREFIX_ENV_VAR,
2935
+ OPENHI_TAG_SUFFIX_BRANCH_NAME,
2936
+ OPENHI_TAG_SUFFIX_REPO_NAME,
2937
+ OPENHI_TAG_SUFFIX_SERVICE_TYPE,
2938
+ OPENHI_TAG_SUFFIX_STAGE_TYPE,
2297
2939
  OpenHiApp,
2298
2940
  OpenHiAuthService,
2299
2941
  OpenHiDataService,
@@ -2304,10 +2946,17 @@ export {
2304
2946
  OpenHiService,
2305
2947
  OpenHiStage,
2306
2948
  OpsEventBus,
2949
+ PLACEHOLDER_TENANT_ID,
2950
+ PLACEHOLDER_WORKSPACE_ID,
2951
+ PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM,
2952
+ PLATFORM_SCOPE_TENANT_ID,
2307
2953
  POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
2308
2954
  POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
2309
2955
  POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2310
2956
  PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,
2957
+ PlatformDeployBridge,
2958
+ PlatformDeployBridgeLambda,
2959
+ export_PlatformDeploymentCompletedV1 as PlatformDeploymentCompletedV1,
2311
2960
  PostAuthenticationLambda,
2312
2961
  PostConfirmationLambda,
2313
2962
  PreTokenGenerationLambda,
@@ -2317,13 +2966,39 @@ export {
2317
2966
  RootHostedZone,
2318
2967
  RootHttpApi,
2319
2968
  RootWildcardCertificate,
2969
+ SEED_DEMO_DATA_CONSUMER_NAME,
2970
+ SEED_SYSTEM_DATA_ACTOR_SYSTEM,
2971
+ SEED_SYSTEM_DATA_CONSUMER_NAME,
2972
+ SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR,
2320
2973
  STATIC_HOSTING_SERVICE_TYPE,
2974
+ SeedDemoDataLambda,
2975
+ SeedDemoDataWorkflow,
2976
+ SeedSystemDataLambda,
2977
+ SeedSystemDataWorkflow,
2321
2978
  StaticHosting,
2322
2979
  USER_ONBOARDING_EVENT_SOURCE,
2323
2980
  UserOnboardingWorkflow,
2981
+ WorkflowDedupConsumerNameInvalidError,
2982
+ WorkflowDedupTable,
2983
+ WorkflowDedupTableDuplicateError,
2324
2984
  buildFhirCurrentResourceChangeDetail,
2325
2985
  buildProvisionDefaultWorkspaceRequestedDetail,
2986
+ demoBasePartitionKeys,
2987
+ demoDevUserPartitionKeys,
2988
+ demoMembershipId,
2989
+ demoMembershipPartitionKey,
2990
+ demoRoleAssignmentId,
2991
+ demoRoleAssignmentPartitionKey,
2992
+ demoRolesForUserInTenant,
2993
+ demoScenarioIdentifier,
2994
+ demoTenantPartitionKey,
2995
+ demoUserPartitionKey,
2996
+ demoWorkspacePartitionKey,
2326
2997
  getDynamoDbDataStoreTableName,
2327
- getPostgresReplicaSchemaName
2998
+ getPostgresReplicaSchemaName,
2999
+ getWorkflowDedupTableName,
3000
+ openHiTagKey,
3001
+ openhiResourceIdentifier,
3002
+ rolePartitionKey
2328
3003
  };
2329
3004
  //# sourceMappingURL=index.mjs.map