@aws/nx-plugin 0.1.6 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-THIRD-PARTY +1554 -3241
- package/generators.json +1 -13
- package/package.json +14 -14
- package/src/cloudscape-website/app/README.md +84 -48
- package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +168 -233
- package/src/cloudscape-website/app/files/app/README.md.template +44 -0
- package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
- package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
- package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
- package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
- package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
- package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
- package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +79 -144
- package/src/cloudscape-website/app/generator.js +90 -74
- package/src/cloudscape-website/app/generator.js.map +1 -1
- package/src/cloudscape-website/app/schema.d.ts +3 -5
- package/src/cloudscape-website/app/schema.json +1 -24
- package/src/cloudscape-website/cognito-auth/README.md +53 -32
- package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +162 -124
- package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
- package/src/cloudscape-website/cognito-auth/generator.js +130 -47
- package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
- package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
- package/src/cloudscape-website/cognito-auth/schema.json +7 -1
- package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +20 -15
- package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
- package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
- package/src/cloudscape-website/runtime-config/generator.js +4 -2
- package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
- package/src/infra/app/README.md +71 -46
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +184 -305
- package/src/infra/app/files/app/README.md.template +76 -0
- package/src/infra/app/files/app/src/main.ts.template +18 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
- package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
- package/src/infra/app/generator.js +36 -7
- package/src/infra/app/generator.js.map +1 -1
- package/src/infra/app/schema.d.ts +10 -1
- package/src/infra/app/schema.json +16 -8
- package/src/trpc/backend/README.md +102 -80
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +42 -19
- package/src/trpc/backend/files/backend/README.md.template +33 -0
- package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
- package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
- package/src/trpc/backend/files/schema/README.md.template +33 -0
- package/src/trpc/backend/generator.js +30 -44
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/backend/schema.d.ts +3 -1
- package/src/trpc/backend/schema.json +8 -13
- package/src/trpc/react/README.md +46 -66
- package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
- package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
- package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
- package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
- package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
- package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
- package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
- package/src/trpc/react/generator.js +124 -25
- package/src/trpc/react/generator.js.map +1 -1
- package/src/trpc/react/schema.json +2 -2
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +47 -93
- package/src/ts/lib/eslint.d.ts +1 -2
- package/src/ts/lib/eslint.js +62 -21
- package/src/ts/lib/eslint.js.map +1 -1
- package/src/ts/lib/files/README.md.template +33 -0
- package/src/ts/lib/generator.js +44 -5
- package/src/ts/lib/generator.js.map +1 -1
- package/src/ts/lib/schema.d.ts +1 -4
- package/src/ts/lib/schema.json +2 -21
- package/src/ts/lib/ts-project-utils.js +3 -18
- package/src/ts/lib/ts-project-utils.js.map +1 -1
- package/src/ts/lib/vitest.js +12 -0
- package/src/ts/lib/vitest.js.map +1 -1
- package/src/utils/ast.d.ts +13 -0
- package/src/utils/ast.js +102 -0
- package/src/utils/ast.js.map +1 -0
- package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
- package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
- package/src/utils/files/common/constructs/src/index.ts.template +2 -1
- package/src/utils/files/common/readme/README.md.template +33 -0
- package/src/utils/files/common/types/src/runtime-config.ts.template +2 -13
- package/src/utils/format.d.ts +1 -1
- package/src/utils/format.js +2 -2
- package/src/utils/format.js.map +1 -1
- package/src/utils/names.d.ts +2 -0
- package/src/utils/names.js +27 -0
- package/src/utils/names.js.map +1 -0
- package/src/utils/npm-scope.js.map +1 -1
- package/src/utils/paths.js.map +1 -1
- package/src/utils/shared-constructs.js +37 -4
- package/src/utils/shared-constructs.js.map +1 -1
- package/src/utils/test.d.ts +2 -0
- package/src/utils/test.js +19 -0
- package/src/utils/test.js.map +1 -0
- package/src/utils/versions.d.ts +15 -9
- package/src/utils/versions.js +14 -8
- package/src/utils/versions.js.map +1 -1
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
- package/src/gitlab/generator.d.ts +0 -8
- package/src/gitlab/generator.js +0 -16
- package/src/gitlab/generator.js.map +0 -1
- package/src/gitlab/schema.d.ts +0 -9
- package/src/gitlab/schema.json +0 -52
- package/src/infra/app/files/src/main.ts.template +0 -37
- package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
- package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
- package/src/ts/cjs-to-esm/generator.d.ts +0 -12
- package/src/ts/cjs-to-esm/generator.js +0 -189
- package/src/ts/cjs-to-esm/generator.js.map +0 -1
- package/src/ts/cjs-to-esm/schema.d.ts +0 -9
- package/src/ts/cjs-to-esm/schema.json +0 -28
- /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
- /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
- /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
|
@@ -3,17 +3,8 @@
|
|
|
3
3
|
exports[`cloudscape-website generator > should configure TypeScript correctly > tsconfig.json 1`] = `
|
|
4
4
|
{
|
|
5
5
|
"compilerOptions": {
|
|
6
|
-
"allowJs": false,
|
|
7
|
-
"allowSyntheticDefaultImports": true,
|
|
8
|
-
"esModuleInterop": false,
|
|
9
|
-
"jsx": "react-jsx",
|
|
10
6
|
"module": "Preserve",
|
|
11
7
|
"moduleResolution": "Bundler",
|
|
12
|
-
"strict": true,
|
|
13
|
-
"types": [
|
|
14
|
-
"vite/client",
|
|
15
|
-
"vitest",
|
|
16
|
-
],
|
|
17
8
|
},
|
|
18
9
|
"extends": "../tsconfig.base.json",
|
|
19
10
|
"files": [],
|
|
@@ -75,12 +66,7 @@ export default defineConfig({
|
|
|
75
66
|
`;
|
|
76
67
|
|
|
77
68
|
exports[`cloudscape-website generator > should generate base files and structure > app-layout.tsx 1`] = `
|
|
78
|
-
"
|
|
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';
|
|
69
|
+
"import * as React from 'react';
|
|
84
70
|
import { createContext, useCallback, useEffect, useState } from 'react';
|
|
85
71
|
import { NavItems } from './navitems';
|
|
86
72
|
import Config from '../../config';
|
|
@@ -90,11 +76,42 @@ import {
|
|
|
90
76
|
BreadcrumbGroup,
|
|
91
77
|
BreadcrumbGroupProps,
|
|
92
78
|
SideNavigation,
|
|
79
|
+
TopNavigation,
|
|
93
80
|
} from '@cloudscape-design/components';
|
|
94
81
|
import AppLayout, {
|
|
95
82
|
AppLayoutProps,
|
|
96
83
|
} from '@cloudscape-design/components/app-layout';
|
|
97
|
-
import { useLocation, useNavigate } from 'react-router-dom';
|
|
84
|
+
import { matchPath, useLocation, useNavigate } from 'react-router-dom';
|
|
85
|
+
|
|
86
|
+
const getBreadcrumbs = (
|
|
87
|
+
pathName: string,
|
|
88
|
+
search: string,
|
|
89
|
+
defaultBreadcrumb: string,
|
|
90
|
+
availableRoutes?: string[],
|
|
91
|
+
) => {
|
|
92
|
+
const segments = [
|
|
93
|
+
defaultBreadcrumb,
|
|
94
|
+
...pathName.split('/').filter((segment) => segment !== ''),
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
return segments.map((segment, i) => {
|
|
98
|
+
const href =
|
|
99
|
+
i === 0
|
|
100
|
+
? '/'
|
|
101
|
+
: \`/\${segments
|
|
102
|
+
.slice(1, i + 1)
|
|
103
|
+
.join('/')
|
|
104
|
+
.replace('//', '/')}\`;
|
|
105
|
+
|
|
106
|
+
const matched =
|
|
107
|
+
!availableRoutes || availableRoutes.find((r) => matchPath(r, href));
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
href: matched ? \`\${href}\${search}\` : '#',
|
|
111
|
+
text: segment,
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
};
|
|
98
115
|
|
|
99
116
|
/**
|
|
100
117
|
* Context for updating/retrieving the AppLayout.
|
|
@@ -109,10 +126,6 @@ export const AppLayoutContext = createContext({
|
|
|
109
126
|
* Defines the App layout and contains logic for routing.
|
|
110
127
|
*/
|
|
111
128
|
const App: React.FC = () => {
|
|
112
|
-
const [username, setUsername] = useState<string | undefined>();
|
|
113
|
-
const [email, setEmail] = useState<string | undefined>();
|
|
114
|
-
const { getAuthenticatedUser } = useCognitoAuthContext();
|
|
115
|
-
|
|
116
129
|
const navigate = useNavigate();
|
|
117
130
|
const [activeHref, setActiveHref] = useState('/');
|
|
118
131
|
const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
|
|
@@ -121,23 +134,12 @@ const App: React.FC = () => {
|
|
|
121
134
|
const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
|
|
122
135
|
const location = useLocation();
|
|
123
136
|
|
|
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
137
|
const setAppLayoutPropsSafe = useCallback(
|
|
136
138
|
(props: AppLayoutProps) => {
|
|
137
139
|
JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
|
|
138
140
|
setAppLayoutProps(props);
|
|
139
141
|
},
|
|
140
|
-
[appLayoutProps]
|
|
142
|
+
[appLayoutProps],
|
|
141
143
|
);
|
|
142
144
|
|
|
143
145
|
useEffect(() => {
|
|
@@ -152,37 +154,25 @@ const App: React.FC = () => {
|
|
|
152
154
|
e.preventDefault();
|
|
153
155
|
setAppLayoutPropsSafe({
|
|
154
156
|
contentType: undefined,
|
|
155
|
-
splitPanelOpen: false,
|
|
156
|
-
splitPanelSize: undefined,
|
|
157
|
-
splitPanelPreferences: undefined,
|
|
158
157
|
});
|
|
159
158
|
navigate(e.detail.href);
|
|
160
159
|
}
|
|
161
160
|
},
|
|
162
|
-
[navigate, setAppLayoutPropsSafe]
|
|
161
|
+
[navigate, setAppLayoutPropsSafe],
|
|
163
162
|
);
|
|
164
163
|
|
|
165
164
|
return (
|
|
166
165
|
<AppLayoutContext.Provider
|
|
167
166
|
value={{ appLayoutProps, setAppLayoutProps: setAppLayoutPropsSafe }}
|
|
168
167
|
>
|
|
169
|
-
<
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
: undefined
|
|
179
|
-
}
|
|
180
|
-
onSignout={() =>
|
|
181
|
-
new Promise(() => {
|
|
182
|
-
getAuthenticatedUser()?.signOut();
|
|
183
|
-
window.location.href = '/';
|
|
184
|
-
})
|
|
185
|
-
}
|
|
168
|
+
<TopNavigation
|
|
169
|
+
identity={{
|
|
170
|
+
href: '/',
|
|
171
|
+
title: Config.applicationName,
|
|
172
|
+
logo: {
|
|
173
|
+
src: Config.logo,
|
|
174
|
+
},
|
|
175
|
+
}}
|
|
186
176
|
/>
|
|
187
177
|
<AppLayout
|
|
188
178
|
breadcrumbs={
|
|
@@ -198,8 +188,6 @@ const App: React.FC = () => {
|
|
|
198
188
|
/>
|
|
199
189
|
}
|
|
200
190
|
content={<Routes />}
|
|
201
|
-
splitPanelOpen={false}
|
|
202
|
-
splitPanelPreferences={{ position: 'bottom' }}
|
|
203
191
|
{...appLayoutProps}
|
|
204
192
|
/>
|
|
205
193
|
</AppLayoutContext.Provider>
|
|
@@ -219,46 +207,42 @@ exports[`cloudscape-website generator > should generate base files and structure
|
|
|
219
207
|
`;
|
|
220
208
|
|
|
221
209
|
exports[`cloudscape-website generator > should generate base files and structure > main.tsx 1`] = `
|
|
222
|
-
"
|
|
223
|
-
SPDX-License-Identifier: Apache-2.0 */
|
|
224
|
-
import { NorthStarThemeProvider } from '@aws-northstar/ui';
|
|
225
|
-
import React from 'react';
|
|
210
|
+
"import React from 'react';
|
|
226
211
|
import { createRoot } from 'react-dom/client';
|
|
227
212
|
import { BrowserRouter } from 'react-router-dom';
|
|
228
213
|
import { I18nProvider } from '@cloudscape-design/components/i18n';
|
|
229
214
|
import messages from '@cloudscape-design/components/i18n/messages/all.en';
|
|
230
215
|
import App from './layouts/App';
|
|
231
216
|
|
|
217
|
+
import '@cloudscape-design/global-styles/index.css';
|
|
218
|
+
|
|
232
219
|
const root = document.getElementById('root');
|
|
233
220
|
root &&
|
|
234
221
|
createRoot(root).render(
|
|
235
222
|
<React.StrictMode>
|
|
236
|
-
<
|
|
237
|
-
<
|
|
238
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
</NorthStarThemeProvider>
|
|
243
|
-
</React.StrictMode>
|
|
223
|
+
<I18nProvider locale="en" messages={[messages]}>
|
|
224
|
+
<BrowserRouter>
|
|
225
|
+
<App />
|
|
226
|
+
</BrowserRouter>
|
|
227
|
+
</I18nProvider>
|
|
228
|
+
</React.StrictMode>,
|
|
244
229
|
);
|
|
245
230
|
"
|
|
246
231
|
`;
|
|
247
232
|
|
|
248
|
-
exports[`cloudscape-website generator > should generate shared constructs > common/constructs-index.ts 1`] = `
|
|
249
|
-
"
|
|
250
|
-
SPDX-License-Identifier: Apache-2.0 */
|
|
251
|
-
export * from './cloudfront-web-acl.js';
|
|
252
|
-
export * from './static-website.js';
|
|
233
|
+
exports[`cloudscape-website generator > should generate shared constructs > common/constructs-app-index.ts 1`] = `
|
|
234
|
+
"export * from './test-app.js';
|
|
253
235
|
"
|
|
254
236
|
`;
|
|
255
237
|
|
|
256
|
-
exports[`cloudscape-website generator > should generate shared constructs >
|
|
257
|
-
"
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
238
|
+
exports[`cloudscape-website generator > should generate shared constructs > common/constructs-core-index.ts 1`] = `
|
|
239
|
+
"export * from './static-website.js';
|
|
240
|
+
export * from './runtime-config.js';
|
|
241
|
+
"
|
|
242
|
+
`;
|
|
243
|
+
|
|
244
|
+
exports[`cloudscape-website generator > should generate shared constructs > common/constructs-core-static-website.ts 1`] = `
|
|
245
|
+
"import { CfnJson, CfnOutput, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
|
|
262
246
|
import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
|
|
263
247
|
import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
264
248
|
import {
|
|
@@ -269,13 +253,16 @@ import {
|
|
|
269
253
|
ObjectOwnership,
|
|
270
254
|
} from 'aws-cdk-lib/aws-s3';
|
|
271
255
|
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
|
|
272
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
273
256
|
import { Construct } from 'constructs';
|
|
274
|
-
import {
|
|
275
|
-
import {
|
|
276
|
-
|
|
257
|
+
import { RuntimeConfig } from './runtime-config.js';
|
|
258
|
+
import { Key } from 'aws-cdk-lib/aws-kms';
|
|
259
|
+
import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
|
|
277
260
|
const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
|
|
278
261
|
|
|
262
|
+
export interface StaticWebsiteProps {
|
|
263
|
+
readonly websiteFilePath: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
279
266
|
/**
|
|
280
267
|
* Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
|
|
281
268
|
*
|
|
@@ -289,61 +276,68 @@ export class StaticWebsite extends Construct {
|
|
|
289
276
|
public readonly cloudFrontDistribution: Distribution;
|
|
290
277
|
public readonly bucketDeployment: BucketDeployment;
|
|
291
278
|
|
|
292
|
-
constructor(
|
|
279
|
+
constructor(
|
|
280
|
+
scope: Construct,
|
|
281
|
+
id: string,
|
|
282
|
+
{ websiteFilePath }: StaticWebsiteProps,
|
|
283
|
+
) {
|
|
293
284
|
super(scope, id);
|
|
294
|
-
|
|
295
285
|
this.node.setContext(
|
|
296
286
|
'@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
|
|
297
|
-
true
|
|
287
|
+
true,
|
|
298
288
|
);
|
|
299
289
|
|
|
290
|
+
const websiteKey = new Key(this, 'WebsiteKey', {
|
|
291
|
+
enableKeyRotation: true,
|
|
292
|
+
});
|
|
293
|
+
|
|
300
294
|
const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
|
|
301
295
|
versioned: false,
|
|
302
296
|
enforceSSL: true,
|
|
303
297
|
autoDeleteObjects: true,
|
|
304
298
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
305
|
-
encryption: BucketEncryption.
|
|
299
|
+
encryption: BucketEncryption.KMS,
|
|
300
|
+
encryptionKey: websiteKey,
|
|
306
301
|
objectOwnership: ObjectOwnership.OBJECT_WRITER,
|
|
307
302
|
publicReadAccess: false,
|
|
308
303
|
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
309
304
|
});
|
|
310
|
-
|
|
311
305
|
// S3 Bucket to hold website files
|
|
312
306
|
this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
|
|
313
307
|
versioned: true,
|
|
314
308
|
enforceSSL: true,
|
|
315
309
|
autoDeleteObjects: true,
|
|
316
310
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
317
|
-
encryption: BucketEncryption.
|
|
311
|
+
encryption: BucketEncryption.KMS,
|
|
312
|
+
encryptionKey: websiteKey,
|
|
318
313
|
objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
|
|
319
314
|
publicReadAccess: false,
|
|
320
315
|
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
321
316
|
serverAccessLogsPrefix: 'website-access-logs',
|
|
322
317
|
serverAccessLogsBucket: accessLogsBucket,
|
|
323
318
|
});
|
|
324
|
-
|
|
325
319
|
// Web ACL
|
|
326
|
-
const
|
|
320
|
+
const wafStack = new CloudfrontWebAcl(this, 'waf');
|
|
327
321
|
|
|
328
322
|
// Cloudfront Distribution
|
|
329
323
|
const logBucket = new Bucket(this, 'DistributionLogBucket', {
|
|
330
324
|
enforceSSL: true,
|
|
331
325
|
autoDeleteObjects: true,
|
|
332
326
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
333
|
-
encryption: BucketEncryption.
|
|
327
|
+
encryption: BucketEncryption.KMS,
|
|
328
|
+
encryptionKey: websiteKey,
|
|
334
329
|
objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
|
|
335
330
|
publicReadAccess: false,
|
|
336
331
|
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
337
332
|
serverAccessLogsPrefix: 'distribution-access-logs',
|
|
338
333
|
serverAccessLogsBucket: accessLogsBucket,
|
|
339
334
|
});
|
|
340
|
-
|
|
341
335
|
const defaultRootObject = 'index.html';
|
|
342
336
|
this.cloudFrontDistribution = new Distribution(
|
|
343
337
|
this,
|
|
344
338
|
'CloudfrontDistribution',
|
|
345
339
|
{
|
|
346
|
-
webAclId:
|
|
340
|
+
webAclId: wafStack.wafArn,
|
|
347
341
|
enableLogging: true,
|
|
348
342
|
logBucket: logBucket,
|
|
349
343
|
defaultBehavior: {
|
|
@@ -357,48 +351,42 @@ export class StaticWebsite extends Construct {
|
|
|
357
351
|
responseHttpStatus: 200,
|
|
358
352
|
responsePagePath: \`/\${defaultRootObject}\`,
|
|
359
353
|
},
|
|
354
|
+
{
|
|
355
|
+
httpStatus: 403, // We need to redirect reloads from paths (e.g. /foo/bar) to index.html for single page apps
|
|
356
|
+
responseHttpStatus: 200,
|
|
357
|
+
responsePagePath: \`/\${defaultRootObject}\`,
|
|
358
|
+
},
|
|
360
359
|
],
|
|
361
|
-
}
|
|
360
|
+
},
|
|
362
361
|
);
|
|
363
|
-
|
|
364
362
|
// Deploy Website
|
|
365
|
-
const runtimeConfig = RuntimeConfig.ensure(this).config;
|
|
366
363
|
this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
|
|
367
364
|
sources: [
|
|
368
|
-
Source.asset(
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
)
|
|
365
|
+
Source.asset(websiteFilePath),
|
|
366
|
+
Source.jsonData(
|
|
367
|
+
DEFAULT_RUNTIME_CONFIG_FILENAME,
|
|
368
|
+
this.resolveTokens(RuntimeConfig.ensure(this).config),
|
|
372
369
|
),
|
|
373
|
-
...(Object.keys(runtimeConfig).length > 0
|
|
374
|
-
? [Source.jsonData(DEFAULT_RUNTIME_CONFIG_FILENAME, this.lazilyRender(runtimeConfig))]
|
|
375
|
-
: []),
|
|
376
370
|
],
|
|
377
371
|
destinationBucket: this.websiteBucket,
|
|
378
372
|
// Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
|
|
379
373
|
distribution: this.cloudFrontDistribution,
|
|
380
374
|
});
|
|
381
|
-
|
|
382
375
|
new CfnOutput(this, 'DistributionDomainName', {
|
|
383
376
|
value: this.cloudFrontDistribution.domainName,
|
|
384
377
|
});
|
|
385
|
-
|
|
386
|
-
this.suppressCDKNagViolations();
|
|
387
378
|
}
|
|
388
|
-
|
|
389
|
-
private lazilyRender = (payload: any) => Lazy.any({
|
|
390
|
-
produce: () => this.resolveTokens(payload),
|
|
391
|
-
});
|
|
392
|
-
|
|
393
379
|
private resolveTokens = (payload: any) => {
|
|
394
380
|
const _payload: Record<string, any> = {};
|
|
395
|
-
|
|
396
381
|
Object.entries(payload).forEach(([key, value]) => {
|
|
397
|
-
if (
|
|
382
|
+
if (
|
|
383
|
+
Token.isUnresolved(value) ||
|
|
384
|
+
(typeof value === 'string' && value.endsWith('}}'))
|
|
385
|
+
) {
|
|
398
386
|
_payload[key] = new CfnJson(this, \`ResolveToken-\${key}\`, {
|
|
399
|
-
|
|
387
|
+
value,
|
|
400
388
|
}).value;
|
|
401
|
-
} else if (typeof value ===
|
|
389
|
+
} else if (typeof value === 'object') {
|
|
402
390
|
_payload[key] = this.resolveTokens(value);
|
|
403
391
|
} else if (Array.isArray(value)) {
|
|
404
392
|
_payload[key] = value.map((v) => this.resolveTokens(v));
|
|
@@ -406,158 +394,105 @@ export class StaticWebsite extends Construct {
|
|
|
406
394
|
_payload[key] = value;
|
|
407
395
|
}
|
|
408
396
|
});
|
|
409
|
-
|
|
410
397
|
return _payload;
|
|
411
|
-
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
412
400
|
|
|
413
|
-
|
|
414
|
-
|
|
401
|
+
export class CloudfrontWebAcl extends Stack {
|
|
402
|
+
public readonly wafArn;
|
|
403
|
+
constructor(scope: Construct, id: string) {
|
|
404
|
+
super(scope, id, {
|
|
405
|
+
env: {
|
|
406
|
+
region: 'us-east-1',
|
|
407
|
+
account: Stack.of(scope).account,
|
|
408
|
+
},
|
|
409
|
+
crossRegionReferences: true,
|
|
410
|
+
});
|
|
415
411
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
412
|
+
this.wafArn = new CfnWebACL(this, 'WebAcl', {
|
|
413
|
+
defaultAction: { allow: {} },
|
|
414
|
+
scope: 'CLOUDFRONT',
|
|
415
|
+
visibilityConfig: {
|
|
416
|
+
cloudWatchMetricsEnabled: true,
|
|
417
|
+
metricName: id,
|
|
418
|
+
sampledRequestsEnabled: true,
|
|
419
|
+
},
|
|
420
|
+
rules: [
|
|
419
421
|
{
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
422
|
+
name: 'CRSRule',
|
|
423
|
+
priority: 0,
|
|
424
|
+
statement: {
|
|
425
|
+
managedRuleGroupStatement: {
|
|
426
|
+
name: 'AWSManagedRulesCommonRuleSet',
|
|
427
|
+
vendorName: 'AWS',
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
visibilityConfig: {
|
|
431
|
+
cloudWatchMetricsEnabled: true,
|
|
432
|
+
metricName: 'MetricForWebACLCDK-CRS',
|
|
433
|
+
sampledRequestsEnabled: true,
|
|
434
|
+
},
|
|
435
|
+
overrideAction: {
|
|
436
|
+
none: {},
|
|
437
|
+
},
|
|
423
438
|
},
|
|
424
439
|
],
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
);
|
|
440
|
+
}).attrArn;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
"
|
|
444
|
+
`;
|
|
480
445
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
);
|
|
446
|
+
exports[`cloudscape-website generator > should generate shared constructs > test-app.ts 1`] = `
|
|
447
|
+
"import * as url from 'url';
|
|
448
|
+
import { Construct } from 'constructs';
|
|
449
|
+
import { StaticWebsite } from '../../core/index.js';
|
|
503
450
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
},
|
|
513
|
-
],
|
|
514
|
-
true
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
);
|
|
518
|
-
};
|
|
451
|
+
export class TestApp extends StaticWebsite {
|
|
452
|
+
constructor(scope: Construct, id: string) {
|
|
453
|
+
super(scope, id, {
|
|
454
|
+
websiteFilePath: url.fileURLToPath(
|
|
455
|
+
new URL('../../../../../../dist/test-app', import.meta.url),
|
|
456
|
+
),
|
|
457
|
+
});
|
|
458
|
+
}
|
|
519
459
|
}
|
|
520
460
|
"
|
|
521
461
|
`;
|
|
522
462
|
|
|
523
463
|
exports[`cloudscape-website generator > should handle custom directory option > custom-dir-main.tsx 1`] = `
|
|
524
|
-
"
|
|
525
|
-
SPDX-License-Identifier: Apache-2.0 */
|
|
526
|
-
import { NorthStarThemeProvider } from '@aws-northstar/ui';
|
|
527
|
-
import React from 'react';
|
|
464
|
+
"import React from 'react';
|
|
528
465
|
import { createRoot } from 'react-dom/client';
|
|
529
466
|
import { BrowserRouter } from 'react-router-dom';
|
|
530
467
|
import { I18nProvider } from '@cloudscape-design/components/i18n';
|
|
531
468
|
import messages from '@cloudscape-design/components/i18n/messages/all.en';
|
|
532
469
|
import App from './layouts/App';
|
|
533
470
|
|
|
471
|
+
import '@cloudscape-design/global-styles/index.css';
|
|
472
|
+
|
|
534
473
|
const root = document.getElementById('root');
|
|
535
474
|
root &&
|
|
536
475
|
createRoot(root).render(
|
|
537
476
|
<React.StrictMode>
|
|
538
|
-
<
|
|
539
|
-
<
|
|
540
|
-
<
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
</NorthStarThemeProvider>
|
|
545
|
-
</React.StrictMode>
|
|
477
|
+
<I18nProvider locale="en" messages={[messages]}>
|
|
478
|
+
<BrowserRouter>
|
|
479
|
+
<App />
|
|
480
|
+
</BrowserRouter>
|
|
481
|
+
</I18nProvider>
|
|
482
|
+
</React.StrictMode>,
|
|
546
483
|
);
|
|
547
484
|
"
|
|
548
485
|
`;
|
|
549
486
|
|
|
550
487
|
exports[`cloudscape-website generator > should handle npm scope prefix correctly > scoped-dependencies 1`] = `
|
|
551
488
|
{
|
|
552
|
-
"@aws-northstar/ui": "^1.1.13",
|
|
553
|
-
"@aws/pdk": "^0.25.7",
|
|
554
489
|
"@cloudscape-design/board-components": "^3.0.84",
|
|
555
490
|
"@cloudscape-design/components": "^3.0.823",
|
|
491
|
+
"@cloudscape-design/global-styles": "^1.0.34",
|
|
556
492
|
"aws-cdk-lib": "^2.166.0",
|
|
557
|
-
"cdk-nag": "^2.32.2",
|
|
558
493
|
"constructs": "^10.4.2",
|
|
559
494
|
"react": "18.3.1",
|
|
560
495
|
"react-dom": "18.3.1",
|
|
561
|
-
"react-router-dom": "^
|
|
496
|
+
"react-router-dom": "^7.1.1",
|
|
562
497
|
}
|
|
563
498
|
`;
|
|
@@ -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)
|