@openhi/constructs 0.0.105 → 0.0.106

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-AGF3RAAZ.mjs +20 -0
  2. package/lib/chunk-AGF3RAAZ.mjs.map +1 -0
  3. package/lib/{chunk-BXEG7IOZ.mjs → chunk-AO3E22CS.mjs} +2 -2
  4. package/lib/{chunk-WNUH2WDZ.mjs → chunk-CHPEQRXU.mjs} +2 -2
  5. package/lib/chunk-JUNL76HF.mjs +428 -0
  6. package/lib/chunk-JUNL76HF.mjs.map +1 -0
  7. package/lib/chunk-L6UAP4KP.mjs +27 -0
  8. package/lib/chunk-L6UAP4KP.mjs.map +1 -0
  9. package/lib/{chunk-3QS3WKRC.mjs → chunk-LZOMFHX3.mjs} +9 -2
  10. package/lib/chunk-QMIOLLAS.mjs +531 -0
  11. package/lib/chunk-QMIOLLAS.mjs.map +1 -0
  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-DGep6C7w.d.mts +207 -0
  27. package/lib/events-DGep6C7w.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 +2400 -111
  32. package/lib/index.js.map +1 -1
  33. package/lib/index.mjs +781 -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-QMIOLLAS.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,242 @@ 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 { CONTROL_PLANE_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(CONTROL_PLANE_ROLE_IDS).map(
1855
+ rolePartitionKey
1856
+ );
1857
+ this.lambda.addToRolePolicy(
1858
+ new PolicyStatement3({
1859
+ effect: Effect3.ALLOW,
1860
+ actions: ["dynamodb:GetItem"],
1861
+ resources: [props.dataStoreTable.tableArn],
1862
+ conditions: {
1863
+ "ForAllValues:StringEquals": {
1864
+ "dynamodb:LeadingKeys": roleReadKeys
1865
+ }
1866
+ }
1867
+ })
1868
+ );
1869
+ const writeKeys = [
1870
+ ...demoBasePartitionKeys(),
1871
+ ...demoDevUserPartitionKeys(DEV_USERS)
1872
+ ];
1873
+ this.lambda.addToRolePolicy(
1874
+ new PolicyStatement3({
1875
+ effect: Effect3.ALLOW,
1876
+ actions: ["dynamodb:PutItem", "dynamodb:UpdateItem"],
1877
+ resources: [props.dataStoreTable.tableArn],
1878
+ conditions: {
1879
+ "ForAllValues:StringEquals": {
1880
+ "dynamodb:LeadingKeys": writeKeys
1881
+ }
1882
+ }
1883
+ })
1884
+ );
1885
+ this.lambda.addToRolePolicy(
1886
+ new PolicyStatement3({
1887
+ effect: Effect3.ALLOW,
1888
+ actions: [
1889
+ "cognito-idp:AdminCreateUser",
1890
+ "cognito-idp:AdminGetUser",
1891
+ "cognito-idp:AdminSetUserPassword"
1892
+ ],
1893
+ resources: [
1894
+ Stack4.of(this).formatArn({
1895
+ service: "cognito-idp",
1896
+ resource: "userpool",
1897
+ resourceName: props.userPool.userPoolId
1898
+ })
1899
+ ]
1900
+ })
1901
+ );
1902
+ this.rule = new Rule2(this, "rule", {
1903
+ eventBus: props.controlEventBus,
1904
+ eventPattern: {
1905
+ source: [import_workflows.PlatformSystemDataSeededV1.source],
1906
+ detailType: [import_workflows.PlatformSystemDataSeededV1.detailType]
1907
+ },
1908
+ targets: [
1909
+ new LambdaFunction2(this.lambda, {
1910
+ retryAttempts: 2,
1911
+ maxEventAge: Duration7.hours(2)
1912
+ })
1913
+ ]
1914
+ });
1915
+ }
1916
+ };
1917
+
1918
+ // src/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.ts
1919
+ import { Construct as Construct12 } from "constructs";
1920
+ var SeedDemoDataWorkflow = class extends Construct12 {
1921
+ constructor(scope, props) {
1922
+ super(scope, "seed-demo-data-workflow");
1923
+ this.seedDemoData = new SeedDemoDataLambda(this, {
1924
+ controlEventBus: props.controlEventBus,
1925
+ dataStoreTable: props.dataStoreTable,
1926
+ userPool: props.userPool
1927
+ });
1928
+ WorkflowDedupTable.grantConsumerFromLookup(
1929
+ this,
1930
+ this.seedDemoData.lambda,
1931
+ SEED_DEMO_DATA_CONSUMER_NAME
1932
+ );
1933
+ }
1934
+ };
1935
+
1936
+ // src/workflows/control-plane/seed-system-data/seed-system-data-lambda.ts
1937
+ import fs8 from "fs";
1938
+ import path8 from "path";
1939
+ import { CONTROL_PLANE_ROLE_IDS as CONTROL_PLANE_ROLE_IDS2 } from "@openhi/types";
1940
+ import { Duration as Duration8, Stack as Stack5 } from "aws-cdk-lib";
1941
+ import { Rule as Rule3 } from "aws-cdk-lib/aws-events";
1942
+ import { LambdaFunction as LambdaFunction3 } from "aws-cdk-lib/aws-events-targets";
1943
+ import { Effect as Effect4, PolicyStatement as PolicyStatement4 } from "aws-cdk-lib/aws-iam";
1944
+ import { Runtime as Runtime8 } from "aws-cdk-lib/aws-lambda";
1945
+ import { NodejsFunction as NodejsFunction8 } from "aws-cdk-lib/aws-lambda-nodejs";
1946
+ import { Construct as Construct13 } from "constructs";
1947
+ var HANDLER_NAME8 = "seed-system-data.handler.js";
1948
+ function resolveHandlerEntry8(dirname) {
1949
+ const sameDir = path8.join(dirname, HANDLER_NAME8);
1950
+ if (fs8.existsSync(sameDir)) {
1951
+ return sameDir;
1952
+ }
1953
+ return path8.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME8);
1954
+ }
1955
+ var SeedSystemDataLambda = class extends Construct13 {
1956
+ constructor(scope, props) {
1957
+ super(scope, "seed-system-data-lambda");
1958
+ this.lambda = new NodejsFunction8(this, "handler", {
1959
+ entry: resolveHandlerEntry8(__dirname),
1960
+ runtime: Runtime8.NODEJS_LATEST,
1961
+ memorySize: 512,
1962
+ timeout: Duration8.minutes(1),
1963
+ environment: {
1964
+ DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
1965
+ [SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR]: props.controlEventBus.eventBusName
1966
+ }
1967
+ });
1968
+ const roleArns = Object.values(CONTROL_PLANE_ROLE_IDS2).map(
1969
+ (id) => `role#id#${id}`
1970
+ );
1971
+ this.lambda.addToRolePolicy(
1972
+ new PolicyStatement4({
1973
+ effect: Effect4.ALLOW,
1974
+ actions: ["dynamodb:PutItem", "dynamodb:UpdateItem"],
1975
+ resources: [props.dataStoreTable.tableArn],
1976
+ conditions: {
1977
+ "ForAllValues:StringEquals": {
1978
+ "dynamodb:LeadingKeys": roleArns
1979
+ }
1980
+ }
1981
+ })
1982
+ );
1983
+ props.controlEventBus.grantPutEventsTo(this.lambda);
1984
+ const hostStackName = Stack5.of(this).stackName;
1985
+ this.rule = new Rule3(this, "rule", {
1986
+ eventBus: props.controlEventBus,
1987
+ eventPattern: {
1988
+ source: [import_workflows2.PlatformDeploymentCompletedV1.source],
1989
+ detailType: [import_workflows2.PlatformDeploymentCompletedV1.detailType],
1990
+ detail: {
1991
+ payload: {
1992
+ stackName: [hostStackName]
1993
+ }
1994
+ }
1995
+ },
1996
+ targets: [
1997
+ new LambdaFunction3(this.lambda, {
1998
+ retryAttempts: 2,
1999
+ maxEventAge: Duration8.hours(2)
2000
+ })
2001
+ ]
2002
+ });
2003
+ }
2004
+ };
2005
+
2006
+ // src/workflows/control-plane/seed-system-data/seed-system-data-workflow.ts
2007
+ import { Construct as Construct14 } from "constructs";
2008
+ var SeedSystemDataWorkflow = class extends Construct14 {
2009
+ constructor(scope, props) {
2010
+ super(scope, "seed-system-data-workflow");
2011
+ this.seedSystemData = new SeedSystemDataLambda(this, {
2012
+ controlEventBus: props.controlEventBus,
2013
+ dataStoreTable: props.dataStoreTable
2014
+ });
2015
+ WorkflowDedupTable.grantConsumerFromLookup(
2016
+ this,
2017
+ this.seedSystemData.lambda,
2018
+ SEED_SYSTEM_DATA_CONSUMER_NAME
2019
+ );
1453
2020
  }
2021
+ };
2022
+
2023
+ // src/services/open-hi-data-service.ts
2024
+ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1454
2025
  constructor(ohEnv, props = {}) {
1455
2026
  super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
2027
+ /**
2028
+ * Cached control-event-bus lookup. `OpenHiGlobalService.controlEventBusFromConstruct`
2029
+ * registers a child `EventBus.fromEventBusName` construct with a
2030
+ * fixed id under the scope it is passed, so calling it twice on the
2031
+ * same `OpenHiDataService` instance collides. The cache mirrors the
2032
+ * `private controlEventBus()` pattern already used in
2033
+ * `OpenHiAuthService`. Use {@link controlEventBus} from this class
2034
+ * — never call the static lookup from inside `OpenHiDataService`.
2035
+ */
2036
+ this._controlEventBus = null;
1456
2037
  this.props = props;
1457
2038
  this.dataStoreChangeStream = new kinesis.Stream(
1458
2039
  this,
@@ -1487,6 +2068,53 @@ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1487
2068
  branchHash: this.branchHash
1488
2069
  }
1489
2070
  );
