@openhi/constructs 0.0.0 → 0.0.2

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 (101) hide show
  1. package/lib/chunk-LZOMFHX3.mjs +38 -0
  2. package/lib/chunk-LZOMFHX3.mjs.map +1 -0
  3. package/lib/index.d.mts +788 -0
  4. package/lib/index.d.ts +869 -3
  5. package/lib/index.js +1318 -19
  6. package/lib/index.js.map +1 -0
  7. package/lib/index.mjs +1303 -0
  8. package/lib/index.mjs.map +1 -0
  9. package/lib/rest-api-lambda.handler.d.mts +6 -0
  10. package/lib/rest-api-lambda.handler.d.ts +6 -0
  11. package/lib/rest-api-lambda.handler.js +677 -0
  12. package/lib/rest-api-lambda.handler.js.map +1 -0
  13. package/lib/rest-api-lambda.handler.mjs +646 -0
  14. package/lib/rest-api-lambda.handler.mjs.map +1 -0
  15. package/package.json +37 -28
  16. package/lib/app/index.d.ts +0 -4
  17. package/lib/app/index.js +0 -21
  18. package/lib/app/open-hi-app.d.ts +0 -85
  19. package/lib/app/open-hi-app.js +0 -127
  20. package/lib/app/open-hi-environment.d.ts +0 -59
  21. package/lib/app/open-hi-environment.js +0 -72
  22. package/lib/app/open-hi-service.d.ts +0 -169
  23. package/lib/app/open-hi-service.js +0 -195
  24. package/lib/app/open-hi-stage.d.ts +0 -71
  25. package/lib/app/open-hi-stage.js +0 -70
  26. package/lib/components/acm/root-wildcard-certificate.d.ts +0 -15
  27. package/lib/components/acm/root-wildcard-certificate.js +0 -35
  28. package/lib/components/api-gateway/core-http-api.d.ts +0 -10
  29. package/lib/components/api-gateway/core-http-api.js +0 -44
  30. package/lib/components/api-gateway/http-lambda-integration-no-permissions.d.ts +0 -18
  31. package/lib/components/api-gateway/http-lambda-integration-no-permissions.js +0 -26
  32. package/lib/components/app-sync/core-graphql-api.d.ts +0 -12
  33. package/lib/components/app-sync/core-graphql-api.js +0 -54
  34. package/lib/components/auth.d.ts +0 -75
  35. package/lib/components/auth.js +0 -100
  36. package/lib/components/cognito/core-user-pool-client.d.ts +0 -10
  37. package/lib/components/cognito/core-user-pool-client.js +0 -47
  38. package/lib/components/cognito/core-user-pool-domain.d.ts +0 -10
  39. package/lib/components/cognito/core-user-pool-domain.js +0 -41
  40. package/lib/components/cognito/core-user-pool-kms-key.d.ts +0 -10
  41. package/lib/components/cognito/core-user-pool-kms-key.js +0 -37
  42. package/lib/components/cognito/core-user-pool.d.ts +0 -10
  43. package/lib/components/cognito/core-user-pool.js +0 -54
  44. package/lib/components/core.d.ts +0 -102
  45. package/lib/components/core.js +0 -79
  46. package/lib/components/dynamodb/dynamo-db-data-store.d.ts +0 -33
  47. package/lib/components/dynamodb/dynamo-db-data-store.js +0 -107
  48. package/lib/components/event-bridge/data-event-bus.d.ts +0 -19
  49. package/lib/components/event-bridge/data-event-bus.js +0 -34
  50. package/lib/components/event-bridge/ops-event-bus.d.ts +0 -19
  51. package/lib/components/event-bridge/ops-event-bus.js +0 -34
  52. package/lib/components/global.d.ts +0 -36
  53. package/lib/components/global.js +0 -63
  54. package/lib/components/index.d.ts +0 -1
  55. package/lib/components/index.js +0 -18
  56. package/lib/components/route-53/child-hosted-zone.d.ts +0 -20
  57. package/lib/components/route-53/child-hosted-zone.js +0 -48
  58. package/lib/components/route-53/root-hosted-zone.d.ts +0 -10
  59. package/lib/components/route-53/root-hosted-zone.js +0 -20
  60. package/lib/components/ssm/discoverable-string-parameter.d.ts +0 -59
  61. package/lib/components/ssm/discoverable-string-parameter.js +0 -50
  62. package/lib/components/ssm/index.d.ts +0 -1
  63. package/lib/components/ssm/index.js +0 -18
  64. package/lib/data/dynamo/ehr/r4/Patient.d.ts +0 -180
  65. package/lib/data/dynamo/ehr/r4/Patient.js +0 -192
  66. package/lib/data/dynamo/ehr/r4/ehr-r4-data-service.d.ts +0 -162
  67. package/lib/data/dynamo/ehr/r4/ehr-r4-data-service.js +0 -37
  68. package/lib/data/hello-world.d.ts +0 -39
  69. package/lib/data/hello-world.js +0 -59
  70. package/lib/data/import-patient-with-dynalite.d.ts +0 -1
  71. package/lib/data/import-patient-with-dynalite.js +0 -87
  72. package/lib/data/import-patient.d.ts +0 -47
  73. package/lib/data/import-patient.js +0 -158
  74. package/lib/data/lambda/rest-api-lambda.d.ts +0 -13
  75. package/lib/data/lambda/rest-api-lambda.handler.d.ts +0 -1
  76. package/lib/data/lambda/rest-api-lambda.handler.js +0 -10
  77. package/lib/data/lambda/rest-api-lambda.js +0 -22
  78. package/lib/data/middleware/open-hi-context.d.ts +0 -13
  79. package/lib/data/middleware/open-hi-context.js +0 -31
  80. package/lib/data/rest-api/ehr/r4/Patient.d.ts +0 -16
  81. package/lib/data/rest-api/ehr/r4/Patient.js +0 -234
  82. package/lib/data/rest-api/rest-api-local.d.ts +0 -1
  83. package/lib/data/rest-api/rest-api-local.js +0 -8
  84. package/lib/data/rest-api/rest-api-mockdata.d.ts +0 -7
  85. package/lib/data/rest-api/rest-api-mockdata.js +0 -585
  86. package/lib/data/rest-api/rest-api.d.ts +0 -3
  87. package/lib/data/rest-api/rest-api.js +0 -26
  88. package/lib/lib/compression.d.ts +0 -27
  89. package/lib/lib/compression.js +0 -87
  90. package/lib/services/index.d.ts +0 -5
  91. package/lib/services/index.js +0 -22
  92. package/lib/services/open-hi-auth-service.d.ts +0 -31
  93. package/lib/services/open-hi-auth-service.js +0 -31
  94. package/lib/services/open-hi-core-service.d.ts +0 -15
  95. package/lib/services/open-hi-core-service.js +0 -38
  96. package/lib/services/open-hi-data-service.d.ts +0 -18
  97. package/lib/services/open-hi-data-service.js +0 -18
  98. package/lib/services/open-hi-global-service.d.ts +0 -15
  99. package/lib/services/open-hi-global-service.js +0 -44
  100. package/lib/services/open-hi-rest-api-service.d.ts +0 -17
  101. package/lib/services/open-hi-rest-api-service.js +0 -107
