@aws/nx-plugin 0.1.6 → 0.2.0

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 (115) hide show
  1. package/LICENSE-THIRD-PARTY +114 -244
  2. package/generators.json +1 -7
  3. package/package.json +1 -1
  4. package/src/cloudscape-website/app/README.md +84 -48
  5. package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +157 -218
  6. package/src/cloudscape-website/app/files/app/README.md.template +44 -0
  7. package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
  8. package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
  9. package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
  10. package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
  11. package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
  12. package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
  13. package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +74 -144
  14. package/src/cloudscape-website/app/generator.js +74 -64
  15. package/src/cloudscape-website/app/generator.js.map +1 -1
  16. package/src/cloudscape-website/app/schema.d.ts +3 -4
  17. package/src/cloudscape-website/app/schema.json +1 -24
  18. package/src/cloudscape-website/cognito-auth/README.md +53 -32
  19. package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +161 -125
  20. package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
  21. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
  22. package/src/cloudscape-website/cognito-auth/generator.js +129 -46
  23. package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
  24. package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
  25. package/src/cloudscape-website/cognito-auth/schema.json +7 -1
  26. package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +15 -17
  27. package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
  28. package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
  29. package/src/cloudscape-website/runtime-config/generator.js +3 -1
  30. package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
  31. package/src/infra/app/README.md +71 -46
  32. package/src/infra/app/__snapshots__/generator.spec.ts.snap +114 -252
  33. package/src/infra/app/files/app/README.md.template +76 -0
  34. package/src/infra/app/files/app/src/main.ts.template +18 -0
  35. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
  36. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
  37. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
  38. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
  39. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
  40. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
  41. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
  42. package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
  43. package/src/infra/app/generator.js +17 -3
  44. package/src/infra/app/generator.js.map +1 -1
  45. package/src/infra/app/schema.d.ts +10 -1
  46. package/src/infra/app/schema.json +16 -8
  47. package/src/trpc/backend/README.md +102 -80
  48. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +37 -17
  49. package/src/trpc/backend/files/backend/README.md.template +33 -0
  50. package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
  51. package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
  52. package/src/trpc/backend/files/schema/README.md.template +33 -0
  53. package/src/trpc/backend/generator.js +29 -43
  54. package/src/trpc/backend/generator.js.map +1 -1
  55. package/src/trpc/backend/schema.d.ts +3 -1
  56. package/src/trpc/backend/schema.json +8 -13
  57. package/src/trpc/react/README.md +46 -66
  58. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
  59. package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
  60. package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
  61. package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
  62. package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
  63. package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
  64. package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
  65. package/src/trpc/react/generator.js +123 -24
  66. package/src/trpc/react/generator.js.map +1 -1
  67. package/src/trpc/react/schema.json +2 -2
  68. package/src/ts/cjs-to-esm/generator.js.map +1 -1
  69. package/src/ts/lib/eslint.d.ts +1 -1
  70. package/src/ts/lib/eslint.js +59 -11
  71. package/src/ts/lib/eslint.js.map +1 -1
  72. package/src/ts/lib/files/README.md.template +33 -0
  73. package/src/ts/lib/generator.js +11 -4
  74. package/src/ts/lib/generator.js.map +1 -1
  75. package/src/ts/lib/schema.d.ts +1 -3
  76. package/src/ts/lib/schema.json +2 -15
  77. package/src/ts/lib/ts-project-utils.js.map +1 -1
  78. package/src/ts/lib/vitest.js +14 -0
  79. package/src/ts/lib/vitest.js.map +1 -1
  80. package/src/utils/ast.d.ts +13 -0
  81. package/src/utils/ast.js +102 -0
  82. package/src/utils/ast.js.map +1 -0
  83. package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
  84. package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
  85. package/src/utils/files/common/constructs/src/index.ts.template +2 -1
  86. package/src/utils/files/common/readme/README.md.template +33 -0
  87. package/src/utils/files/common/types/src/runtime-config.ts.template +1 -13
  88. package/src/utils/format.js.map +1 -1
  89. package/src/utils/names.d.ts +2 -0
  90. package/src/utils/names.js +27 -0
  91. package/src/utils/names.js.map +1 -0
  92. package/src/utils/npm-scope.js.map +1 -1
  93. package/src/utils/paths.js.map +1 -1
  94. package/src/utils/shared-constructs.js +37 -4
  95. package/src/utils/shared-constructs.js.map +1 -1
  96. package/src/utils/versions.d.ts +15 -9
  97. package/src/utils/versions.js +14 -8
  98. package/src/utils/versions.js.map +1 -1
  99. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
  100. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
  101. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
  102. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
  103. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
  104. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
  105. package/src/gitlab/generator.d.ts +0 -8
  106. package/src/gitlab/generator.js +0 -16
  107. package/src/gitlab/generator.js.map +0 -1
  108. package/src/gitlab/schema.d.ts +0 -9
  109. package/src/gitlab/schema.json +0 -52
  110. package/src/infra/app/files/src/main.ts.template +0 -37
  111. package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
  112. package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
  113. /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
  114. /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
  115. /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