2071
+ this.seedSystemDataWorkflow = this.createSeedSystemDataWorkflow();
2072
+ this.seedDemoDataWorkflow = this.createSeedDemoDataWorkflow();
2073
+ }
2074
+ /**
2075
+ * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
2076
+ */
2077
+ static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
2078
+ return Table3.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
2079
+ }
2080
+ get serviceType() {
2081
+ return _OpenHiDataService.SERVICE_TYPE;
2082
+ }
2083
+ /**
2084
+ * Lazily looks up the control event bus exactly once per
2085
+ * `OpenHiDataService` instance and caches the reference. Every
2086
+ * workflow that consumes the bus must read it through this method
2087
+ * — see {@link _controlEventBus} for the underlying collision risk.
2088
+ */
2089
+ controlEventBus() {
2090
+ if (this._controlEventBus === null) {
2091
+ this._controlEventBus = OpenHiGlobalService.controlEventBusFromConstruct(this);
2092
+ }
2093
+ return this._controlEventBus;
2094
+ }
2095
+ /**
2096
+ * Creates the seed-system-data workflow. Override to customize.
2097
+ */
2098
+ createSeedSystemDataWorkflow() {
2099
+ return new SeedSystemDataWorkflow(this, {
2100
+ controlEventBus: this.controlEventBus(),
2101
+ dataStoreTable: this.dataStore
2102
+ });
2103
+ }
2104
+ /**
2105
+ * Creates the seed-demo-data workflow — but only on non-prod
2106
+ * stages. Returns `undefined` on prod so the workflow literally
2107
+ * does not exist in prod stacks. Override to customize.
2108
+ */
2109
+ createSeedDemoDataWorkflow() {
2110
+ if (this.ohEnv.ohStage.stageType === import_config4.OPEN_HI_STAGE.PROD) {
2111
+ return void 0;
2112
+ }
2113
+ return new SeedDemoDataWorkflow(this, {
2114
+ controlEventBus: this.controlEventBus(),
2115
+ dataStoreTable: this.dataStore,
2116
+ userPool: OpenHiAuthService.userPoolFromConstruct(this)
2117
+ });
1490
2118
  }
