@infoxchange/make-it-so-sst-v2 3.0.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/.editorconfig +16 -0
- package/LICENSE +21 -0
- package/README.md +377 -0
- package/commitlint.config.ts +14 -0
- package/dist/cdk-constructs/IxApi.d.ts +12 -0
- package/dist/cdk-constructs/IxApi.d.ts.map +1 -0
- package/dist/cdk-constructs/IxApi.js +56 -0
- package/dist/cdk-constructs/IxBucket.d.ts +9 -0
- package/dist/cdk-constructs/IxBucket.d.ts.map +1 -0
- package/dist/cdk-constructs/IxBucket.js +22 -0
- package/dist/cdk-constructs/IxCertificate.d.ts +16 -0
- package/dist/cdk-constructs/IxCertificate.d.ts.map +1 -0
- package/dist/cdk-constructs/IxCertificate.js +26 -0
- package/dist/cdk-constructs/IxDnsRecord.d.ts +23 -0
- package/dist/cdk-constructs/IxDnsRecord.d.ts.map +1 -0
- package/dist/cdk-constructs/IxDnsRecord.js +43 -0
- package/dist/cdk-constructs/IxElasticache.d.ts +17 -0
- package/dist/cdk-constructs/IxElasticache.d.ts.map +1 -0
- package/dist/cdk-constructs/IxElasticache.js +70 -0
- package/dist/cdk-constructs/IxNextjsSite.d.ts +16 -0
- package/dist/cdk-constructs/IxNextjsSite.d.ts.map +1 -0
- package/dist/cdk-constructs/IxNextjsSite.js +38 -0
- package/dist/cdk-constructs/IxQuicksightWorkspace.d.ts +17 -0
- package/dist/cdk-constructs/IxQuicksightWorkspace.d.ts.map +1 -0
- package/dist/cdk-constructs/IxQuicksightWorkspace.js +29 -0
- package/dist/cdk-constructs/IxSESIdentity.d.ts +12 -0
- package/dist/cdk-constructs/IxSESIdentity.d.ts.map +1 -0
- package/dist/cdk-constructs/IxSESIdentity.js +45 -0
- package/dist/cdk-constructs/IxStaticSite.d.ts +17 -0
- package/dist/cdk-constructs/IxStaticSite.d.ts.map +1 -0
- package/dist/cdk-constructs/IxStaticSite.js +38 -0
- package/dist/cdk-constructs/IxVpcDetails.d.ts +12 -0
- package/dist/cdk-constructs/IxVpcDetails.d.ts.map +1 -0
- package/dist/cdk-constructs/IxVpcDetails.js +26 -0
- package/dist/cdk-constructs/IxWebsiteRedirect.d.ts +35 -0
- package/dist/cdk-constructs/IxWebsiteRedirect.d.ts.map +1 -0
- package/dist/cdk-constructs/IxWebsiteRedirect.js +72 -0
- package/dist/cdk-constructs/SiteOidcAuth/auth-check-handler-body.d.ts +2 -0
- package/dist/cdk-constructs/SiteOidcAuth/auth-check-handler-body.d.ts.map +1 -0
- package/dist/cdk-constructs/SiteOidcAuth/auth-check-handler-body.js +130 -0
- package/dist/cdk-constructs/SiteOidcAuth/auth-route.d.ts +2 -0
- package/dist/cdk-constructs/SiteOidcAuth/auth-route.d.ts.map +1 -0
- package/dist/cdk-constructs/SiteOidcAuth/auth-route.js +59 -0
- package/dist/cdk-constructs/SiteOidcAuth/index.d.ts +197 -0
- package/dist/cdk-constructs/SiteOidcAuth/index.d.ts.map +1 -0
- package/dist/cdk-constructs/SiteOidcAuth/index.js +188 -0
- package/dist/cdk-constructs/index.d.ts +11 -0
- package/dist/cdk-constructs/index.d.ts.map +1 -0
- package/dist/cdk-constructs/index.js +10 -0
- package/dist/deployConfig.d.ts +72 -0
- package/dist/deployConfig.d.ts.map +1 -0
- package/dist/deployConfig.js +78 -0
- package/dist/lib/auth/index.d.ts +2 -0
- package/dist/lib/auth/index.d.ts.map +1 -0
- package/dist/lib/auth/index.js +1 -0
- package/dist/lib/auth/oidc.d.ts +26 -0
- package/dist/lib/auth/oidc.d.ts.map +1 -0
- package/dist/lib/auth/oidc.js +48 -0
- package/dist/lib/proxy/fetch.d.ts +4 -0
- package/dist/lib/proxy/fetch.d.ts.map +1 -0
- package/dist/lib/proxy/fetch.js +31 -0
- package/dist/lib/proxy/index.d.ts +2 -0
- package/dist/lib/proxy/index.d.ts.map +1 -0
- package/dist/lib/proxy/index.js +1 -0
- package/dist/lib/site/support.d.ts +71 -0
- package/dist/lib/site/support.d.ts.map +1 -0
- package/dist/lib/site/support.js +262 -0
- package/dist/lib/utils/hash.d.ts +2 -0
- package/dist/lib/utils/hash.d.ts.map +1 -0
- package/dist/lib/utils/hash.js +13 -0
- package/dist/lib/utils/objects.d.ts +4 -0
- package/dist/lib/utils/objects.d.ts.map +1 -0
- package/dist/lib/utils/objects.js +7 -0
- package/eslint.config.js +11 -0
- package/package.json +66 -0
- package/src/cdk-constructs/IxApi.ts +81 -0
- package/src/cdk-constructs/IxBucket.ts +35 -0
- package/src/cdk-constructs/IxCertificate.ts +54 -0
- package/src/cdk-constructs/IxDnsRecord.ts +79 -0
- package/src/cdk-constructs/IxElasticache.ts +106 -0
- package/src/cdk-constructs/IxNextjsSite.ts +72 -0
- package/src/cdk-constructs/IxQuicksightWorkspace.ts +54 -0
- package/src/cdk-constructs/IxSESIdentity.ts +70 -0
- package/src/cdk-constructs/IxStaticSite.ts +69 -0
- package/src/cdk-constructs/IxVpcDetails.ts +38 -0
- package/src/cdk-constructs/IxWebsiteRedirect.ts +133 -0
- package/src/cdk-constructs/SiteOidcAuth/auth-check-handler-body.ts +168 -0
- package/src/cdk-constructs/SiteOidcAuth/auth-route.ts +71 -0
- package/src/cdk-constructs/SiteOidcAuth/index.ts +299 -0
- package/src/cdk-constructs/index.ts +10 -0
- package/src/deployConfig.ts +87 -0
- package/src/lib/auth/index.ts +1 -0
- package/src/lib/auth/oidc.ts +73 -0
- package/src/lib/proxy/fetch.ts +41 -0
- package/src/lib/proxy/index.ts +1 -0
- package/src/lib/site/support.ts +439 -0
- package/src/lib/utils/hash.ts +14 -0
- package/src/lib/utils/objects.ts +19 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import {
|
|
3
|
+
NextjsSite,
|
|
4
|
+
NextjsSiteProps,
|
|
5
|
+
Stack,
|
|
6
|
+
StaticSite,
|
|
7
|
+
StaticSiteProps,
|
|
8
|
+
} from "sst/constructs";
|
|
9
|
+
import ixDeployConfig from "../../deployConfig.js";
|
|
10
|
+
import { IxCertificate } from "../../cdk-constructs/IxCertificate.js";
|
|
11
|
+
import { IxWebsiteRedirect } from "../../cdk-constructs/IxWebsiteRedirect.js";
|
|
12
|
+
import { IxVpcDetails } from "../../cdk-constructs/IxVpcDetails.js";
|
|
13
|
+
import { IxDnsRecord } from "../../cdk-constructs/IxDnsRecord.js";
|
|
14
|
+
import { CloudFrontTarget } from "aws-cdk-lib/aws-route53-targets";
|
|
15
|
+
import { convertToBase62Hash } from "../utils/hash.js";
|
|
16
|
+
import { type DistributionDomainProps } from "sst/constructs/Distribution.js";
|
|
17
|
+
import type { Plan as SSTPlan } from "sst/constructs/SsrSite.js";
|
|
18
|
+
import {
|
|
19
|
+
SiteOidcAuth,
|
|
20
|
+
type AddToSiteProps as SiteOidcAuthAddToSiteProps,
|
|
21
|
+
} from "../../cdk-constructs/SiteOidcAuth/index.js";
|
|
22
|
+
|
|
23
|
+
type SharedExtendedSiteProps = {
|
|
24
|
+
customDomain?: string | ExtendedCustomDomains;
|
|
25
|
+
auth?: {
|
|
26
|
+
oidc: {
|
|
27
|
+
issuerUrl: string;
|
|
28
|
+
clientId: string;
|
|
29
|
+
scope: string;
|
|
30
|
+
};
|
|
31
|
+
} & SiteOidcAuthAddToSiteProps;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type ExtendedCustomDomains = DistributionDomainProps & {
|
|
35
|
+
isIxManagedDomain?: boolean;
|
|
36
|
+
additionalDomainAliases?: string[];
|
|
37
|
+
};
|
|
38
|
+
export type ExtendedNextjsSiteProps = Omit<
|
|
39
|
+
NextjsSiteProps,
|
|
40
|
+
"customDomain" | "environment"
|
|
41
|
+
> &
|
|
42
|
+
SharedExtendedSiteProps & {
|
|
43
|
+
/**
|
|
44
|
+
* An object with the key being the environment variable name. The value can either be the environment variable value
|
|
45
|
+
* as a string or as an object with `buildtime` and/or `runtime` properties where the values of `buildtime` and
|
|
46
|
+
* `runtime` is the environment variable value that will be used during that step.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```js
|
|
50
|
+
* environment: {
|
|
51
|
+
* USER_POOL_CLIENT: auth.cognitoUserPoolClient.userPoolClientId,
|
|
52
|
+
* NODE_OPTIONS: {
|
|
53
|
+
* buildtime: "--max-old-space-size=4096",
|
|
54
|
+
* },
|
|
55
|
+
* API_URL: {
|
|
56
|
+
* buildtime: "https://external.domain",
|
|
57
|
+
* runtime: "https://internal.domain",
|
|
58
|
+
* },
|
|
59
|
+
* },
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
environment?: Record<
|
|
63
|
+
string,
|
|
64
|
+
string | { buildtime?: string; runtime?: string }
|
|
65
|
+
>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type ExtendedStaticSiteProps = Omit<StaticSiteProps, "customDomain"> &
|
|
69
|
+
SharedExtendedSiteProps;
|
|
70
|
+
|
|
71
|
+
export function setupCustomDomain<
|
|
72
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
73
|
+
>(scope: Construct, id: string, props: Readonly<Props>): Props {
|
|
74
|
+
let updatedProps = props;
|
|
75
|
+
// Default to using domains names passed in by the pipeline as the custom domain
|
|
76
|
+
if (ixDeployConfig.isIxDeploy && !("customDomain" in updatedProps)) {
|
|
77
|
+
updatedProps = {
|
|
78
|
+
...updatedProps,
|
|
79
|
+
customDomain: {
|
|
80
|
+
isIxManagedDomain: true,
|
|
81
|
+
isExternalDomain: true,
|
|
82
|
+
domainName: ixDeployConfig.siteDomains[0],
|
|
83
|
+
alternateNames: ixDeployConfig.siteDomains.slice(1),
|
|
84
|
+
domainAlias: ixDeployConfig.siteDomainAliases[0],
|
|
85
|
+
additionalDomainAliases: ixDeployConfig.siteDomainAliases.slice(1),
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return updatedProps;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function setupCertificate<
|
|
93
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
94
|
+
>(scope: Construct, id: string, props: Readonly<Props>): Props {
|
|
95
|
+
const updatedProps: Props = { ...props };
|
|
96
|
+
if (!updatedProps?.customDomain) return updatedProps;
|
|
97
|
+
|
|
98
|
+
if (typeof updatedProps.customDomain === "string") {
|
|
99
|
+
updatedProps.customDomain = { domainName: updatedProps.customDomain };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// No cert creation required if isIxManagedDomain is false or a cert is already provided
|
|
103
|
+
if (
|
|
104
|
+
!updatedProps.customDomain.isIxManagedDomain &&
|
|
105
|
+
updatedProps.customDomain.cdk?.certificate
|
|
106
|
+
) {
|
|
107
|
+
return updatedProps;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const domainCert = new IxCertificate(scope, id + "-IxCertificate", {
|
|
111
|
+
domainName: updatedProps.customDomain.domainName,
|
|
112
|
+
subjectAlternativeNames: updatedProps.customDomain.alternateNames,
|
|
113
|
+
region: "us-east-1", // CloudFront will only use certificates in us-east-1
|
|
114
|
+
});
|
|
115
|
+
updatedProps.customDomain.cdk = updatedProps.customDomain.cdk ?? {};
|
|
116
|
+
updatedProps.customDomain.cdk.certificate = domainCert.acmCertificate;
|
|
117
|
+
|
|
118
|
+
return updatedProps;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function setupDomainAliasRedirect<
|
|
122
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
123
|
+
>(scope: Construct, id: string, props: Readonly<Props>): Props {
|
|
124
|
+
if (
|
|
125
|
+
typeof props.customDomain !== "object" ||
|
|
126
|
+
!(
|
|
127
|
+
props.customDomain.domainAlias ||
|
|
128
|
+
props.customDomain.additionalDomainAliases?.length
|
|
129
|
+
) ||
|
|
130
|
+
!props.customDomain.isIxManagedDomain ||
|
|
131
|
+
!props.customDomain.cdk?.certificate
|
|
132
|
+
) {
|
|
133
|
+
return props;
|
|
134
|
+
}
|
|
135
|
+
const domainsToRedirectFrom = [
|
|
136
|
+
...(props.customDomain.domainAlias ? [props.customDomain.domainAlias] : []),
|
|
137
|
+
...(props.customDomain.additionalDomainAliases ?? []),
|
|
138
|
+
];
|
|
139
|
+
new IxWebsiteRedirect(scope, id + "-IxWebsiteRedirect", {
|
|
140
|
+
recordNames: domainsToRedirectFrom,
|
|
141
|
+
targetDomain: props.customDomain.domainName,
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
...props,
|
|
145
|
+
customDomain: {
|
|
146
|
+
...props.customDomain,
|
|
147
|
+
domainAlias: undefined, // SST's site constructs will complain if domainAlias is set while isExternalDomain is true
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function setupVpcDetails<Props extends ExtendedNextjsSiteProps>(
|
|
153
|
+
scope: Construct,
|
|
154
|
+
id: string,
|
|
155
|
+
props: Readonly<Props>,
|
|
156
|
+
): Props {
|
|
157
|
+
const updatedProps: Props = { ...props };
|
|
158
|
+
|
|
159
|
+
// Don't make any changes if the user has set the VPC manually in any place
|
|
160
|
+
if (
|
|
161
|
+
"vpc" in (updatedProps.cdk?.server || {}) ||
|
|
162
|
+
"vpc" in (updatedProps.cdk?.revalidation || {})
|
|
163
|
+
) {
|
|
164
|
+
return updatedProps;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const vpcDetails = new IxVpcDetails(scope, id + "-IxVpcDetails");
|
|
168
|
+
|
|
169
|
+
updatedProps.cdk = updatedProps.cdk ?? {};
|
|
170
|
+
updatedProps.cdk.server = {
|
|
171
|
+
...updatedProps.cdk.server,
|
|
172
|
+
vpc: vpcDetails.vpc,
|
|
173
|
+
};
|
|
174
|
+
updatedProps.cdk.revalidation = {
|
|
175
|
+
...updatedProps.cdk.revalidation,
|
|
176
|
+
vpc: vpcDetails.vpc,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
if (!ixDeployConfig.vpcHttpProxy) {
|
|
180
|
+
console.warn(
|
|
181
|
+
`Attempting to add HTTP proxy environment variables to ${id} but the VPC_HTTP_PROXY env var is not configured.`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
// If we're using the AWS runner then the build stage will already be inside the VPC and required the proxy but
|
|
185
|
+
// the HTTP proxy environment variables will be already set in the environment by the pipeline and so the build
|
|
186
|
+
// stage will inherit that.
|
|
187
|
+
updatedProps.environment = {
|
|
188
|
+
HTTP_PROXY: { runtime: ixDeployConfig.vpcHttpProxy },
|
|
189
|
+
HTTPS_PROXY: { runtime: ixDeployConfig.vpcHttpProxy },
|
|
190
|
+
http_proxy: { runtime: ixDeployConfig.vpcHttpProxy },
|
|
191
|
+
https_proxy: { runtime: ixDeployConfig.vpcHttpProxy },
|
|
192
|
+
...updatedProps.environment,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return updatedProps;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Ensures environment variables that are conditionally included for buildtime or runtime are only used during the
|
|
200
|
+
* appropriate phase.
|
|
201
|
+
*/
|
|
202
|
+
export function applyConditionalEnvironmentVariables<
|
|
203
|
+
Props extends ExtendedNextjsSiteProps,
|
|
204
|
+
>(scope: Construct, id: string, props: Readonly<Props>): Props {
|
|
205
|
+
const updatedProps: Props = { ...props };
|
|
206
|
+
|
|
207
|
+
if (!updatedProps.environment) return updatedProps;
|
|
208
|
+
|
|
209
|
+
const buildtimeSpecificEnvVars = Object.fromEntries(
|
|
210
|
+
Object.entries(updatedProps.environment)
|
|
211
|
+
.filter(([, value]) => typeof value === "object")
|
|
212
|
+
.map(([varName, value]) => [
|
|
213
|
+
varName,
|
|
214
|
+
typeof value === "object" && "buildtime" in value
|
|
215
|
+
? value.buildtime
|
|
216
|
+
: undefined,
|
|
217
|
+
]),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
const runtimeSpecificEnvVars = Object.fromEntries(
|
|
221
|
+
Object.entries(updatedProps.environment)
|
|
222
|
+
.filter(([, value]) => typeof value === "object")
|
|
223
|
+
.map(([varName, value]) => [
|
|
224
|
+
varName,
|
|
225
|
+
typeof value === "object" && "runtime" in value
|
|
226
|
+
? value.runtime
|
|
227
|
+
: undefined,
|
|
228
|
+
]),
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Remove runtime excluded env vars from lambda
|
|
232
|
+
updatedProps.cdk = updatedProps.cdk ?? {};
|
|
233
|
+
const oldTransform = updatedProps.cdk.transform;
|
|
234
|
+
updatedProps.cdk.transform = (plan: SSTPlan) => {
|
|
235
|
+
oldTransform?.(plan);
|
|
236
|
+
|
|
237
|
+
for (const origin of Object.values(plan.origins)) {
|
|
238
|
+
if (!("function" in origin) || !origin.function.environment) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
for (const [envVarName, envVarValue] of Object.entries(
|
|
242
|
+
runtimeSpecificEnvVars,
|
|
243
|
+
)) {
|
|
244
|
+
if (envVarValue !== undefined) {
|
|
245
|
+
origin.function.environment[envVarName] = envVarValue;
|
|
246
|
+
} else {
|
|
247
|
+
// @ts-expect-error - Environment values should generally only be strings but we need to set it to undefined
|
|
248
|
+
// as a workaround to override any environment variables that are mixed in during function creation which are
|
|
249
|
+
// only meant to be included at build time.
|
|
250
|
+
// https://github.com/sst/v2/blob/d0c9d5c1cbf8016b2a2b7ed2e247c27546b40387/packages/sst/src/constructs/SsrSite.ts#L1029
|
|
251
|
+
origin.function.environment[envVarName] = undefined;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// Remove buildtime excluded env vars from environment object which is used during build
|
|
258
|
+
for (const [envVarName, envVarValue] of Object.entries(
|
|
259
|
+
buildtimeSpecificEnvVars,
|
|
260
|
+
)) {
|
|
261
|
+
if (envVarValue !== undefined) {
|
|
262
|
+
updatedProps.environment[envVarName] = envVarValue;
|
|
263
|
+
} else {
|
|
264
|
+
delete updatedProps.environment[envVarName];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return updatedProps;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Before props reach this function they should have already been converted into something compatible with the parent
|
|
273
|
+
* SST construct. This function verifies that's the case and updates the type if so.
|
|
274
|
+
*/
|
|
275
|
+
export function parentCompatibleSsrProps<
|
|
276
|
+
Props extends ExtendedNextjsSiteProps,
|
|
277
|
+
ResultProps = Omit<Props, "environment"> & {
|
|
278
|
+
environment?: Record<string, string>;
|
|
279
|
+
},
|
|
280
|
+
>(props: Readonly<Props>): ResultProps {
|
|
281
|
+
for (const value of Object.values(props.environment ?? {})) {
|
|
282
|
+
if (typeof value !== "string") {
|
|
283
|
+
throw new Error(
|
|
284
|
+
"Internal make-it-so error: The environment prop contains buildtime/runtime specific environment variables which cannot be passed to the parent NextjsSite construct. Please use the applyConditionalEnvironmentVariables function to ensure only appropriate environment variables are included.",
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return props as ResultProps;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function setupDefaultEnvVars<Props extends ExtendedNextjsSiteProps>(
|
|
292
|
+
scope: Construct | Stack,
|
|
293
|
+
id: string,
|
|
294
|
+
props: Readonly<Props>,
|
|
295
|
+
): Props {
|
|
296
|
+
const updatedProps: Props = { ...props };
|
|
297
|
+
// NextjsSite functions to not use default env var unfortunately so we have to
|
|
298
|
+
// explicitly set them ourselves https://github.com/sst/sst/issues/2359
|
|
299
|
+
if ("defaultFunctionProps" in scope) {
|
|
300
|
+
for (const funcProps of scope.defaultFunctionProps) {
|
|
301
|
+
const defaultFunctionEnvVars = { ...funcProps.environment };
|
|
302
|
+
|
|
303
|
+
updatedProps.environment = {
|
|
304
|
+
...defaultFunctionEnvVars,
|
|
305
|
+
...updatedProps.environment,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return updatedProps;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function setupDnsRecords<
|
|
313
|
+
Instance extends NextjsSite | StaticSite,
|
|
314
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
315
|
+
>(
|
|
316
|
+
instance: Instance,
|
|
317
|
+
scope: Construct,
|
|
318
|
+
id: string,
|
|
319
|
+
props: Readonly<Props>,
|
|
320
|
+
): void {
|
|
321
|
+
if (
|
|
322
|
+
!instance.cdk?.distribution ||
|
|
323
|
+
typeof props.customDomain !== "object" ||
|
|
324
|
+
!props.customDomain.isIxManagedDomain
|
|
325
|
+
)
|
|
326
|
+
return;
|
|
327
|
+
|
|
328
|
+
for (const domainName of getCustomDomains(props)) {
|
|
329
|
+
const domainNameLogicalId = convertToBase62Hash(domainName);
|
|
330
|
+
|
|
331
|
+
new IxDnsRecord(scope, `DnsRecord-${domainNameLogicalId}`, {
|
|
332
|
+
type: "ALIAS",
|
|
333
|
+
name: domainName,
|
|
334
|
+
value: instance.cdk.distribution.distributionDomainName,
|
|
335
|
+
aliasZoneId: CloudFrontTarget.getHostedZoneId(scope),
|
|
336
|
+
ttl: 900,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function getCustomDomains<
|
|
342
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
343
|
+
>(props: Readonly<Props>): string[] {
|
|
344
|
+
const domainNames = new Set<string>();
|
|
345
|
+
|
|
346
|
+
const primaryCustomDomain = getPrimaryCustomDomain(props);
|
|
347
|
+
const alternativeDomains = getAlternativeDomains(props);
|
|
348
|
+
|
|
349
|
+
if (primaryCustomDomain) domainNames.add(primaryCustomDomain);
|
|
350
|
+
if (alternativeDomains.length)
|
|
351
|
+
alternativeDomains.forEach((domain) => domainNames.add(domain));
|
|
352
|
+
|
|
353
|
+
return Array.from(domainNames);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function getPrimaryDomain<
|
|
357
|
+
Instance extends NextjsSite | StaticSite,
|
|
358
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
359
|
+
>(instance: Instance, props: Readonly<Props>): string | null {
|
|
360
|
+
return (
|
|
361
|
+
getPrimaryCustomDomain(props) ??
|
|
362
|
+
instance.cdk?.distribution?.distributionDomainName ??
|
|
363
|
+
null
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function getPrimaryOrigin<
|
|
368
|
+
Instance extends NextjsSite | StaticSite,
|
|
369
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
370
|
+
>(instance: Instance, props: Readonly<Props>): string | null {
|
|
371
|
+
const primaryDomain = getPrimaryDomain(instance, props);
|
|
372
|
+
return primaryDomain ? `https://${primaryDomain}` : null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function getPrimaryCustomDomain<
|
|
376
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
377
|
+
>(props: Readonly<Props>): string | null {
|
|
378
|
+
if (typeof props.customDomain === "string") {
|
|
379
|
+
return props.customDomain;
|
|
380
|
+
} else if (typeof props.customDomain === "object") {
|
|
381
|
+
return props.customDomain.domainName ?? null;
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export function getAliasDomain<
|
|
387
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
388
|
+
>(props: Readonly<Props>): string | null {
|
|
389
|
+
if (typeof props.customDomain === "object") {
|
|
390
|
+
return props.customDomain.domainAlias ?? null;
|
|
391
|
+
}
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function getAlternativeDomains<
|
|
396
|
+
Props extends ExtendedStaticSiteProps | ExtendedNextjsSiteProps,
|
|
397
|
+
>(props: Readonly<Props>): string[] {
|
|
398
|
+
if (typeof props.customDomain === "object") {
|
|
399
|
+
return props.customDomain.alternateNames ?? [];
|
|
400
|
+
}
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export function processAuthProps<
|
|
405
|
+
SiteType extends "StaticSite" | "SsrSite",
|
|
406
|
+
Props extends SiteType extends "StaticSite"
|
|
407
|
+
? ExtendedStaticSiteProps
|
|
408
|
+
: ExtendedNextjsSiteProps,
|
|
409
|
+
>(
|
|
410
|
+
scope: Construct,
|
|
411
|
+
id: string,
|
|
412
|
+
siteType: SiteType,
|
|
413
|
+
props: Readonly<Props>,
|
|
414
|
+
): Props {
|
|
415
|
+
if (!props.auth) return props;
|
|
416
|
+
const { oidc, ...otherAuthProps } = props.auth;
|
|
417
|
+
const auth = new SiteOidcAuth(scope, `${id}-SiteOidcAuth`, {
|
|
418
|
+
oidcIssuerUrl: oidc.issuerUrl,
|
|
419
|
+
oidcClientId: oidc.clientId,
|
|
420
|
+
oidcScope: oidc.scope,
|
|
421
|
+
});
|
|
422
|
+
if (siteType === "StaticSite") {
|
|
423
|
+
return auth.addToStaticSiteProps(
|
|
424
|
+
scope,
|
|
425
|
+
props as ExtendedStaticSiteProps,
|
|
426
|
+
otherAuthProps,
|
|
427
|
+
) as Props;
|
|
428
|
+
} else if (siteType === "SsrSite") {
|
|
429
|
+
return auth.addToSsrSiteProps(
|
|
430
|
+
scope,
|
|
431
|
+
props as ExtendedNextjsSiteProps,
|
|
432
|
+
otherAuthProps,
|
|
433
|
+
) as Props;
|
|
434
|
+
}
|
|
435
|
+
siteType satisfies never;
|
|
436
|
+
throw new Error(
|
|
437
|
+
`Unsupported site type ${siteType} when processing auth prop.`,
|
|
438
|
+
);
|
|
439
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function convertToBase62Hash(string: string): string {
|
|
2
|
+
const base62Chars =
|
|
3
|
+
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
4
|
+
let hash = "";
|
|
5
|
+
let num = 0;
|
|
6
|
+
for (let i = 0; i < string.length; i++) {
|
|
7
|
+
num += string.charCodeAt(i);
|
|
8
|
+
}
|
|
9
|
+
while (num > 0) {
|
|
10
|
+
hash = base62Chars[num % 62] + hash;
|
|
11
|
+
num = Math.floor(num / 62);
|
|
12
|
+
}
|
|
13
|
+
return hash;
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function remapKeys<
|
|
2
|
+
SourceObject extends object,
|
|
3
|
+
MapObject extends Record<keyof SourceObject, string>,
|
|
4
|
+
>(
|
|
5
|
+
object: SourceObject,
|
|
6
|
+
keyMap: Readonly<MapObject>,
|
|
7
|
+
): {
|
|
8
|
+
[k in keyof SourceObject as k extends keyof MapObject
|
|
9
|
+
? MapObject[k]
|
|
10
|
+
: k]: SourceObject[k];
|
|
11
|
+
} {
|
|
12
|
+
return Object.fromEntries(
|
|
13
|
+
Object.entries(object).map(([key, value]) => {
|
|
14
|
+
// @ts-expect-error the typing for map() reduces keys to general string
|
|
15
|
+
const newKey = keyMap[key] ?? key;
|
|
16
|
+
return [newKey, value];
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
}
|