@@ -75,12 +75,7 @@ export default defineConfig({
75
75
  `;
76
76
 
77
77
  exports[`cloudscape-website generator > should generate base files and structure > app-layout.tsx 1`] = `
78
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
79
- SPDX-License-Identifier: Apache-2.0 */
80
- import { useCognitoAuthContext } from '@aws-northstar/ui';
81
- import getBreadcrumbs from '@aws-northstar/ui/components/AppLayout/utils/getBreadcrumbs';
82
- import NavHeader from '@aws-northstar/ui/components/AppLayout/components/NavHeader';
83
- import * as React from 'react';
78
+ "import * as React from 'react';
84
79
  import { createContext, useCallback, useEffect, useState } from 'react';
85
80
  import { NavItems } from './navitems';
86
81
  import Config from '../../config';
@@ -90,11 +85,42 @@ import {
90
85
  BreadcrumbGroup,
91
86
  BreadcrumbGroupProps,
92
87
  SideNavigation,
88
+ TopNavigation,
93
89
  } from '@cloudscape-design/components';
94
90
  import AppLayout, {
95
91
  AppLayoutProps,
96
92
  } from '@cloudscape-design/components/app-layout';
97
- import { useLocation, useNavigate } from 'react-router-dom';
93
+ import { matchPath, useLocation, useNavigate } from 'react-router-dom';
94
+
95
+ const getBreadcrumbs = (
96
+ pathName: string,
97
+ search: string,
98
+ defaultBreadcrumb: string,
99
+ availableRoutes?: string[]
100
+ ) => {
101
+ const segments = [
102
+ defaultBreadcrumb,
103
+ ...pathName.split('/').filter((segment) => segment !== ''),
104
+ ];
105
+
106
+ return segments.map((segment, i) => {
107
+ const href =
108
+ i === 0
109
+ ? '/'
110
+ : \`/\${segments
111
+ .slice(1, i + 1)
112
+ .join('/')
113
+ .replace('//', '/')}\`;
114
+
115
+ const matched =
116
+ !availableRoutes || availableRoutes.find((r) => matchPath(r, href));
117
+
118
+ return {
119
+ href: matched ? \`\${href}\${search}\` : '#',
120
+ text: segment,
121
+ };
122
+ });
123
+ };
98
124
 
99
125
  /**
100
126
  * Context for updating/retrieving the AppLayout.
@@ -109,10 +135,6 @@ export const AppLayoutContext = createContext({
109
135
  * Defines the App layout and contains logic for routing.
110
136
  */
111
137
  const App: React.FC = () => {
112
- const [username, setUsername] = useState<string | undefined>();
113
- const [email, setEmail] = useState<string | undefined>();
114
- const { getAuthenticatedUser } = useCognitoAuthContext();
115
-
116
138
  const navigate = useNavigate();
117
139
  const [activeHref, setActiveHref] = useState('/');
118
140
  const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
@@ -121,17 +143,6 @@ const App: React.FC = () => {
121
143
  const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
122
144
  const location = useLocation();
123
145
 
124
- useEffect(() => {
125
- const authUser = getAuthenticatedUser();
126
- setUsername(authUser?.getUsername());
127
-
128
- authUser?.getSession(() => {
129
- authUser.getUserAttributes((_, attributes) => {
130
- setEmail(attributes?.find((a) => a.Name === 'email')?.Value);
131
- });
132
- });
133
- }, [getAuthenticatedUser, setUsername, setEmail]);
134
-
135
146
  const setAppLayoutPropsSafe = useCallback(
136
147
  (props: AppLayoutProps) => {
137
148
  JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
@@ -152,9 +163,6 @@ const App: React.FC = () => {
152
163
  e.preventDefault();
153
164
  setAppLayoutPropsSafe({
154
165
  contentType: undefined,
155
- splitPanelOpen: false,
156
- splitPanelSize: undefined,
157
- splitPanelPreferences: undefined,
158
166
  });
159
167
  navigate(e.detail.href);
160
168
  }
@@ -166,23 +174,14 @@ const App: React.FC = () => {
166
174
  <AppLayoutContext.Provider
167
175
  value={{ appLayoutProps, setAppLayoutProps: setAppLayoutPropsSafe }}
168
176
  >
169
- <NavHeader
170
- title={Config.applicationName}
171
- logo={Config.logo}
172
- user={
173
- username
174
- ? {
175
- username,
176
- email,
177
- }
178
- : undefined
179
- }
180
- onSignout={() =>
181
- new Promise(() => {
182
- getAuthenticatedUser()?.signOut();
183
- window.location.href = '/';
184
- })
185
- }
177
+ <TopNavigation
178
+ identity={{
179
+ href: '/',
180
+ title: Config.applicationName,
181
+ logo: {
182
+ src: Config.logo,
183
+ },
184
+ }}
186
185
  />
187
186
  <AppLayout
188
187
  breadcrumbs={
@@ -198,8 +197,6 @@ const App: React.FC = () => {
198
197
  />
199
198
  }
200
199
  content={<Routes />}
201
- splitPanelOpen={false}
202
- splitPanelPreferences={{ position: 'bottom' }}
203
200
  {...appLayoutProps}
204
201
  />
205
202
  </AppLayoutContext.Provider>
@@ -219,46 +216,42 @@ exports[`cloudscape-website generator > should generate base files and structure
219
216
  `;
220
217
 
221
218
  exports[`cloudscape-website generator > should generate base files and structure > main.tsx 1`] = `
222
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
223
- SPDX-License-Identifier: Apache-2.0 */
224
- import { NorthStarThemeProvider } from '@aws-northstar/ui';
225
- import React from 'react';
219
+ "import React from 'react';
226
220
  import { createRoot } from 'react-dom/client';
227
221
  import { BrowserRouter } from 'react-router-dom';
228
222
  import { I18nProvider } from '@cloudscape-design/components/i18n';
229
223
  import messages from '@cloudscape-design/components/i18n/messages/all.en';
230
224
  import App from './layouts/App';
231
225
 
226
+ import '@cloudscape-design/global-styles/index.css';
227
+
232
228
  const root = document.getElementById('root');
233
229
  root &&
234
230
  createRoot(root).render(
235
231
  <React.StrictMode>
236
- <NorthStarThemeProvider>
237
- <I18nProvider locale="en" messages={[messages]}>
238
- <BrowserRouter>
239
- <App />
240
- </BrowserRouter>
241
- </I18nProvider>
242
- </NorthStarThemeProvider>
232
+ <I18nProvider locale="en" messages={[messages]}>
233
+ <BrowserRouter>
234
+ <App />
235
+ </BrowserRouter>
236
+ </I18nProvider>
243
237
  </React.StrictMode>
244
238
  );
245
239
  "
246
240
  `;
247
241
 
248
- exports[`cloudscape-website generator > should generate shared constructs > common/constructs-index.ts 1`] = `
249
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
250
- SPDX-License-Identifier: Apache-2.0 */
251
- export * from './cloudfront-web-acl.js';
252
- export * from './static-website.js';
242
+ exports[`cloudscape-website generator > should generate shared constructs > common/constructs-app-index.ts 1`] = `
243
+ "export * from './test-app.js';
244
+ "
245
+ `;
246
+
247
+ exports[`cloudscape-website generator > should generate shared constructs > common/constructs-core-index.ts 1`] = `
248
+ "export * from './static-website.js';
249
+ export * from './runtime-config.js';
253
250
  "
254
251
  `;
255
252
 
256
- exports[`cloudscape-website generator > should generate shared constructs > static-website.ts 1`] = `
257
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
258
- SPDX-License-Identifier: Apache-2.0 */
259
- import * as url from 'url';
260
- import { PDKNag } from '@aws/pdk/pdk-nag';
261
- import { CfnJson, CfnOutput, Lazy, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
253
+ exports[`cloudscape-website generator > should generate shared constructs > common/constructs-core-static-website.ts 1`] = `
254
+ "import { CfnJson, CfnOutput, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
262
255
  import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
263
256
  import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
264
257
  import {
@@ -269,13 +262,16 @@ import {
269
262
  ObjectOwnership,
270
263
  } from 'aws-cdk-lib/aws-s3';
271
264
  import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
272
- import { NagSuppressions } from 'cdk-nag';
273
265
  import { Construct } from 'constructs';
274
- import { CloudfrontWebAcl } from './cloudfront-web-acl.js';
275
- import { RuntimeConfig } from '../runtime-config/index.js';
276
-
266
+ import { RuntimeConfig } from './runtime-config.js';
267
+ import { Key } from 'aws-cdk-lib/aws-kms';
268
+ import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
277
269
  const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
278
270
 
271
+ export interface StaticWebsiteProps {
272
+ readonly websiteFilePath: string;
273
+ }
274
+
279
275
  /**
280
276
  * Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
281
277
  *
@@ -289,61 +285,68 @@ export class StaticWebsite extends Construct {
289
285
  public readonly cloudFrontDistribution: Distribution;
290
286
  public readonly bucketDeployment: BucketDeployment;
291
287
 
292
- constructor(scope: Construct, id: string) {
288
+ constructor(
289
+ scope: Construct,
290
+ id: string,
291
+ { websiteFilePath }: StaticWebsiteProps
292
+ ) {
293
293
  super(scope, id);
294
-
295
294
  this.node.setContext(
296
295
  '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
297
296
  true
298
297
  );
299
298
 
299
+ const websiteKey = new Key(this, 'WebsiteKey', {
300
+ enableKeyRotation: true,
301
+ });
302
+
300
303
  const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
301
304
  versioned: false,
302
305
  enforceSSL: true,
303
306
  autoDeleteObjects: true,
304
307
  removalPolicy: RemovalPolicy.DESTROY,
305
- encryption: BucketEncryption.S3_MANAGED,
308
+ encryption: BucketEncryption.KMS,
309
+ encryptionKey: websiteKey,
306
310
  objectOwnership: ObjectOwnership.OBJECT_WRITER,
307
311
  publicReadAccess: false,
308
312
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
309
313
  });
310
-
311
314
  // S3 Bucket to hold website files
312
315
  this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
313
316
  versioned: true,
314
317
  enforceSSL: true,
315
318
  autoDeleteObjects: true,
316
319
  removalPolicy: RemovalPolicy.DESTROY,
317
- encryption: BucketEncryption.S3_MANAGED,
320
+ encryption: BucketEncryption.KMS,
321
+ encryptionKey: websiteKey,
318
322
  objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
319
323
  publicReadAccess: false,
320
324
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
321
325
  serverAccessLogsPrefix: 'website-access-logs',
322
326
  serverAccessLogsBucket: accessLogsBucket,
323
327
  });
324
-
325
328
  // Web ACL
326
- const webAclArn = new CloudfrontWebAcl(this, 'WebsiteAcl').webAclArn;
329
+ const wafStack = new CloudfrontWebAcl(this, 'waf');
327
330
 
328
331
  // Cloudfront Distribution
329
332
  const logBucket = new Bucket(this, 'DistributionLogBucket', {
330
333
  enforceSSL: true,
331
334
  autoDeleteObjects: true,
332
335
  removalPolicy: RemovalPolicy.DESTROY,
333
- encryption: BucketEncryption.S3_MANAGED,
336
+ encryption: BucketEncryption.KMS,
337
+ encryptionKey: websiteKey,
334
338
  objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
335
339
  publicReadAccess: false,
336
340
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
337
341
  serverAccessLogsPrefix: 'distribution-access-logs',
338
342
  serverAccessLogsBucket: accessLogsBucket,
339
343
  });
340
-
341
344
  const defaultRootObject = 'index.html';
342
345
  this.cloudFrontDistribution = new Distribution(
343
346
  this,
344
347
  'CloudfrontDistribution',
345
348
  {
346
- webAclId: webAclArn,
349
+ webAclId: wafStack.wafArn,
347
350
  enableLogging: true,
348
351
  logBucket: logBucket,
349
352
  defaultBehavior: {
@@ -360,45 +363,34 @@ export class StaticWebsite extends Construct {
360
363
  ],
361
364
  }
362
365
  );
363
-
364
366
  // Deploy Website
365
- const runtimeConfig = RuntimeConfig.ensure(this).config;
366
367
  this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
367
368
  sources: [
368
- Source.asset(
369
- url.fileURLToPath(
370
- new URL('../../../../../dist/test-app', import.meta.url)
371
- )
369
+ Source.asset(websiteFilePath),
370
+ Source.jsonData(
371
+ DEFAULT_RUNTIME_CONFIG_FILENAME,
372
+ this.resolveTokens(RuntimeConfig.ensure(this).config)
372
373
  ),
373
- ...(Object.keys(runtimeConfig).length > 0
374
- ? [Source.jsonData(DEFAULT_RUNTIME_CONFIG_FILENAME, this.lazilyRender(runtimeConfig))]
375
- : []),
376
374
  ],
377
375
  destinationBucket: this.websiteBucket,
378
376
  // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
379
377
  distribution: this.cloudFrontDistribution,
380
378
  });
381
-
382
379
  new CfnOutput(this, 'DistributionDomainName', {
383
380
  value: this.cloudFrontDistribution.domainName,
384
381
  });
385
-
386
- this.suppressCDKNagViolations();
387
382
  }
388
-
389
- private lazilyRender = (payload: any) => Lazy.any({
390
- produce: () => this.resolveTokens(payload),
391
- });
392
-
393
383
  private resolveTokens = (payload: any) => {
394
384
  const _payload: Record<string, any> = {};
395
-
396
385
  Object.entries(payload).forEach(([key, value]) => {
397
- if (Token.isUnresolved(value) || (typeof value === "string" && value.endsWith("}}"))) {
386
+ if (
387
+ Token.isUnresolved(value) ||
388
+ (typeof value === 'string' && value.endsWith('}}'))
389
+ ) {
398
390
  _payload[key] = new CfnJson(this, \`ResolveToken-\${key}\`, {
399
- value,
391
+ value,
400
392
  }).value;
401
- } else if (typeof value === "object") {
393
+ } else if (typeof value === 'object') {
402
394
  _payload[key] = this.resolveTokens(value);
403
395
  } else if (Array.isArray(value)) {
404
396
  _payload[key] = value.map((v) => this.resolveTokens(v));
@@ -406,142 +398,91 @@ export class StaticWebsite extends Construct {
406
398
  _payload[key] = value;
407
399
  }
408
400
  });
409
-
410
401
  return _payload;
411
- }
402
+ };
403
+ }
412
404
 
413
- private suppressCDKNagViolations = () => {
414
- const stack = Stack.of(this);
405
+ export class CloudfrontWebAcl extends Stack {
406
+ public readonly wafArn;
407
+ constructor(scope: Construct, id: string) {
408
+ super(scope, id, {
409
+ env: {
410
+ region: 'us-east-1',
411
+ account: Stack.of(scope).account,
412
+ },
413
+ crossRegionReferences: true,
414
+ });
415
415
 
416
- NagSuppressions.addResourceSuppressions(
417
- this,
418
- [
416
+ this.wafArn = new CfnWebACL(this, 'WebAcl', {
417
+ defaultAction: { allow: {} },
418
+ scope: 'CLOUDFRONT',
419
+ visibilityConfig: {
420
+ cloudWatchMetricsEnabled: true,
421
+ metricName: id,
422
+ sampledRequestsEnabled: true,
423
+ },
424
+ rules: [
419
425
  {
420
- id: 'AwsPrototyping-CloudFrontDistributionGeoRestrictions',
421
- reason:
422
- 'Suppressed to allow unrestricted access. Not recommended in production.',
426
+ name: 'CRSRule',
427
+ priority: 0,
428
+ statement: {
429
+ managedRuleGroupStatement: {
430
+ name: 'AWSManagedRulesCommonRuleSet',
431
+ vendorName: 'AWS',
432
+ },
433
+ },
434
+ visibilityConfig: {
435
+ cloudWatchMetricsEnabled: true,
436
+ metricName: 'MetricForWebACLCDK-CRS',
437
+ sampledRequestsEnabled: true,
438
+ },
439
+ overrideAction: {
440
+ none: {},
441
+ },
423
442
  },
424
443
  ],
425
- true
426
- );
427
-
428
- [
429
- 'AwsSolutions-CFR4',
430
- 'AwsPrototyping-CloudFrontDistributionHttpsViewerNoOutdatedSSL',
431
- ].forEach((RuleId) => {
432
- NagSuppressions.addResourceSuppressions(this.cloudFrontDistribution, [
433
- {
434
- id: RuleId,
435
- reason:
436
- 'Certificate is not mandatory therefore the Cloudfront certificate will be used.',
437
- },
438
- ]);
439
- });
440
-
441
- ['AwsSolutions-L1', 'AwsPrototyping-LambdaLatestVersion'].forEach(
442
- (RuleId) => {
443
- NagSuppressions.addResourceSuppressions(
444
- this,
445
- [
446
- {
447
- id: RuleId,
448
- reason:
449
- 'Latest runtime cannot be configured. CDK will need to upgrade the BucketDeployment construct accordingly.',
450
- },
451
- ],
452
- true
453
- );
454
- }
455
- );
456
-
457
- ['AwsSolutions-IAM5', 'AwsPrototyping-IAMNoWildcardPermissions'].forEach(
458
- (RuleId) => {
459
- NagSuppressions.addResourceSuppressions(
460
- this,
461
- [
462
- {
463
- id: RuleId,
464
- reason:
465
- 'All Policies have been scoped to a Bucket. Given Buckets can contain arbitrary content, wildcard resources with bucket scope are required.',
466
- appliesTo: [
467
- {
468
- regex: '/^Action::s3:.*$/g',
469
- },
470
- {
471
- regex: \`/^Resource::.*$/g\`,
472
- },
473
- ],
474
- },
475
- ],
476
- true
477
- );
478
- }
479
- );
444
+ }).attrArn;
445
+ }
446
+ }
447
+ "
448
+ `;
480
449
 
481
- ['AwsSolutions-IAM4', 'AwsPrototyping-IAMNoManagedPolicies'].forEach(
482
- (RuleId) => {
483
- NagSuppressions.addResourceSuppressions(
484
- this,
485
- [
486
- {
487
- id: RuleId,
488
- reason:
489
- 'Buckets can contain arbitrary content, therefore wildcard resources under a bucket are required.',
490
- appliesTo: [
491
- {
492
- regex: \`/^Policy::arn:\${PDKNag.getStackPartitionRegex(
493
- stack
494
- )}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole$/g\`,
495
- },
496
- ],
497
- },
498
- ],
499
- true
500
- );
501
- }
502
- );
450
+ exports[`cloudscape-website generator > should generate shared constructs > test-app.ts 1`] = `
451
+ "import * as url from 'url';
452
+ import { Construct } from 'constructs';
453
+ import { StaticWebsite } from '../../core/index.js';
503
454
 
504
- ['AwsSolutions-S1', 'AwsPrototyping-S3BucketLoggingEnabled'].forEach(
505
- (RuleId) => {
506
- NagSuppressions.addResourceSuppressions(
507
- this,
508
- [
509
- {
510
- id: RuleId,
511
- reason: 'Access Log buckets should not have s3 bucket logging',
512
- },
513
- ],
514
- true
515
- );
516
- }
517
- );
518
- };
455
+ export class TestApp extends StaticWebsite {
456
+ constructor(scope: Construct, id: string) {
457
+ super(scope, id, {
458
+ websiteFilePath: url.fileURLToPath(
459
+ new URL('../../../../../../dist/test-app', import.meta.url)
460
+ ),
461
+ });
462
+ }
519
463
  }
520
464
  "
521
465
  `;
522
466
 
523
467
  exports[`cloudscape-website generator > should handle custom directory option > custom-dir-main.tsx 1`] = `
524
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
525
- SPDX-License-Identifier: Apache-2.0 */
526
- import { NorthStarThemeProvider } from '@aws-northstar/ui';
527
- import React from 'react';
468
+ "import React from 'react';
528
469
  import { createRoot } from 'react-dom/client';
529
470
  import { BrowserRouter } from 'react-router-dom';
530
471
  import { I18nProvider } from '@cloudscape-design/components/i18n';
531
472
  import messages from '@cloudscape-design/components/i18n/messages/all.en';
532
473
  import App from './layouts/App';
533
474
 
475
+ import '@cloudscape-design/global-styles/index.css';
476
+
534
477
  const root = document.getElementById('root');
535
478
  root &&
536
479
  createRoot(root).render(
537
480
  <React.StrictMode>
538
- <NorthStarThemeProvider>
539
- <I18nProvider locale="en" messages={[messages]}>
540
- <BrowserRouter>
541
- <App />
542
- </BrowserRouter>
543
- </I18nProvider>
544
- </NorthStarThemeProvider>
481
+ <I18nProvider locale="en" messages={[messages]}>
482
+ <BrowserRouter>
483
+ <App />
484
+ </BrowserRouter>
485
+ </I18nProvider>
545
486
  </React.StrictMode>
546
487
  );
547
488
  "
@@ -549,15 +490,13 @@ root &&
549
490
 
550
491
  exports[`cloudscape-website generator > should handle npm scope prefix correctly > scoped-dependencies 1`] = `
551
492
  {
552
- "@aws-northstar/ui": "^1.1.13",
553
- "@aws/pdk": "^0.25.7",
554
493
  "@cloudscape-design/board-components": "^3.0.84",
555
494
  "@cloudscape-design/components": "^3.0.823",
495
+ "@cloudscape-design/global-styles": "^1.0.34",
556
496
  "aws-cdk-lib": "^2.166.0",
557
- "cdk-nag": "^2.32.2",
558
497
  "constructs": "^10.4.2",
559
498
  "react": "18.3.1",
560
499
  "react-dom": "18.3.1",
561
- "react-router-dom": "^6.28.0",
500
+ "react-router-dom": "^7.1.1",
562
501
  }
563
502
  `;
@@ -0,0 +1,44 @@
1
+ # <%= fullyQualifiedName %>
2
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
3
+
4
+ ## Building
5
+
6
+ Run `<%= pkgMgrCmd %> nx build <%= fullyQualifiedName %> [--skip-nx-cache]` to build the application.
7
+
8
+ ## Run dev server
9
+
10
+ Run `<%= pkgMgrCmd %> nx serve <%= fullyQualifiedName %>`
11
+
12
+ ## Running unit tests
13
+
14
+ Run `<%= pkgMgrCmd %> nx test <%= fullyQualifiedName %>` to execute the unit tests via Vitest.
15
+
16
+ ### Updating snapshots
17
+
18
+ To update snapshots, run the following command:
19
+
20
+ `<%= pkgMgrCmd %> nx test <%= fullyQualifiedName %> --configuration=update-snapshot`
21
+
22
+ ## Run lint
23
+
24
+ Run `<%= pkgMgrCmd %> nx lint <%= fullyQualifiedName %>`
25
+
26
+ ### Fixable issues
27
+
28
+ You can also automatically fix some lint errors by running the following command:
29
+
30
+ `<%= pkgMgrCmd %> nx lint <%= fullyQualifiedName %> --configuration=fix`
31
+
32
+ ### Runtime config
33
+
34
+ In order to integrate with cognito or trpc backends, you need to have a `runtime-config.json` file in your `/public` website directory. You can fetch this is follows:
35
+
36
+ `AWS_REGION=ap-southeast-2 CDK_APP_DIR=./dist/packages/infra/cdk.out nx run <%= fullyQualifiedName %>:load:runtime-config`
37
+
38
+ > [!IMPORTANT]
39
+ > Ensure you have deployed your infrastructure first before executing this command.
40
+
41
+ ## Useful links
42
+
43
+ - [Cloudscape website reference docs](TODO)
44
+ - [Learn more about NX](https://nx.dev/getting-started/intro)