1491
2119
  /**
1492
2120
  * Creates the single-table DynamoDB data store.
@@ -1503,29 +2131,29 @@ _OpenHiDataService.SERVICE_TYPE = "data";
1503
2131
  var OpenHiDataService = _OpenHiDataService;
1504
2132
 
1505
2133
  // 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)) {
2134
+ import fs9 from "fs";
2135
+ import path9 from "path";
2136
+ import { Duration as Duration9 } from "aws-cdk-lib";
2137
+ import { Rule as Rule4 } from "aws-cdk-lib/aws-events";
2138
+ import { LambdaFunction as LambdaFunction4 } from "aws-cdk-lib/aws-events-targets";
2139
+ import { Effect as Effect5, PolicyStatement as PolicyStatement5 } from "aws-cdk-lib/aws-iam";
2140
+ import { Runtime as Runtime9 } from "aws-cdk-lib/aws-lambda";
2141
+ import { NodejsFunction as NodejsFunction9 } from "aws-cdk-lib/aws-lambda-nodejs";
2142
+ import { Construct as Construct15 } from "constructs";
2143
+ var HANDLER_NAME9 = "provision-default-workspace.handler.js";
2144
+ function resolveHandlerEntry9(dirname) {
2145
+ const sameDir = path9.join(dirname, HANDLER_NAME9);
2146
+ if (fs9.existsSync(sameDir)) {
1519
2147
  return sameDir;
1520
2148
  }
1521
- return path6.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME6);
2149
+ return path9.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME9);
1522
2150
  }
1523
- var ProvisionDefaultWorkspaceLambda = class extends Construct8 {
2151
+ var ProvisionDefaultWorkspaceLambda = class extends Construct15 {
1524
2152
  constructor(scope, props) {
1525
2153
  super(scope, "provision-default-workspace-lambda");
1526
- this.lambda = new NodejsFunction6(this, "handler", {
1527
- entry: resolveHandlerEntry6(__dirname),
1528
- runtime: Runtime6.NODEJS_LATEST,
2154
+ this.lambda = new NodejsFunction9(this, "handler", {
2155
+ entry: resolveHandlerEntry9(__dirname),
2156
+ runtime: Runtime9.NODEJS_LATEST,
1529
2157
  memorySize: 1024,
1530
2158
  environment: {
1531
2159
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
@@ -1537,22 +2165,22 @@ var ProvisionDefaultWorkspaceLambda = class extends Construct8 {
1537
2165
  "dynamodb:UpdateItem"
1538
2166
  );
1539
2167
  this.lambda.addToRolePolicy(
1540
- new PolicyStatement({
1541
- effect: Effect.ALLOW,
2168
+ new PolicyStatement5({
2169
+ effect: Effect5.ALLOW,
1542
2170
  actions: ["dynamodb:Query"],
1543
2171
  resources: [`${props.dataStoreTable.tableArn}/index/*`]
1544
2172
  })
1545
2173
  );
1546
- this.rule = new Rule(this, "rule", {
2174
+ this.rule = new Rule4(this, "rule", {
1547
2175
  eventBus: props.controlEventBus,
1548
2176
  eventPattern: {
1549
2177
  source: [USER_ONBOARDING_EVENT_SOURCE],
1550
2178
  detailType: [PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE]
1551
2179
  },
1552
2180
  targets: [
1553
- new LambdaFunction(this.lambda, {
2181
+ new LambdaFunction4(this.lambda, {
1554
2182
  retryAttempts: 2,
1555
- maxEventAge: Duration6.hours(2)
2183
+ maxEventAge: Duration9.hours(2)
1556
2184
  })
1557
2185
  ]
1558
2186
  });
@@ -1560,8 +2188,8 @@ var ProvisionDefaultWorkspaceLambda = class extends Construct8 {
1560
2188
  };
1561
2189
 
1562
2190
  // src/workflows/control-plane/user-onboarding/user-onboarding-workflow.ts
1563
- import { Construct as Construct9 } from "constructs";
1564
- var UserOnboardingWorkflow = class extends Construct9 {
2191
+ import { Construct as Construct16 } from "constructs";
2192
+ var UserOnboardingWorkflow = class extends Construct16 {
1565
2193
  constructor(scope, props) {
1566
2194
  super(scope, "user-onboarding-workflow");
1567
2195
  this.provisionDefaultWorkspace = new ProvisionDefaultWorkspaceLambda(this, {
@@ -1776,8 +2404,8 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1776
2404
  const dynamoActions = ["dynamodb:GetItem", "dynamodb:Query"];
1777
2405
  dataStoreTable.grant(this.preTokenGenerationLambda, ...dynamoActions);
1778
2406
  this.preTokenGenerationLambda.addToRolePolicy(
1779
- new PolicyStatement2({
1780
- effect: Effect2.ALLOW,
2407
+ new PolicyStatement6({
2408
+ effect: Effect6.ALLOW,
1781
2409
  actions: [...dynamoActions],
1782
2410
  resources: [`${dataStoreTable.tableArn}/index/*`]
1783
2411
  })
@@ -1798,10 +2426,10 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1798
2426
  */