package/lib/index.mjs ADDED
@@ -0,0 +1,1303 @@
1
+ import {
2
+ __commonJS,
3
+ __toESM
4
+ } from "./chunk-LZOMFHX3.mjs";
5
+
6
+ // ../config/lib/open-hi-config.js
7
+ var require_open_hi_config = __commonJS({
8
+ "../config/lib/open-hi-config.js"(exports) {
9
+ "use strict";
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.OPEN_HI_DEPLOYMENT_TARGET_ROLE = exports.OPEN_HI_STAGE = void 0;
12
+ exports.OPEN_HI_STAGE = {
13
+ /**
14
+ * Development environment, typically used for testing and development.
15
+ */
16
+ DEV: "dev",
17
+ /**
18
+ * Staging environment, used for pre-production testing.
19
+ */
20
+ STAGE: "stage",
21
+ /**
22
+ * Production environment, used for live deployments.
23
+ */
24
+ PROD: "prod"
25
+ };
26
+ exports.OPEN_HI_DEPLOYMENT_TARGET_ROLE = {
27
+ /**
28
+ * The primary deployment target for this stage (main account/region).
29
+ * For example, the base DynamoDB region for global tables.
30
+ */
31
+ PRIMARY: "primary",
32
+ /**
33
+ * A secondary deployment target for this stage (additional account/region).
34
+ * For example, a replica region for a global DynamoDB table, or another cell in the same region.
35
+ */
36
+ SECONDARY: "secondary"
37
+ };
38
+ }
39
+ });
40
+
41
+ // ../config/lib/index.js
42
+ var require_lib = __commonJS({
43
+ "../config/lib/index.js"(exports) {
44
+ "use strict";
45
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
46
+ if (k2 === void 0) k2 = k;
47
+ var desc = Object.getOwnPropertyDescriptor(m, k);
48
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
49
+ desc = { enumerable: true, get: function() {
50
+ return m[k];
51
+ } };
52
+ }
53
+ Object.defineProperty(o, k2, desc);
54
+ }) : (function(o, m, k, k2) {
55
+ if (k2 === void 0) k2 = k;
56
+ o[k2] = m[k];
57
+ }));
58
+ var __exportStar = exports && exports.__exportStar || function(m, exports2) {
59
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
60
+ };
61
+ Object.defineProperty(exports, "__esModule", { value: true });
62
+ __exportStar(require_open_hi_config(), exports);
63
+ }
64
+ });
65
+
66
+ // src/app/open-hi-app.ts
67
+ var import_config2 = __toESM(require_lib());
68
+ import { App } from "aws-cdk-lib";
69
+
70
+ // src/app/open-hi-environment.ts
71
+ var import_config = __toESM(require_lib());
72
+ import { Stage } from "aws-cdk-lib";
73
+ var OPEN_HI_ENVIRONMENT_SYMBOL = /* @__PURE__ */ Symbol.for(
74
+ "@openhi/constructs/core.OpenHiEnvironment"
75
+ );
76
+ var OpenHiEnvironment = class _OpenHiEnvironment extends Stage {
77
+ /**
78
+ * Creates a new OpenHiEnvironment.
79
+ */
80
+ constructor(ohStage, props) {
81
+ if (props.config.account && props.config.region) {
82
+ props = {
83
+ ...props,
84
+ env: {
85
+ account: props.config.account,
86
+ region: props.config.region
87
+ }
88
+ };
89
+ }
90
+ const stageName = props.deploymentTargetRole === import_config.OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY ? props.deploymentTargetRole : [props.deploymentTargetRole, ohStage.environments.length].join("-");
91
+ super(ohStage, stageName, {
92
+ env: props.env ?? ohStage.props.env,
93
+ ...props
94
+ });
95
+ this.ohStage = ohStage;
96
+ this.props = props;
97
+ Object.defineProperty(this, OPEN_HI_ENVIRONMENT_SYMBOL, { value: true });
98
+ this.deploymentTargetRole = props.deploymentTargetRole;
99
+ this.config = props.config;
100
+ }
101
+ /**
102
+ * Finds the OpenHiEnvironment that contains the given construct.
103
+ * ```
104
+ */
105
+ static of(construct) {
106
+ return construct.node.scopes.reverse().find(_OpenHiEnvironment.isOpenHiEnvironment);
107
+ }
108
+ /**
109
+ * Type guard to check if a value is an OpenHiEnvironment instance.
110
+ */
111
+ static isOpenHiEnvironment(x) {
112
+ return x !== null && typeof x === "object" && OPEN_HI_ENVIRONMENT_SYMBOL in x;
113
+ }
114
+ };
115
+
116
+ // src/app/open-hi-stage.ts
117
+ import { Stage as Stage2 } from "aws-cdk-lib";
118
+ var OPEN_HI_STAGE_SYMBOL = /* @__PURE__ */ Symbol.for("@openhi/constructs/core.OpenHiStage");
119
+ var OpenHiStage = class _OpenHiStage extends Stage2 {
120
+ /**
121
+ * Creates a new OpenHiStage instance.
122
+ */
123
+ constructor(ohApp, props) {
124
+ super(ohApp, props.stageType, props);
125
+ this.ohApp = ohApp;
126
+ this.props = props;
127
+ Object.defineProperty(this, OPEN_HI_STAGE_SYMBOL, { value: true });
128
+ this.stageType = props.stageType;
129
+ }
130
+ /**
131
+ * Finds the OpenHiStage that contains the given construct.
132
+ */
133
+ static of(construct) {
134
+ return construct.node.scopes.reverse().find(_OpenHiStage.isOpenHiStage);
135
+ }
136
+ /**
137
+ * Type guard to check if a value is an OpenHiStage instance.
138
+ */
139
+ static isOpenHiStage(x) {
140
+ return x !== null && typeof x === "object" && OPEN_HI_STAGE_SYMBOL in x;
141
+ }
142
+ /**
143
+ * Gets all OpenHiEnvironment instances contained within this stage.
144
+ */
145
+ get environments() {
146
+ return this.node.children.filter(OpenHiEnvironment.isOpenHiEnvironment);
147
+ }
148
+ /**
149
+ * Gets the primary OpenHiEnvironment for this stage, if one exists.
150
+ */
151
+ get primaryEnvironment() {
152
+ return this.environments.find(
153
+ (env) => env.deploymentTargetRole === "primary"
154
+ );
155
+ }
156
+ /**
157
+ * Gets all secondary OpenHiEnvironment instances for this stage.
158
+ */
159
+ get secondaryEnvironments() {
160
+ return this.environments.filter(
161
+ (env) => env.deploymentTargetRole === "secondary"
162
+ );
163
+ }
164
+ };
165
+
166
+ // src/app/open-hi-app.ts
167
+ var OPEN_HI_APP_SYMBOL = /* @__PURE__ */ Symbol.for("@openhi/constructs/core.OpenHiApp");
168
+ var OpenHiApp = class _OpenHiApp extends App {
169
+ /**
170
+ * Finds the OpenHiApp instance that contains the given construct in its
171
+ * construct tree.
172
+ */
173
+ static of(construct) {
174
+ return construct.node.scopes.reverse().find(_OpenHiApp.isOpenHiApp);
175
+ }
176
+ /**
177
+ * Type guard that checks if a value is an OpenHiApp instance.
178
+ */
179
+ static isOpenHiApp(x) {
180
+ return x !== null && typeof x === "object" && OPEN_HI_APP_SYMBOL in x;
181
+ }
182
+ /**
183
+ * Creates a new OpenHiApp instance.
184
+ */
185
+ constructor(props) {
186
+ super(props);
187
+ Object.defineProperty(this, OPEN_HI_APP_SYMBOL, { value: true });
188
+ this.appName = props.appName ?? "openhi";
189
+ this.config = props.config;
190
+ Object.values(import_config2.OPEN_HI_STAGE).forEach((stageType) => {
191
+ if (this.config.deploymentTargets?.[stageType]) {
192
+ const stage = new OpenHiStage(this, { stageType });
193
+ if (this.config.deploymentTargets?.[stageType]?.[import_config2.OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY]) {
194
+ const envConfig = this.config.deploymentTargets[stageType][import_config2.OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY];
195
+ new OpenHiEnvironment(stage, {
196
+ deploymentTargetRole: import_config2.OPEN_HI_DEPLOYMENT_TARGET_ROLE.PRIMARY,
197
+ config: envConfig,
198
+ env: { account: envConfig.account, region: envConfig.region }
199
+ });
200
+ }
201
+ if (this.config.deploymentTargets?.[stageType]?.[import_config2.OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY]) {
202
+ this.config.deploymentTargets[stageType][import_config2.OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY].forEach((envConfig) => {
203
+ new OpenHiEnvironment(stage, {
204
+ deploymentTargetRole: import_config2.OPEN_HI_DEPLOYMENT_TARGET_ROLE.SECONDARY,
205
+ config: envConfig,
206
+ env: { account: envConfig.account, region: envConfig.region }
207
+ });
208
+ });
209
+ }
210
+ }
211
+ });
212
+ }
213
+ /*****************************************************************************
214
+ *
215
+ * Stages
216
+ *
217
+ ****************************************************************************/
218
+ /**
219
+ * Gets all OpenHiStage instances that are direct children of this app.
220
+
221
+ */
222
+ get stages() {
223
+ return this.node.children.filter(OpenHiStage.isOpenHiStage);
224
+ }
225
+ /**
226
+ * Gets the development stage, if it exists.
227
+ */
228
+ get devStage() {
229
+ return this.stages.find((stage) => stage.stageType === import_config2.OPEN_HI_STAGE.DEV);
230
+ }
231
+ /**
232
+ * Gets the staging stage, if it exists.
233
+ */
234
+ get stageStage() {
235
+ return this.stages.find((stage) => stage.stageType === import_config2.OPEN_HI_STAGE.STAGE);
236
+ }
237
+ /**
238
+ * Gets the production stage, if it exists.
239
+ */
240
+ get prodStage() {
241
+ return this.stages.find((stage) => stage.stageType === import_config2.OPEN_HI_STAGE.PROD);
242
+ }
243
+ /*****************************************************************************
244
+ *
245
+ * Environments
246
+ *
247
+ ****************************************************************************/
248
+ /**
249
+ * Gets all OpenHiEnvironment instances across all stages in this app.
250
+ */
251
+ get environments() {
252
+ return this.stages.flatMap((stage) => stage.environments);
253
+ }
254
+ /**
255
+ * Gets all primary environments across all stages in this app.
256
+ */
257
+ get primaryEnvironments() {
258
+ return this.environments.filter(
259
+ (env) => env.deploymentTargetRole === "primary"
260
+ );
261
+ }
262
+ /**
263
+ * Gets all secondary environments across all stages in this app.
264
+ */
265
+ get secondaryEnvironments() {
266
+ return this.environments.filter(
267
+ (env) => env.deploymentTargetRole === "secondary"
268
+ );
269
+ }
270
+ };
271
+
272
+ // src/app/open-hi-service.ts
273
+ var import_config3 = __toESM(require_lib());
274
+ import {
275
+ findGitBranch,
276
+ findGitRepoName,
277
+ hashString
278
+ } from "@codedrifters/utils";
279
+ import { RemovalPolicy, Stack, Tags } from "aws-cdk-lib";
280
+ import { paramCase } from "change-case";
281
+ var OpenHiService = class extends Stack {
282
+ /**
283
+ * Creates a new OpenHI service stack.
284
+ *
285
+ * @param ohEnv - The OpenHI environment (stage) this service belongs to
286
+ * @param id - Unique identifier for this service stack (e.g., "user-service")
287
+ * @param props - Optional properties for configuring the service
288
+ *
289
+ * @throws {Error} If account and region are not defined in props or environment
290
+ *
291
+ */
292
+ constructor(ohEnv, id, props = {}) {
293
+ const { account, region } = props.env || ohEnv;
294
+ if (!account || !region) {
295
+ throw new Error(
296
+ "Account and region must be defined in OpenHiServiceProps or OpenHiEnvironment"
297
+ );
298
+ }
299
+ const appName = props.appName ?? ohEnv.ohStage.ohApp.appName ?? "openhi";
300
+ const repoName = props.repoName ?? findGitRepoName();
301
+ const defaultReleaseBranch = props.defaultReleaseBranch ?? "main";
302
+ const branchName = props.branchName ?? (process.env.JEST_WORKER_ID ? "test-branch" : ohEnv.ohStage.stageType === import_config3.OPEN_HI_STAGE.DEV ? findGitBranch() : defaultReleaseBranch);
303
+ const environmentHash = hashString(
304
+ [appName, ohEnv.deploymentTargetRole, account, region].join("-"),
305
+ 6
306
+ );
307
+ const branchHash = hashString(
308
+ [appName, ohEnv.deploymentTargetRole, account, region, branchName].join(
309
+ "-"
310
+ ),
311
+ 6
312
+ );
313
+ const stackHash = hashString(
314
+ [
315
+ appName,
316
+ ohEnv.deploymentTargetRole,
317
+ account,
318
+ region,
319
+ branchName,
320
+ id
321
+ ].join("-"),
322
+ 6
323
+ );
324
+ const removalPolicy = props.removalPolicy ?? (ohEnv.ohStage.stageType === import_config3.OPEN_HI_STAGE.PROD ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY);
325
+ Object.assign(props, { removalPolicy });
326
+ const description = `OpenHi Service: ${id} [${branchName}] - ${branchHash}`;
327
+ super(ohEnv, [branchHash, id, account, region].join("-"), {
328
+ ...props,
329
+ description
330
+ });
331
+ this.ohEnv = ohEnv;
332
+ this.props = props;
333
+ this.serviceId = id;
334
+ this.removalPolicy = removalPolicy;
335
+ this.config = props.config ?? ohEnv.props.config;
336
+ this.deploymentTargetRole = ohEnv.deploymentTargetRole;
337
+ this.repoName = repoName;
338
+ this.appName = appName;
339
+ this.defaultReleaseBranch = defaultReleaseBranch;
340
+ this.branchName = branchName;
341
+ this.environmentHash = environmentHash;
342
+ this.branchHash = branchHash;
343
+ this.stackHash = stackHash;
344
+ Tags.of(this).add(`${appName}:repo-name`, repoName.slice(0, 255));
345
+ Tags.of(this).add(`${appName}:branch-name`, branchName.slice(0, 255));
346
+ Tags.of(this).add(`${appName}:service-type`, id.slice(0, 255));
347
+ Tags.of(this).add(
348
+ `${appName}:stage-type`,
349
+ ohEnv.ohStage.stageType.slice(0, 255)
350
+ );
351
+ }
352
+ /**
353
+ * DNS prefix for this branche's child zone.
354
+ */
355
+ get childZonePrefix() {
356
+ return paramCase(this.branchName).slice(0, 200);
357
+ }
358
+ };
359
+
360
+ // src/components/acm/root-wildcard-certificate.ts
361
+ import {
362
+ Certificate
363
+ } from "aws-cdk-lib/aws-certificatemanager";
364
+ import { StringParameter } from "aws-cdk-lib/aws-ssm";
365
+ var _RootWildcardCertificate = class _RootWildcardCertificate extends Certificate {
366
+ /**
367
+ * Using a special name here since this will be shared and used among many
368
+ * stacks and services. Use with OpenHiGlobalService.rootWildcardCertificateFromConstruct.
369
+ */
370
+ static ssmParameterName() {
371
+ return "/" + ["GLOBAL", _RootWildcardCertificate.SSM_PARAM_NAME].join("/").toUpperCase();
372
+ }
373
+ constructor(scope, props) {
374
+ super(scope, "root-wildcard-certificate", { ...props });
375
+ new StringParameter(this, "wildcard-cert-param", {
376
+ parameterName: _RootWildcardCertificate.ssmParameterName(),
377
+ stringValue: this.certificateArn
378
+ });
379
+ }
380
+ };
381
+ /**
382
+ * Used when storing the Certificate ARN in SSM.
383
+ */
384
+ _RootWildcardCertificate.SSM_PARAM_NAME = "ROOT_WILDCARD_CERT_ARN";
385
+ var RootWildcardCertificate = _RootWildcardCertificate;
386
+
387
+ // src/components/api-gateway/root-http-api.ts
388
+ import { HttpApi } from "aws-cdk-lib/aws-apigatewayv2";
389
+ var RootHttpApi = class extends HttpApi {
390
+ constructor(scope, props = {}) {
391
+ const stack = OpenHiService.of(scope);
392
+ super(scope, "http-api", {
393
+ /**
394
+ * User provided props
395
+ */
396
+ ...props,
397
+ /**
398
+ * Required
399
+ */
400
+ apiName: ["root", "http", "api", stack.branchHash].join("-")
401
+ });
402
+ }
403
+ };
404
+ /**
405
+ * Used when storing the API ID in SSM.
406
+ */
407
+ RootHttpApi.SSM_PARAM_NAME = "ROOT_HTTP_API";
408
+
409
+ // src/components/app-sync/root-graphql-api.ts
410
+ import {
411
+ Definition,
412
+ GraphqlApi
413
+ } from "aws-cdk-lib/aws-appsync";
414
+ import { CodeFirstSchema, GraphqlType, ObjectType } from "awscdk-appsync-utils";
415
+
416
+ // src/components/ssm/discoverable-string-parameter.ts
417
+ import { Tags as Tags2 } from "aws-cdk-lib";
418
+ import {
419
+ StringParameter as StringParameter2
420
+ } from "aws-cdk-lib/aws-ssm";
421
+ var _DiscoverableStringParameter = class _DiscoverableStringParameter extends StringParameter2 {
422
+ /**
423
+ * Build a param name based on predictable attributes found in services and
424
+ * constructs. Used for storage and retrieval of SSM values across services.
425
+ */
426
+ static buildParameterName(scope, props) {
427
+ const stack = OpenHiService.of(scope);
428
+ return "/" + [
429
+ _DiscoverableStringParameter.version,
430
+ props.branchHash ?? stack.branchHash,
431
+ props.serviceType ?? stack.serviceType,
432
+ props.account ?? stack.account,
433
+ props.region ?? stack.region,
434
+ props.ssmParamName
435
+ ].join("/").toUpperCase();
436
+ }
437
+ /**
438
+ * Read the string value of an SSM parameter created with DiscoverableStringParameter,
439
+ * using props that include ssmParamName and optional overrides (e.g. serviceType).
440
+ */
441
+ static valueForLookupName(scope, props) {
442
+ const paramName = _DiscoverableStringParameter.buildParameterName(
443
+ scope,
444
+ props
445
+ );
446
+ return StringParameter2.valueForStringParameter(scope, paramName);
447
+ }
448
+ constructor(scope, id, props) {
449
+ const { ssmParamName, branchHash, serviceType, account, region, ...rest } = props;
450
+ const parameterName = _DiscoverableStringParameter.buildParameterName(
451
+ scope,
452
+ props
453
+ );
454
+ super(scope, id + "-" + _DiscoverableStringParameter.version, {
455
+ ...rest,
456
+ parameterName
457
+ });
458
+ const { appName } = OpenHiService.of(scope);
459
+ Tags2.of(this).add(`${appName}:param-name`, ssmParamName);
460
+ }
461
+ };
462
+ /**
463
+ * Version of the parameter name format / discoverability schema.
464
+ * Bump when buildParameterName or tagging semantics change.
465
+ * Also used to drive replacement of parameters during CloudFormation deploys.
466
+ */
467
+ _DiscoverableStringParameter.version = "v1";
468
+ var DiscoverableStringParameter = _DiscoverableStringParameter;
469
+
470
+ // src/components/app-sync/root-graphql-api.ts
471
+ var _RootGraphqlApi = class _RootGraphqlApi extends GraphqlApi {
472
+ static fromConstruct(scope) {
473
+ const graphqlApiId = DiscoverableStringParameter.valueForLookupName(scope, {
474
+ ssmParamName: _RootGraphqlApi.SSM_PARAM_NAME,
475
+ serviceType: "graphql-api"
476
+ });
477
+ return GraphqlApi.fromGraphqlApiAttributes(scope, "root-graphql-api", {
478
+ graphqlApiId
479
+ });
480
+ }
481
+ constructor(scope, props) {
482
+ const stack = OpenHiService.of(scope);
483
+ const schema = new CodeFirstSchema();
484
+ schema.addType(
485
+ new ObjectType("Query", {
486
+ definition: { HelloWorld: GraphqlType.string() }
487
+ })
488
+ );
489
+ super(scope, "root-graphql-api", {
490
+ /**
491
+ * Defaults
492
+ */
493
+ queryDepthLimit: 2,
494
+ resolverCountLimit: 50,
495
+ definition: Definition.fromSchema(schema),
496
+ /**
497
+ * Overrideable props
498
+ */
499
+ ...props,
500
+ /**
501
+ * Required
502
+ */
503
+ name: ["root", "graphql", "api", stack.branchHash].join("-")
504
+ });
505
+ new DiscoverableStringParameter(this, "graphql-api-param", {
506
+ ssmParamName: _RootGraphqlApi.SSM_PARAM_NAME,
507
+ serviceType: "graphql-api",
508
+ stringValue: this.apiId
509
+ });
510
+ }
511
+ };
512
+ /**
513
+ * Used when storing the GraphQl API ID in SSM.
514
+ */
515
+ _RootGraphqlApi.SSM_PARAM_NAME = "ROOT_GRAPHQL_API";
516
+ var RootGraphqlApi = _RootGraphqlApi;
517
+
518
+ // src/components/cognito/cognito-user-pool.ts
519
+ import {
520
+ UserPool,
521
+ VerificationEmailStyle
522
+ } from "aws-cdk-lib/aws-cognito";
523
+ var CognitoUserPool = class extends UserPool {
524
+ constructor(scope, props = {}) {
525
+ const service = OpenHiService.of(scope);
526
+ super(scope, "user-pool", {
527
+ /**
528
+ * Defaults
529
+ */
530
+ selfSignUpEnabled: true,
531
+ signInAliases: {
532
+ email: true
533
+ },
534
+ userVerification: {
535
+ emailSubject: "Verify your email!",
536
+ emailBody: "Your verification code is {####}.",
537
+ emailStyle: VerificationEmailStyle.CODE
538
+ },
539
+ removalPolicy: props.removalPolicy ?? service.removalPolicy,
540
+ /**
541
+ * Over-rideable props
542
+ */
543
+ ...props,
544
+ /**
545
+ * Required
546
+ */
547
+ userPoolName: ["cognito", "user", "pool", service.branchHash].join("-")
548
+ });
549
+ }
550
+ };
551
+ /**
552
+ * Used when storing the User Pool ID in SSM.
553
+ */
554
+ CognitoUserPool.SSM_PARAM_NAME = "COGNITO_USER_POOL";
555
+
556
+ // src/components/cognito/cognito-user-pool-client.ts
557
+ import { UserPoolClient } from "aws-cdk-lib/aws-cognito";
558
+ var CognitoUserPoolClient = class extends UserPoolClient {
559
+ constructor(scope, props) {
560
+ super(scope, "user-pool-client", {
561
+ /**
562
+ * Defaults
563
+ */
564
+ generateSecret: false,
565
+ oAuth: {
566
+ flows: {
567
+ authorizationCodeGrant: true,
568
+ implicitCodeGrant: true
569
+ },
570
+ callbackUrls: [`https://localhost:3000/oauth/callback`]
571
+ },
572
+ /**
573
+ * Overrideable props
574
+ */
575
+ ...props
576
+ });
577
+ }
578
+ };
579
+ /**
580
+ * Used when storing the User Pool Client ID in SSM.
581
+ */
582
+ CognitoUserPoolClient.SSM_PARAM_NAME = "COGNITO_USER_POOL_CLIENT";
583
+
584
+ // src/components/cognito/cognito-user-pool-domain.ts
585
+ import { UserPoolDomain } from "aws-cdk-lib/aws-cognito";
586
+ var CognitoUserPoolDomain = class extends UserPoolDomain {
587
+ constructor(scope, props) {
588
+ const id = props.cognitoDomain?.domainPrefix ? "cognito-domain" : "custom-domain";
589
+ super(scope, id, {
590
+ ...props
591
+ });
592
+ }
593
+ };
594
+ /**
595
+ * Used when storing the User Pool Domain in SSM.
596
+ */
597
+ CognitoUserPoolDomain.SSM_PARAM_NAME = "COGNITO_USER_POOL_DOMAIN";
598
+
599
+ // src/components/cognito/cognito-user-pool-kms-key.ts
600
+ import { Key } from "aws-cdk-lib/aws-kms";
601
+ var CognitoUserPoolKmsKey = class extends Key {
602
+ constructor(scope, props = {}) {
603
+ const service = OpenHiService.of(scope);
604
+ super(scope, "kms-key", {
605
+ ...props,
606
+ // alias: ["alias", "cognito", service.branchHash].join("/"),
607
+ description: `KMS Key for Cognito User Pool - ${service.branchHash}`,
608
+ removalPolicy: props.removalPolicy ?? service.removalPolicy
609
+ });
610
+ }
611
+ };
612
+ /**
613
+ * Used when storing the KMS Key in SSM.
614
+ */
615
+ CognitoUserPoolKmsKey.SSM_PARAM_NAME = "COGNITO_USER_POOL_KMS_KEY";
616
+
617
+ // src/components/dynamodb/dynamo-db-data-store.ts
618
+ import {
619
+ AttributeType,
620
+ BillingMode,
621
+ ProjectionType,
622
+ Table
623
+ } from "aws-cdk-lib/aws-dynamodb";
624
+ function getDynamoDbDataStoreTableName(scope) {
625
+ const stack = OpenHiService.of(scope);
626
+ return `data-store-${stack.branchHash}`;
627
+ }
628
+ var DynamoDbDataStore = class extends Table {
629
+ constructor(scope, id, props = {}) {
630
+ const service = OpenHiService.of(scope);
631
+ super(scope, id, {
632
+ ...props,
633
+ tableName: getDynamoDbDataStoreTableName(scope),
634
+ partitionKey: {
635
+ name: "PK",
636
+ type: AttributeType.STRING
637
+ },
638
+ sortKey: {
639
+ name: "SK",
640
+ type: AttributeType.STRING
641
+ },
642
+ billingMode: BillingMode.PAY_PER_REQUEST,
643
+ removalPolicy: props.removalPolicy ?? service.removalPolicy
644
+ });
645
+ this.addGlobalSecondaryIndex({
646
+ indexName: "GSI1",
647
+ partitionKey: {
648
+ name: "GSI1PK",
649
+ type: AttributeType.STRING
650
+ },
651
+ sortKey: {
652
+ name: "GSI1SK",
653
+ type: AttributeType.STRING
654
+ },
655
+ projectionType: ProjectionType.INCLUDE,
656
+ nonKeyAttributes: ["srcType", "srcId", "path", "srcPk", "srcSk", "ts"]
657
+ });
658
+ this.addGlobalSecondaryIndex({
659
+ indexName: "GSI2",
660
+ partitionKey: {
661
+ name: "GSI2PK",
662
+ type: AttributeType.STRING
663
+ },
664
+ sortKey: {
665
+ name: "GSI2SK",
666
+ type: AttributeType.STRING
667
+ },
668
+ projectionType: ProjectionType.INCLUDE,
669
+ nonKeyAttributes: ["resourcePk", "resourceSk", "display", "status"]
670
+ });
671
+ this.addGlobalSecondaryIndex({
672
+ indexName: "GSI3",
673
+ partitionKey: {
674
+ name: "GSI3PK",
675
+ type: AttributeType.STRING
676
+ },
677
+ sortKey: {
678
+ name: "GSI3SK",
679
+ type: AttributeType.STRING
680
+ },
681
+ projectionType: ProjectionType.INCLUDE,
682
+ nonKeyAttributes: ["resourcePk", "resourceSk"]
683
+ });
684
+ this.addGlobalSecondaryIndex({
685
+ indexName: "GSI4",
686
+ partitionKey: {
687
+ name: "GSI4PK",
688
+ type: AttributeType.STRING
689
+ },
690
+ sortKey: {
691
+ name: "GSI4SK",
692
+ type: AttributeType.STRING
693
+ },
694
+ projectionType: ProjectionType.ALL
695
+ });
696
+ }
697
+ };
698
+
699
+ // src/components/event-bridge/data-event-bus.ts
700
+ import { EventBus } from "aws-cdk-lib/aws-events";
701
+ var DataEventBus = class _DataEventBus extends EventBus {
702
+ /*****************************************************************************
703
+ *
704
+ * Return a name for this EventBus based on the stack environment hash. This
705
+ * name is common across all stacks since it's using the environment hash in
706
+ * it's name.
707
+ *
708
+ ****************************************************************************/
709
+ static getEventBusName(scope) {
710
+ const stack = OpenHiService.of(scope);
711
+ return `data${stack.branchHash}`;
712
+ }
713
+ constructor(scope, props) {
714
+ super(scope, "data-event-bus", {
715
+ ...props,
716
+ eventBusName: _DataEventBus.getEventBusName(scope)
717
+ });
718
+ }
719
+ };
720
+
721
+ // src/components/event-bridge/ops-event-bus.ts
722
+ import { EventBus as EventBus2 } from "aws-cdk-lib/aws-events";
723
+ var OpsEventBus = class _OpsEventBus extends EventBus2 {
724
+ /*****************************************************************************
725
+ *
726
+ * Return a name for this EventBus based on the stack environment hash. This
727
+ * name is common across all stacks since it's using the environment hash in
728
+ * it's name.
729
+ *
730
+ ****************************************************************************/
731
+ static getEventBusName(scope) {
732
+ const stack = OpenHiService.of(scope);
733
+ return `ops${stack.branchHash}`;
734
+ }
735
+ constructor(scope, props) {
736
+ super(scope, "ops-event-bus", {
737
+ ...props,
738
+ eventBusName: _OpsEventBus.getEventBusName(scope)
739
+ });
740
+ }
741
+ };
742
+
743
+ // src/components/route-53/child-hosted-zone.ts
744
+ import { Duration } from "aws-cdk-lib";
745
+ import {
746
+ HostedZone,
747
+ NsRecord
748
+ } from "aws-cdk-lib/aws-route53";
749
+ var ChildHostedZone = class extends HostedZone {
750
+ constructor(scope, id, props) {
751
+ super(scope, id, { ...props });
752
+ new NsRecord(this, "child-ns-record", {
753
+ zone: props.parentHostedZone,
754
+ recordName: this.zoneName,
755
+ values: this.hostedZoneNameServers || [],
756
+ ttl: Duration.minutes(5)
757
+ });
758
+ }
759
+ };
760
+ /**
761
+ * Used when storing the child zone ID in SSM. Use {@link OpenHiGlobalService.childHostedZoneFromConstruct} to look up.
762
+ */
763
+ ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
764
+
765
+ // src/components/route-53/root-hosted-zone.ts
766
+ import { Construct } from "constructs";
767
+ var RootHostedZone = class extends Construct {
768
+ };
769
+
770
+ // src/services/open-hi-auth-service.ts
771
+ import {
772
+ UserPool as UserPool2,
773
+ UserPoolClient as UserPoolClient2,
774
+ UserPoolDomain as UserPoolDomain2
775
+ } from "aws-cdk-lib/aws-cognito";
776
+ import { Key as Key2 } from "aws-cdk-lib/aws-kms";
777
+ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
778
+ constructor(ohEnv, props = {}) {
779
+ super(ohEnv, _OpenHiAuthService.SERVICE_TYPE, props);
780
+ this.props = props;
781
+ this.userPoolKmsKey = this.createUserPoolKmsKey();
782
+ this.userPool = this.createUserPool();
783
+ this.userPoolClient = this.createUserPoolClient();
784
+ this.userPoolDomain = this.createUserPoolDomain();
785
+ }
786
+ /**
787
+ * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
788
+ */
789
+ static userPoolFromConstruct(scope) {
790
+ const userPoolId = DiscoverableStringParameter.valueForLookupName(scope, {
791
+ ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
792
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
793
+ });
794
+ return UserPool2.fromUserPoolId(scope, "user-pool", userPoolId);
795
+ }
796
+ /**
797
+ * Returns an IUserPoolClient by looking up the Auth stack's User Pool Client ID from SSM.
798
+ */
799
+ static userPoolClientFromConstruct(scope) {
800
+ const userPoolClientId = DiscoverableStringParameter.valueForLookupName(
801
+ scope,
802
+ {
803
+ ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,
804
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
805
+ }
806
+ );
807
+ return UserPoolClient2.fromUserPoolClientId(
808
+ scope,
809
+ "user-pool-client",
810
+ userPoolClientId
811
+ );
812
+ }
813
+ /**
814
+ * Returns an IUserPoolDomain by looking up the Auth stack's User Pool Domain from SSM.
815
+ */
816
+ static userPoolDomainFromConstruct(scope) {
817
+ const domainName = DiscoverableStringParameter.valueForLookupName(scope, {
818
+ ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,
819
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
820
+ });
821
+ return UserPoolDomain2.fromDomainName(scope, "user-pool-domain", domainName);
822
+ }
823
+ /**
824
+ * Returns an IKey (KMS) by looking up the Auth stack's User Pool KMS Key ARN from SSM.
825
+ */
826
+ static userPoolKmsKeyFromConstruct(scope) {
827
+ const keyArn = DiscoverableStringParameter.valueForLookupName(scope, {
828
+ ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,
829
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
830
+ });
831
+ return Key2.fromKeyArn(scope, "kms-key", keyArn);
832
+ }
833
+ get serviceType() {
834
+ return _OpenHiAuthService.SERVICE_TYPE;
835
+ }
836
+ /**
837
+ * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.
838
+ * Look up via {@link OpenHiAuthService.userPoolKmsKeyFromConstruct}.
839
+ * Override to customize.
840
+ */
841
+ createUserPoolKmsKey() {
842
+ const key = new CognitoUserPoolKmsKey(this);
843
+ new DiscoverableStringParameter(this, "kms-key-param", {
844
+ ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,
845
+ stringValue: key.keyArn,
846
+ description: "KMS key ARN for Cognito User Pool (e.g. custom sender); cross-stack reference"
847
+ });
848
+ return key;
849
+ }
850
+ /**
851
+ * Creates the Cognito User Pool and exports its ID to SSM.
852
+ * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
853
+ * Override to customize.
854
+ */
855
+ createUserPool() {
856
+ const userPool = new CognitoUserPool(this, {
857
+ ...this.props.userPoolProps,
858
+ customSenderKmsKey: this.userPoolKmsKey
859
+ });
860
+ new DiscoverableStringParameter(this, "user-pool-param", {
861
+ ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
862
+ stringValue: userPool.userPoolId,
863
+ description: "Cognito User Pool ID for this Auth stack; cross-stack reference"
864
+ });
865
+ return userPool;
866
+ }
867
+ /**
868
+ * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
869
+ * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
870
+ * Override to customize.
871
+ */
872
+ createUserPoolClient() {
873
+ const client = new CognitoUserPoolClient(this, {
874
+ userPool: this.userPool
875
+ });
876
+ new DiscoverableStringParameter(this, "user-pool-client-param", {
877
+ ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,
878
+ stringValue: client.userPoolClientId,
879
+ description: "Cognito User Pool Client ID for this Auth stack; cross-stack reference"
880
+ });
881
+ return client;
882
+ }
883
+ /**
884
+ * Creates the User Pool Domain (Cognito hosted UI) and exports domain name to SSM.
885
+ * Look up via {@link OpenHiAuthService.userPoolDomainFromConstruct}.
886
+ * Override to customize.
887
+ */
888
+ createUserPoolDomain() {
889
+ const domain = new CognitoUserPoolDomain(this, {
890
+ userPool: this.userPool,
891
+ cognitoDomain: {
892
+ domainPrefix: `auth-${this.branchHash}`
893
+ }
894
+ });
895
+ new DiscoverableStringParameter(this, "user-pool-domain-param", {
896
+ ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,
897
+ stringValue: domain.domainName,
898
+ description: "Cognito User Pool Domain (hosted UI) for this Auth stack; cross-stack reference"
899
+ });
900
+ return domain;
901
+ }
902
+ };
903
+ _OpenHiAuthService.SERVICE_TYPE = "auth";
904
+ var OpenHiAuthService = _OpenHiAuthService;
905
+
906
+ // src/services/open-hi-global-service.ts
907
+ import {
908
+ Certificate as Certificate2,
909
+ CertificateValidation
910
+ } from "aws-cdk-lib/aws-certificatemanager";
911
+ import {
912
+ HostedZone as HostedZone2
913
+ } from "aws-cdk-lib/aws-route53";
914
+ import { StringParameter as StringParameter3 } from "aws-cdk-lib/aws-ssm";
915
+ var _OpenHiGlobalService = class _OpenHiGlobalService extends OpenHiService {
916
+ /**
917
+ * Returns an IHostedZone from the given attributes (no SSM). Use when the zone is imported from config.
918
+ */
919
+ static rootHostedZoneFromConstruct(scope, props) {
920
+ return HostedZone2.fromHostedZoneAttributes(scope, "root-zone", props);
921
+ }
922
+ /**
923
+ * Returns an ICertificate by looking up the Global stack's wildcard cert ARN from SSM.
924
+ */
925
+ static rootWildcardCertificateFromConstruct(scope) {
926
+ const certificateArn = StringParameter3.valueForStringParameter(
927
+ scope,
928
+ RootWildcardCertificate.ssmParameterName()
929
+ );
930
+ return Certificate2.fromCertificateArn(
931
+ scope,
932
+ "wildcard-certificate",
933
+ certificateArn
934
+ );
935
+ }
936
+ /**
937
+ * Returns an IHostedZone by looking up the child hosted zone ID from SSM. Defaults to GLOBAL service type.
938
+ */
939
+ static childHostedZoneFromConstruct(scope, props) {
940
+ const hostedZoneId = DiscoverableStringParameter.valueForLookupName(scope, {
941
+ ssmParamName: ChildHostedZone.SSM_PARAM_NAME,
942
+ serviceType: props.serviceType ?? _OpenHiGlobalService.SERVICE_TYPE
943
+ });
944
+ return HostedZone2.fromHostedZoneAttributes(scope, "child-zone", {
945
+ hostedZoneId,
946
+ zoneName: props.zoneName
947
+ });
948
+ }
949
+ get serviceType() {
950
+ return _OpenHiGlobalService.SERVICE_TYPE;
951
+ }
952
+ constructor(ohEnv, props = {}) {
953
+ super(ohEnv, _OpenHiGlobalService.SERVICE_TYPE, props);
954
+ this.validateConfig(props);
955
+ this.rootHostedZone = this.createRootHostedZone();
956
+ this.childHostedZone = this.createChildHostedZone();
957
+ this.rootWildcardCertificate = this.createRootWildcardCertificate();
958
+ }
959
+ /**
960
+ * Validates that config required for the Global stack is present.
961
+ */
962
+ validateConfig(props) {
963
+ const { config } = props;
964
+ if (!config) {
965
+ throw new Error("Config is required");
966
+ }
967
+ if (!config.zoneName) {
968
+ throw new Error("Zone name is required to import the root zone");
969
+ }
970
+ if (!config.hostedZoneId) {
971
+ throw new Error("Hosted zone ID is required to import the root zone");
972
+ }
973
+ }
974
+ /**
975
+ * Creates the root hosted zone (imported via attributes from config).
976
+ * Override to customize or create the zone.
977
+ */
978
+ createRootHostedZone() {
979
+ return _OpenHiGlobalService.rootHostedZoneFromConstruct(this, {
980
+ zoneName: this.config.zoneName,
981
+ hostedZoneId: this.config.hostedZoneId
982
+ });
983
+ }
984
+ /**
985
+ * Creates the optional child hosted zone (e.g. branch subdomain).
986
+ * Override to create a child zone when config provides childHostedZoneAttributes.
987
+ * If you create a ChildHostedZone, also create a DiscoverableStringParameter
988
+ * with ChildHostedZone.SSM_PARAM_NAME and the zone's hostedZoneId.
989
+ */
990
+ createChildHostedZone() {
991
+ return void 0;
992
+ }
993
+ /**
994
+ * Creates the root wildcard certificate. On main branch, creates a new cert
995
+ * with DNS validation; otherwise imports from SSM.
996
+ * Override to customize certificate creation.
997
+ */
998
+ createRootWildcardCertificate() {
999
+ if (this.branchName === "main") {
1000
+ return new RootWildcardCertificate(this, {
1001
+ domainName: `*.${this.rootHostedZone.zoneName}`,
1002
+ subjectAlternativeNames: [this.rootHostedZone.zoneName],
1003
+ validation: CertificateValidation.fromDns(this.rootHostedZone)
1004
+ });
1005
+ }
1006
+ return _OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);
1007
+ }
1008
+ };
1009
+ _OpenHiGlobalService.SERVICE_TYPE = "global";
1010
+ var OpenHiGlobalService = _OpenHiGlobalService;
1011
+
1012
+ // src/services/open-hi-rest-api-service.ts
1013
+ import {
1014
+ DomainName,
1015
+ HttpApi as HttpApi2,
1016
+ HttpMethod,
1017
+ HttpRoute,
1018
+ HttpRouteKey
1019
+ } from "aws-cdk-lib/aws-apigatewayv2";
1020
+ import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
1021
+ import {
1022
+ ARecord,
1023
+ HostedZone as HostedZone3,
1024
+ RecordTarget
1025
+ } from "aws-cdk-lib/aws-route53";
1026
+ import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
1027
+
1028
+ // src/services/open-hi-data-service.ts
1029
+ import { Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
1030
+ import { EventBus as EventBus3 } from "aws-cdk-lib/aws-events";
1031
+ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1032
+ /**
1033
+ * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1034
+ */
1035
+ static dataEventBusFromConstruct(scope) {
1036
+ return EventBus3.fromEventBusName(
1037
+ scope,
1038
+ "data-event-bus",
1039
+ DataEventBus.getEventBusName(scope)
1040
+ );
1041
+ }
1042
+ /**
1043
+ * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1044
+ */
1045
+ static opsEventBusFromConstruct(scope) {
1046
+ return EventBus3.fromEventBusName(
1047
+ scope,
1048
+ "ops-event-bus",
1049
+ OpsEventBus.getEventBusName(scope)
1050
+ );
1051
+ }
1052
+ /**
1053
+ * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
1054
+ */
1055
+ static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1056
+ return Table2.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1057
+ }
1058
+ get serviceType() {
1059
+ return _OpenHiDataService.SERVICE_TYPE;
1060
+ }
1061
+ constructor(ohEnv, props = {}) {
1062
+ super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
1063
+ this.dataEventBus = this.createDataEventBus();
1064
+ this.opsEventBus = this.createOpsEventBus();
1065
+ this.dataStore = this.createDataStore();
1066
+ }
1067
+ /**
1068
+ * Creates the data event bus.
1069
+ * Override to customize.
1070
+ */
1071
+ createDataEventBus() {
1072
+ return new DataEventBus(this);
1073
+ }
1074
+ /**
1075
+ * Creates the ops event bus.
1076
+ * Override to customize.
1077
+ */
1078
+ createOpsEventBus() {
1079
+ return new OpsEventBus(this);
1080
+ }
1081
+ /**
1082
+ * Creates the single-table DynamoDB data store.
1083
+ * Override to customize.
1084
+ */
1085
+ createDataStore() {
1086
+ return new DynamoDbDataStore(this, "dynamo-db-data-store");
1087
+ }
1088
+ };
1089
+ _OpenHiDataService.SERVICE_TYPE = "data";
1090
+ var OpenHiDataService = _OpenHiDataService;
1091
+
1092
+ // src/data/lambda/rest-api-lambda.ts
1093
+ import path from "path";
1094
+ import { Runtime } from "aws-cdk-lib/aws-lambda";
1095
+ import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
1096
+ import { Construct as Construct2 } from "constructs";
1097
+ var RestApiLambda = class extends Construct2 {
1098
+ constructor(scope, props) {
1099
+ super(scope, "rest-api-lambda");
1100
+ this.lambda = new NodejsFunction(this, "handler", {
1101
+ entry: path.join(__dirname, "rest-api-lambda.handler.js"),
1102
+ runtime: Runtime.NODEJS_LATEST,
1103
+ environment: {
1104
+ DYNAMO_TABLE_NAME: props.dynamoTableName
1105
+ }
1106
+ });
1107
+ }
1108
+ };
1109
+
1110
+ // src/services/open-hi-rest-api-service.ts
1111
+ var REST_API_BASE_URL_SSM_NAME = "REST_API_BASE_URL";
1112
+ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1113
+ /**
1114
+ * Returns an IHttpApi by looking up the REST API stack's HTTP API ID from SSM.
1115
+ */
1116
+ static rootHttpApiFromConstruct(scope) {
1117
+ const httpApiId = DiscoverableStringParameter.valueForLookupName(scope, {
1118
+ ssmParamName: RootHttpApi.SSM_PARAM_NAME,
1119
+ serviceType: _OpenHiRestApiService.SERVICE_TYPE
1120
+ });
1121
+ return HttpApi2.fromHttpApiAttributes(scope, "http-api", { httpApiId });
1122
+ }
1123
+ /**
1124
+ * Returns the REST API base URL (e.g. https://api.example.com) by looking it up from SSM.
1125
+ * Use in other stacks for E2E, scripts, or config.
1126
+ */
1127
+ static restApiBaseUrlFromConstruct(scope) {
1128
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1129
+ ssmParamName: REST_API_BASE_URL_SSM_NAME,
1130
+ serviceType: _OpenHiRestApiService.SERVICE_TYPE
1131
+ });
1132
+ }
1133
+ get serviceType() {
1134
+ return _OpenHiRestApiService.SERVICE_TYPE;
1135
+ }
1136
+ constructor(ohEnv, props = {}) {
1137
+ super(ohEnv, _OpenHiRestApiService.SERVICE_TYPE, props);
1138
+ this.validateConfig(props);
1139
+ const hostedZone = this.createHostedZone();
1140
+ const certificate = this.createCertificate();
1141
+ const apiDomainName = this.createApiDomainNameString(hostedZone);
1142
+ this.createRestApiBaseUrlParameter(apiDomainName);
1143
+ const domainName = this.createDomainName(hostedZone, certificate);
1144
+ this.rootHttpApi = this.createRootHttpApi(domainName);
1145
+ this.createRestApiLambdaAndRoutes(hostedZone, domainName);
1146
+ }
1147
+ /**
1148
+ * Validates that config required for the REST API stack is present.
1149
+ */
1150
+ validateConfig(props) {
1151
+ const { config } = props;
1152
+ if (!config) {
1153
+ throw new Error("Config is required");
1154
+ }
1155
+ if (!config.hostedZoneId) {
1156
+ throw new Error("Hosted zone ID is required");
1157
+ }
1158
+ if (!config.zoneName) {
1159
+ throw new Error("Zone name is required");
1160
+ }
1161
+ }
1162
+ /**
1163
+ * Creates the hosted zone reference (imported from config).
1164
+ * Override to customize.
1165
+ */
1166
+ createHostedZone() {
1167
+ const { config } = this.props;
1168
+ return HostedZone3.fromHostedZoneAttributes(this, "root-zone", {
1169
+ hostedZoneId: config.hostedZoneId,
1170
+ zoneName: config.zoneName
1171
+ });
1172
+ }
1173
+ /**
1174
+ * Creates the wildcard certificate (imported from Global stack via SSM).
1175
+ * Override to customize.
1176
+ */
1177
+ createCertificate() {
1178
+ return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);
1179
+ }
1180
+ /**
1181
+ * Returns the API domain name string (e.g. api.example.com or api-{prefix}.example.com).
1182
+ * Override to customize.
1183
+ */
1184
+ createApiDomainNameString(hostedZone) {
1185
+ const apiPrefix = this.branchName === "main" ? `api` : `api-${this.childZonePrefix}`;
1186
+ return [apiPrefix, hostedZone.zoneName].join(".");
1187
+ }
1188
+ /**
1189
+ * Creates the SSM parameter for the REST API base URL.
1190
+ * Look up via {@link OpenHiRestApiService.restApiBaseUrlFromConstruct}.
1191
+ * Override to customize.
1192
+ */
1193
+ createRestApiBaseUrlParameter(apiDomainName) {
1194
+ const restApiBaseUrl = `https://${apiDomainName}`;
1195
+ new DiscoverableStringParameter(this, "rest-api-base-url-param", {
1196
+ ssmParamName: REST_API_BASE_URL_SSM_NAME,
1197
+ stringValue: restApiBaseUrl,
1198
+ description: "REST API base URL for this deployment (E2E, scripts)"
1199
+ });
1200
+ }
1201
+ /**
1202
+ * Creates the API Gateway custom domain name resource.
1203
+ * Override to customize.
1204
+ */
1205
+ createDomainName(_hostedZone, certificate) {
1206
+ const apiDomainName = this.createApiDomainNameString(_hostedZone);
1207
+ return new DomainName(this, "domain", {
1208
+ domainName: apiDomainName,
1209
+ certificate
1210
+ });
1211
+ }
1212
+ /**
1213
+ * Creates the Lambda integration, HTTP routes, and API DNS record.
1214
+ * Override to customize. Uses {@link rootHttpApi} set by the constructor.
1215
+ */
1216
+ createRestApiLambdaAndRoutes(hostedZone, domainName) {
1217
+ const dataStoreTable = OpenHiDataService.dynamoDbDataStoreFromConstruct(this);
1218
+ const { lambda } = new RestApiLambda(this, {
1219
+ dynamoTableName: dataStoreTable.tableName
1220
+ });
1221
+ dataStoreTable.grant(
1222
+ lambda,
1223
+ "dynamodb:GetItem",
1224
+ "dynamodb:Query",
1225
+ "dynamodb:BatchGetItem",
1226
+ "dynamodb:ConditionCheckItem",
1227
+ "dynamodb:DescribeTable",
1228
+ "dynamodb:BatchWriteItem",
1229
+ "dynamodb:PutItem",
1230
+ "dynamodb:UpdateItem",
1231
+ "dynamodb:DeleteItem"
1232
+ );
1233
+ const integration = new HttpLambdaIntegration("lambda-integration", lambda);
1234
+ new HttpRoute(this, "proxy-route-root", {
1235
+ httpApi: this.rootHttpApi,
1236
+ routeKey: HttpRouteKey.with("/", HttpMethod.ANY),
1237
+ integration
1238
+ });
1239
+ new HttpRoute(this, "proxy-route", {
1240
+ httpApi: this.rootHttpApi,
1241
+ routeKey: HttpRouteKey.with("/{proxy+}", HttpMethod.ANY),
1242
+ integration
1243
+ });
1244
+ const apiPrefix = this.branchName === "main" ? `api` : `api-${this.childZonePrefix}`;
1245
+ new ARecord(this, "api-a-record", {
1246
+ zone: hostedZone,
1247
+ recordName: apiPrefix,
1248
+ target: RecordTarget.fromAlias(
1249
+ new ApiGatewayv2DomainProperties(
1250
+ domainName.regionalDomainName,
1251
+ domainName.regionalHostedZoneId
1252
+ )
1253
+ )
1254
+ });
1255
+ }
1256
+ /**
1257
+ * Creates the Root HTTP API with default domain mapping and exports API ID to SSM.
1258
+ * Look up via {@link OpenHiRestApiService.rootHttpApiFromConstruct}.
1259
+ * Override to customize.
1260
+ */
1261
+ createRootHttpApi(domainName) {
1262
+ const rootHttpApi = new RootHttpApi(this, {
1263
+ defaultDomainMapping: {
1264
+ domainName,
1265
+ mappingKey: void 0
1266
+ }
1267
+ });
1268
+ new DiscoverableStringParameter(this, "http-api-url-param", {
1269
+ ssmParamName: RootHttpApi.SSM_PARAM_NAME,
1270
+ stringValue: rootHttpApi.httpApiId,
1271
+ description: "API Gateway HTTP API ID for this REST API stack (cross-stack reference)"
1272
+ });
1273
+ return rootHttpApi;
1274
+ }
1275
+ };
1276
+ _OpenHiRestApiService.SERVICE_TYPE = "rest-api";
1277
+ var OpenHiRestApiService = _OpenHiRestApiService;
1278
+ export {
1279
+ ChildHostedZone,
1280
+ CognitoUserPool,
1281
+ CognitoUserPoolClient,
1282
+ CognitoUserPoolDomain,
1283
+ CognitoUserPoolKmsKey,
1284
+ DataEventBus,
1285
+ DiscoverableStringParameter,
1286
+ DynamoDbDataStore,
1287
+ OpenHiApp,
1288
+ OpenHiAuthService,
1289
+ OpenHiDataService,
1290
+ OpenHiEnvironment,
1291
+ OpenHiGlobalService,
1292
+ OpenHiRestApiService,
1293
+ OpenHiService,
1294
+ OpenHiStage,
1295
+ OpsEventBus,
1296
+ REST_API_BASE_URL_SSM_NAME,
1297
+ RootGraphqlApi,
1298
+ RootHostedZone,
1299
+ RootHttpApi,
1300
+ RootWildcardCertificate,
1301
+ getDynamoDbDataStoreTableName
1302
+ };
1303
+ //# sourceMappingURL=index.mjs.map