1799
2427
  grantPostAuthenticationPermissions() {
1800
2428
  this.postAuthenticationLambda.addToRolePolicy(
1801
- new PolicyStatement2({
2429
+ new PolicyStatement6({
1802
2430
  actions: ["cognito-idp:AdminUserGlobalSignOut"],
1803
2431
  resources: [
1804
- Stack3.of(this).formatArn({
2432
+ Stack6.of(this).formatArn({
1805
2433
  service: "cognito-idp",
1806
2434
  resource: "userpool",
1807
2435
  resourceName: "*"
@@ -1845,7 +2473,7 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1845
2473
  * via env vars to drive `InitiateAuth`.
1846
2474
  */
1847
2475
  createFixtureSeederClient() {
1848
- if (this.ohEnv.ohStage.stageType === import_config4.OPEN_HI_STAGE.PROD) {
2476
+ if (this.ohEnv.ohStage.stageType === import_config5.OPEN_HI_STAGE.PROD) {
1849
2477
  return void 0;
1850
2478
  }
1851
2479
  const client = new CognitoFixtureSeederClient(this, {
@@ -1882,7 +2510,7 @@ _OpenHiAuthService.SERVICE_TYPE = "auth";
1882
2510
  var OpenHiAuthService = _OpenHiAuthService;
1883
2511
 
1884
2512
  // src/services/open-hi-rest-api-service.ts
1885
- var import_config5 = __toESM(require_lib());
2513
+ var import_config6 = __toESM(require_lib2());
1886
2514
  import {
1887
2515
  CorsHttpMethod,
1888
2516
  DomainName,
@@ -1894,62 +2522,62 @@ import {
1894
2522
  } from "aws-cdk-lib/aws-apigatewayv2";
1895
2523
  import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers";
1896
2524
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
1897
- import { Effect as Effect3, PolicyStatement as PolicyStatement3 } from "aws-cdk-lib/aws-iam";
2525
+ import { Effect as Effect7, PolicyStatement as PolicyStatement7 } from "aws-cdk-lib/aws-iam";
1898
2526
  import {
1899
2527
  ARecord,
1900
2528
  HostedZone as HostedZone3,
1901
2529
  RecordTarget
1902
2530
  } from "aws-cdk-lib/aws-route53";
1903
2531
  import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
1904
- import { Duration as Duration7 } from "aws-cdk-lib/core";
2532
+ import { Duration as Duration10 } from "aws-cdk-lib/core";
1905
2533
 
1906
2534
  // 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)) {
2535
+ import fs10 from "fs";
2536
+ import path10 from "path";
2537
+ import { Runtime as Runtime10 } from "aws-cdk-lib/aws-lambda";
2538
+ import { NodejsFunction as NodejsFunction10 } from "aws-cdk-lib/aws-lambda-nodejs";
2539
+ import { Construct as Construct17 } from "constructs";
2540
+ var HANDLER_NAME10 = "cors-options-lambda.handler.js";
2541
+ function resolveHandlerEntry10(dirname) {
2542
+ const sameDir = path10.join(dirname, HANDLER_NAME10);
2543
+ if (fs10.existsSync(sameDir)) {
1916
2544
  return sameDir;
1917
2545
  }
1918
- const fromLib = path7.join(dirname, "..", "..", "..", "lib", HANDLER_NAME7);
2546
+ const fromLib = path10.join(dirname, "..", "..", "..", "lib", HANDLER_NAME10);
1919
2547
  return fromLib;
1920
2548
  }
1921
- var CorsOptionsLambda = class extends Construct10 {
2549
+ var CorsOptionsLambda = class extends Construct17 {
1922
2550
  constructor(scope, id = "cors-options-lambda") {
1923
2551
  super(scope, id);
1924
- this.lambda = new NodejsFunction7(this, "handler", {
1925
- entry: resolveHandlerEntry7(__dirname),
1926
- runtime: Runtime7.NODEJS_LATEST,
2552
+ this.lambda = new NodejsFunction10(this, "handler", {
2553
+ entry: resolveHandlerEntry10(__dirname),
2554
+ runtime: Runtime10.NODEJS_LATEST,
1927
2555
  memorySize: 128
1928
2556
  });
1929
2557
  }
1930
2558
  };
1931
2559
 
1932
2560
  // 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)) {
2561
+ import fs11 from "fs";
2562
+ import path11 from "path";
2563
+ import { Runtime as Runtime11 } from "aws-cdk-lib/aws-lambda";
2564
+ import { NodejsFunction as NodejsFunction11 } from "aws-cdk-lib/aws-lambda-nodejs";
2565
+ import { Construct as Construct18 } from "constructs";
2566
+ var HANDLER_NAME11 = "rest-api-lambda.handler.js";
2567
+ function resolveHandlerEntry11(dirname) {
2568
+ const sameDir = path11.join(dirname, HANDLER_NAME11);
2569
+ if (fs11.existsSync(sameDir)) {
1942
2570
  return sameDir;
1943
2571
  }
1944
- const fromLib = path8.join(dirname, "..", "..", "..", "lib", HANDLER_NAME8);
2572
+ const fromLib = path11.join(dirname, "..", "..", "..", "lib", HANDLER_NAME11);
1945
2573
  return fromLib;
1946
2574
  }
1947
- var RestApiLambda = class extends Construct11 {
2575
+ var RestApiLambda = class extends Construct18 {
1948
2576
  constructor(scope, props) {
1949
2577
  super(scope, "rest-api-lambda");
1950
- this.lambda = new NodejsFunction8(this, "handler", {
1951
- entry: resolveHandlerEntry8(__dirname),
1952
- runtime: Runtime8.NODEJS_LATEST,
2578
+ this.lambda = new NodejsFunction11(this, "handler", {
2579
+ entry: resolveHandlerEntry11(__dirname),
2580
+ runtime: Runtime11.NODEJS_LATEST,
1953
2581
  memorySize: 1024,
1954
2582
  environment: {
1955
2583
  DYNAMO_TABLE_NAME: props.dynamoTableName,
@@ -2091,8 +2719,8 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2091
2719
  postgresSchema
2092
2720
  });
2093
2721
  lambda.addToRolePolicy(
2094
- new PolicyStatement3({
2095
- effect: Effect3.ALLOW,
2722
+ new PolicyStatement7({
2723
+ effect: Effect7.ALLOW,
2096
2724
  actions: [
2097
2725
  "rds-data:ExecuteStatement",
2098
2726
  "rds-data:BatchExecuteStatement"
@@ -2101,8 +2729,8 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2101
2729
  })
2102
2730
  );
2103
2731
  lambda.addToRolePolicy(
2104
- new PolicyStatement3({
2105
- effect: Effect3.ALLOW,
2732
+ new PolicyStatement7({
2733
+ effect: Effect7.ALLOW,
2106
2734
  actions: ["secretsmanager:GetSecretValue"],
2107
2735
  resources: [postgresSecretArn]
2108
2736
  })
@@ -2120,15 +2748,15 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2120
2748
  ];
2121
2749
  dataStoreTable.grant(lambda, ...dynamoActions);
2122
2750
  lambda.addToRolePolicy(
2123
- new PolicyStatement3({
2124
- effect: Effect3.ALLOW,
2751
+ new PolicyStatement7({
2752
+ effect: Effect7.ALLOW,
2125
2753
  actions: [...dynamoActions],
2126
2754
  resources: [`${dataStoreTable.tableArn}/index/*`]
2127
2755
  })
2128
2756
  );
2129
2757
  lambda.addToRolePolicy(
2130
- new PolicyStatement3({
2131
- effect: Effect3.ALLOW,
2758
+ new PolicyStatement7({
2759
+ effect: Effect7.ALLOW,
2132
2760
  actions: [
2133
2761
  "ssm:GetParameter",
2134
2762
  "ssm:GetParameters",
@@ -2187,7 +2815,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2187
2815
  const userPool = OpenHiAuthService.userPoolFromConstruct(this);
2188
2816
  const userPoolClient = OpenHiAuthService.userPoolClientFromConstruct(this);
2189
2817
  const userPoolClients = [userPoolClient];
2190
- if (this.ohEnv.ohStage.stageType !== import_config5.OPEN_HI_STAGE.PROD) {
2818
+ if (this.ohEnv.ohStage.stageType !== import_config6.OPEN_HI_STAGE.PROD) {
2191
2819
  userPoolClients.push(
2192
2820
  OpenHiAuthService.fixtureSeederClientFromConstruct(this)
2193
2821
  );
@@ -2214,7 +2842,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2214
2842
  "Authorization"
2215
2843
  ],
2216
2844
  allowCredentials: cors.allowCredentials ?? true,
2217
- maxAge: cors.maxAge ?? Duration7.days(1),
2845
+ maxAge: cors.maxAge ?? Duration10.days(1),
2218
2846
  ...cors.exposeHeaders !== void 0 && {
2219
2847
  exposeHeaders: cors.exposeHeaders
2220
2848
  }
@@ -2278,7 +2906,12 @@ var _OpenHiGraphqlService = class _OpenHiGraphqlService extends OpenHiService {
2278
2906
  };
2279
2907
  _OpenHiGraphqlService.SERVICE_TYPE = "graphql-api";
2280
2908
  var OpenHiGraphqlService = _OpenHiGraphqlService;
2909
+ var export_PlatformDeploymentCompletedV1 = import_workflows2.PlatformDeploymentCompletedV1;
2281
2910
  export {
2911
+ BRIDGED_STATUSES,
2912
+ CLOUDFORMATION_EVENT_SOURCE,
2913
+ CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE,
2914
+ CONTROL_EVENT_BUS_NAME_ENV_VAR,
2282
2915
  ChildHostedZone,
2283
2916
  CognitoFixtureSeederClient,
2284
2917
  CognitoUserPool,
@@ -2289,11 +2922,22 @@ export {
2289
2922
  DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES,
2290
2923
  DATA_STORE_CHANGE_DETAIL_TYPE,
2291
2924
  DATA_STORE_CHANGE_EVENT_SOURCE,
2925
+ DEMO_PERIOD,
2926
+ DEMO_TENANT_SPECS,
2927
+ DEMO_URN_SYSTEM,
2928
+ DEV_USERS,
2292
2929
  DataEventBus,
2293
2930
  DataStoreHistoricalArchive,
2294
2931
  DataStorePostgresReplica,
2295
2932
  DiscoverableStringParameter,
2296
2933
  DynamoDbDataStore,
2934
+ OPENHI_REPO_TAG_KEY_ENV_VAR,
2935
+ OPENHI_RESOURCE_URN_SYSTEM,
2936
+ OPENHI_TAG_KEY_PREFIX_ENV_VAR,
2937
+ OPENHI_TAG_SUFFIX_BRANCH_NAME,
2938
+ OPENHI_TAG_SUFFIX_REPO_NAME,
2939
+ OPENHI_TAG_SUFFIX_SERVICE_TYPE,
2940
+ OPENHI_TAG_SUFFIX_STAGE_TYPE,
2297
2941
  OpenHiApp,
2298
2942
  OpenHiAuthService,
2299
2943
  OpenHiDataService,
@@ -2304,10 +2948,17 @@ export {
2304
2948
  OpenHiService,
2305
2949
  OpenHiStage,
2306
2950
  OpsEventBus,
2951
+ PLACEHOLDER_TENANT_ID,
2952
+ PLACEHOLDER_WORKSPACE_ID,
2953
+ PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM,
2954
+ PLATFORM_SCOPE_TENANT_ID,
2307
2955
  POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
2308
2956
  POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
2309
2957
  POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2310
2958
  PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE,
2959
+ PlatformDeployBridge,
2960
+ PlatformDeployBridgeLambda,
2961
+ export_PlatformDeploymentCompletedV1 as PlatformDeploymentCompletedV1,
2311
2962
  PostAuthenticationLambda,
2312
2963
  PostConfirmationLambda,
2313
2964
  PreTokenGenerationLambda,
@@ -2317,13 +2968,39 @@ export {
2317
2968
  RootHostedZone,
2318
2969
  RootHttpApi,
2319
2970
  RootWildcardCertificate,
2971
+ SEED_DEMO_DATA_CONSUMER_NAME,
2972
+ SEED_SYSTEM_DATA_ACTOR_SYSTEM,
2973
+ SEED_SYSTEM_DATA_CONSUMER_NAME,
2974
+ SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR,
2320
2975
  STATIC_HOSTING_SERVICE_TYPE,
2976
+ SeedDemoDataLambda,
2977
+ SeedDemoDataWorkflow,
2978
+ SeedSystemDataLambda,
2979
+ SeedSystemDataWorkflow,
2321
2980
  StaticHosting,
2322
2981
  USER_ONBOARDING_EVENT_SOURCE,
2323
2982
  UserOnboardingWorkflow,
2983
+ WorkflowDedupConsumerNameInvalidError,
2984
+ WorkflowDedupTable,
2985
+ WorkflowDedupTableDuplicateError,
2324
2986
  buildFhirCurrentResourceChangeDetail,
2325
2987
  buildProvisionDefaultWorkspaceRequestedDetail,
2988
+ demoBasePartitionKeys,
2989
+ demoDevUserPartitionKeys,
2990
+ demoMembershipId,
2991
+ demoMembershipPartitionKey,
2992
+ demoRoleAssignmentId,
2993
+ demoRoleAssignmentPartitionKey,
2994
+ demoRolesForUserInTenant,
2995
+ demoScenarioIdentifier,
2996
+ demoTenantPartitionKey,
2997
+ demoUserPartitionKey,
2998
+ demoWorkspacePartitionKey,
2326
2999
  getDynamoDbDataStoreTableName,
2327
- getPostgresReplicaSchemaName
3000
+ getPostgresReplicaSchemaName,
3001
+ getWorkflowDedupTableName,
3002
+ openHiTagKey,
3003
+ openhiResourceIdentifier,
3004
+ rolePartitionKey
2328
3005
  };
2329
3006
  //# sourceMappingURL=index.mjs.map