sst 2.0.0-rc.53 → 2.0.0-rc.55
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/bootstrap.d.ts +10 -0
- package/bootstrap.js +1 -1
- package/cdk/cloudformation-deployments-wrapper.js +8 -3
- package/cdk/deploy-stack.js +5 -0
- package/cli/commands/deploy.js +27 -2
- package/cli/commands/dev.js +38 -11
- package/cli/commands/remove.js +2 -1
- package/cli/local/server.js +1 -1
- package/cli/sst.js +4 -0
- package/cli/ui/deploy.js +4 -3
- package/constructs/Api.d.ts +1 -1
- package/constructs/Api.js +3 -6
- package/constructs/ApiGatewayV1Api.js +2 -2
- package/constructs/App.js +1 -1
- package/constructs/Auth.js +16 -16
- package/constructs/Cognito.js +28 -28
- package/constructs/EdgeFunction.js +8 -4
- package/constructs/NextjsSite.js +6 -4
- package/constructs/Queue.js +10 -10
- package/constructs/Secret.js +2 -2
- package/constructs/SolidStartSite.js +3 -1
- package/constructs/SsrSite.js +0 -1
- package/constructs/StaticSite.d.ts +50 -30
- package/constructs/StaticSite.js +105 -80
- package/constructs/Table.js +4 -4
- package/constructs/Topic.js +1 -1
- package/constructs/deprecated/NextjsSite.js +3 -1
- package/constructs/util/apiGatewayV2AccessLog.js +4 -4
- package/constructs/util/apiGatewayV2Domain.js +1 -3
- package/constructs/util/appSyncApiDomain.js +9 -15
- package/constructs/util/permission.js +12 -12
- package/constructs/util/warning.js +2 -2
- package/context/context.d.ts +2 -2
- package/context/context.js +4 -4
- package/node/auth/adapter/facebook.js +1 -1
- package/node/auth/adapter/google.js +2 -2
- package/node/auth/adapter/twitch.js +1 -1
- package/node/config/index.js +3 -8
- package/node/site/index.js +3 -5
- package/package.json +1 -1
- package/project.js +2 -2
- package/sst.mjs +230 -69
- package/stacks/app-metadata.d.ts +7 -0
- package/stacks/app-metadata.js +78 -0
- package/stacks/index.d.ts +1 -0
- package/stacks/index.js +1 -0
- package/stacks/synth.js +2 -2
- package/support/bootstrap-metadata-function/index.mjs +36 -25
- package/support/custom-resources/index.mjs +1 -4
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap.deps.json +1 -1
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap.runtimeconfig.json +1 -1
- package/support/remix-site-function/edge-server.js +1 -1
package/bootstrap.d.ts
CHANGED
package/bootstrap.js
CHANGED
|
@@ -23,7 +23,7 @@ const OUTPUT_VERSION = "Version";
|
|
|
23
23
|
const OUTPUT_BUCKET = "BucketName";
|
|
24
24
|
const LATEST_VERSION = "6";
|
|
25
25
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
26
|
-
const BootstrapContext = Context.create();
|
|
26
|
+
export const BootstrapContext = Context.create("Bootstrap");
|
|
27
27
|
export const useBootstrap = BootstrapContext.use;
|
|
28
28
|
export async function initBootstrap() {
|
|
29
29
|
Logger.debug("Initializing bootstrap context");
|
|
@@ -62,7 +62,7 @@ const useDeployment = Context.memo(() => {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
return state.get(sdkProvider);
|
|
65
|
-
}
|
|
65
|
+
},
|
|
66
66
|
};
|
|
67
67
|
});
|
|
68
68
|
async function deployStack(options) {
|
|
@@ -99,13 +99,18 @@ async function deployStack(options) {
|
|
|
99
99
|
parallel: options.assetParallelism,
|
|
100
100
|
});
|
|
101
101
|
return {
|
|
102
|
-
isUpdate: cloudFormationStack.exists &&
|
|
102
|
+
isUpdate: cloudFormationStack.exists &&
|
|
103
|
+
cloudFormationStack.stackStatus.name !== "REVIEW_IN_PROGRESS",
|
|
103
104
|
params: {
|
|
104
105
|
StackName: deployName,
|
|
105
106
|
TemplateBody: bodyParameter.TemplateBody,
|
|
106
107
|
TemplateURL: bodyParameter.TemplateURL,
|
|
107
108
|
Parameters: stackParams.apiParameters,
|
|
108
|
-
Capabilities: [
|
|
109
|
+
Capabilities: [
|
|
110
|
+
"CAPABILITY_IAM",
|
|
111
|
+
"CAPABILITY_NAMED_IAM",
|
|
112
|
+
"CAPABILITY_AUTO_EXPAND",
|
|
113
|
+
],
|
|
109
114
|
Tags: options.tags,
|
|
110
115
|
},
|
|
111
116
|
};
|
package/cdk/deploy-stack.js
CHANGED
|
@@ -459,6 +459,11 @@ async function canSkipDeploy(deployStackOptions, cloudFormationStack, parameterC
|
|
|
459
459
|
debug(`${deployName}: no existing stack`);
|
|
460
460
|
return false;
|
|
461
461
|
}
|
|
462
|
+
// SST check: stack is not busy
|
|
463
|
+
if (cloudFormationStack.stackStatus.isInProgress) {
|
|
464
|
+
debug(`${deployName}: stack is busy`);
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
462
467
|
// Template has changed (assets taken into account here)
|
|
463
468
|
if (JSON.stringify(deployStackOptions.stack.template) !==
|
|
464
469
|
JSON.stringify(await cloudFormationStack.template())) {
|
package/cli/commands/deploy.js
CHANGED
|
@@ -16,12 +16,21 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
|
|
|
16
16
|
const { createSpinner } = await import("../spinner.js");
|
|
17
17
|
const { dim, blue, bold } = await import("colorette");
|
|
18
18
|
const { useProject } = await import("../../project.js");
|
|
19
|
-
const { loadAssembly, Stacks } = await import("../../stacks/index.js");
|
|
19
|
+
const { loadAssembly, useAppMetadata, saveAppMetadata, Stacks } = await import("../../stacks/index.js");
|
|
20
20
|
const { render } = await import("ink");
|
|
21
21
|
const { DeploymentUI } = await import("../ui/deploy.js");
|
|
22
22
|
const { mapValues } = await import("remeda");
|
|
23
23
|
const project = useProject();
|
|
24
|
-
const identity = await
|
|
24
|
+
const [identity, appMetadata] = await Promise.all([
|
|
25
|
+
useSTSIdentity(),
|
|
26
|
+
useAppMetadata(),
|
|
27
|
+
]);
|
|
28
|
+
// Check app mode changed
|
|
29
|
+
if (appMetadata && appMetadata.mode !== "deploy") {
|
|
30
|
+
if (!(await promptChangeMode())) {
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
25
34
|
Colors.line(`${Colors.primary.bold(`SST v${project.version}`)}`);
|
|
26
35
|
Colors.gap();
|
|
27
36
|
Colors.line(`${Colors.primary(`➜`)} ${Colors.bold("App:")} ${project.config.name}`);
|
|
@@ -61,5 +70,21 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
|
|
|
61
70
|
if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
|
|
62
71
|
process.exit(1);
|
|
63
72
|
fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(mapValues(results, (val) => val.outputs), null, 2));
|
|
73
|
+
// Update app state
|
|
74
|
+
await saveAppMetadata({ mode: "deploy" });
|
|
64
75
|
process.exit(0);
|
|
65
76
|
});
|
|
77
|
+
async function promptChangeMode() {
|
|
78
|
+
const readline = await import("readline");
|
|
79
|
+
const rl = readline.createInterface({
|
|
80
|
+
input: process.stdin,
|
|
81
|
+
output: process.stdout,
|
|
82
|
+
});
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
console.log("");
|
|
85
|
+
rl.question("You were previously running this stage in dev mode. It is recommended that you use a different stage for production. Read more here — https://docs.sst.dev/live-lambda-development\n\nAre you sure you want to deploy to this stage? (y/N) ", async (input) => {
|
|
86
|
+
rl.close();
|
|
87
|
+
resolve(input.trim() === "y");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
package/cli/commands/dev.js
CHANGED
|
@@ -10,21 +10,19 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
10
10
|
const { useRuntimeServer } = await import("../../runtime/server.js");
|
|
11
11
|
const { useBus } = await import("../../bus.js");
|
|
12
12
|
const { useWatcher } = await import("../../watcher.js");
|
|
13
|
-
const { Stacks } = await import("../../stacks/index.js");
|
|
13
|
+
const { useAppMetadata, saveAppMetadata, Stacks } = await import("../../stacks/index.js");
|
|
14
14
|
const { Logger } = await import("../../logger.js");
|
|
15
15
|
const { createSpinner } = await import("../spinner.js");
|
|
16
|
-
const { bold,
|
|
16
|
+
const { bold, dim, yellow } = await import("colorette");
|
|
17
17
|
const { render } = await import("ink");
|
|
18
18
|
const React = await import("react");
|
|
19
19
|
const { Context } = await import("../../context/context.js");
|
|
20
|
-
const { DeploymentUI } = await import("../ui/deploy.js");
|
|
20
|
+
const { printDeploymentResults, DeploymentUI } = await import("../ui/deploy.js");
|
|
21
21
|
const { useLocalServer } = await import("../local/server.js");
|
|
22
22
|
const path = await import("path");
|
|
23
23
|
const fs = await import("fs/promises");
|
|
24
24
|
const crypto = await import("crypto");
|
|
25
|
-
const { printDeploymentResults } = await import("../ui/deploy.js");
|
|
26
25
|
const { useFunctions } = await import("../../constructs/Function.js");
|
|
27
|
-
const { dim, gray, yellow } = await import("colorette");
|
|
28
26
|
const { SiteEnv } = await import("../../site-env.js");
|
|
29
27
|
const { usePothosBuilder } = await import("./plugins/pothos.js");
|
|
30
28
|
const { useKyselyTypeGenerator } = await import("./plugins/kysely.js");
|
|
@@ -169,8 +167,13 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
169
167
|
const results = await Stacks.deployMany(assembly.stacks);
|
|
170
168
|
component.clear();
|
|
171
169
|
component.unmount();
|
|
172
|
-
lastDeployed = nextChecksum;
|
|
173
170
|
printDeploymentResults(assembly, results);
|
|
171
|
+
// Update app state
|
|
172
|
+
if (!lastDeployed) {
|
|
173
|
+
await saveAppMetadata({ mode: "dev" });
|
|
174
|
+
}
|
|
175
|
+
lastDeployed = nextChecksum;
|
|
176
|
+
// Update site env
|
|
174
177
|
const keys = await SiteEnv.keys();
|
|
175
178
|
if (keys.length) {
|
|
176
179
|
const result = {};
|
|
@@ -186,6 +189,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
186
189
|
}
|
|
187
190
|
await SiteEnv.writeValues(result);
|
|
188
191
|
}
|
|
192
|
+
// Write outputs.json
|
|
189
193
|
fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(pipe(results, omitBy((_, key) => key.includes("SstSiteEnv")), mapValues((val) => val.outputs)), null, 2));
|
|
190
194
|
isWorking = false;
|
|
191
195
|
if (isDirty)
|
|
@@ -217,11 +221,20 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
217
221
|
});
|
|
218
222
|
await build();
|
|
219
223
|
});
|
|
220
|
-
await
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
const [appMetadata] = await Promise.all([
|
|
225
|
+
useAppMetadata(),
|
|
226
|
+
useLocalServer({
|
|
227
|
+
key: "",
|
|
228
|
+
cert: "",
|
|
229
|
+
live: true,
|
|
230
|
+
}),
|
|
231
|
+
]);
|
|
232
|
+
// Check app mode changed
|
|
233
|
+
if (appMetadata && appMetadata.mode !== "dev") {
|
|
234
|
+
if (!(await promptChangeMode())) {
|
|
235
|
+
process.exit(0);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
225
238
|
clear();
|
|
226
239
|
await printHeader({ console: true, hint: "ready!" });
|
|
227
240
|
await Promise.all([
|
|
@@ -236,3 +249,17 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
236
249
|
useStackBuilder(),
|
|
237
250
|
]);
|
|
238
251
|
});
|
|
252
|
+
async function promptChangeMode() {
|
|
253
|
+
const readline = await import("readline");
|
|
254
|
+
const rl = readline.createInterface({
|
|
255
|
+
input: process.stdin,
|
|
256
|
+
output: process.stdout,
|
|
257
|
+
});
|
|
258
|
+
return new Promise((resolve) => {
|
|
259
|
+
console.log("");
|
|
260
|
+
rl.question("You have previously deployed this stage in production. It is recommended that you use a different stage for development. Read more here — https://docs.sst.dev/live-lambda-development\n\nAre you sure you want to run this stage in dev mode? [y/N] ", async (input) => {
|
|
261
|
+
rl.close();
|
|
262
|
+
resolve(input.trim() === "y");
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
package/cli/commands/remove.js
CHANGED
|
@@ -5,7 +5,7 @@ export const remove = (program) => program.command("remove [filter]", "Remove yo
|
|
|
5
5
|
const React = await import("react");
|
|
6
6
|
const { dim, blue, bold } = await import("colorette");
|
|
7
7
|
const { useProject } = await import("../../project.js");
|
|
8
|
-
const { loadAssembly, Stacks } = await import("../../stacks/index.js");
|
|
8
|
+
const { loadAssembly, clearAppMetadata, Stacks } = await import("../../stacks/index.js");
|
|
9
9
|
const { render } = await import("ink");
|
|
10
10
|
const { DeploymentUI } = await import("../ui/deploy.js");
|
|
11
11
|
const { printDeploymentResults } = await import("../ui/deploy.js");
|
|
@@ -42,5 +42,6 @@ export const remove = (program) => program.command("remove [filter]", "Remove yo
|
|
|
42
42
|
printDeploymentResults(assembly, results, true);
|
|
43
43
|
if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
|
|
44
44
|
process.exit(1);
|
|
45
|
+
await clearAppMetadata();
|
|
45
46
|
process.exit(0);
|
|
46
47
|
});
|
package/cli/local/server.js
CHANGED
|
@@ -20,7 +20,7 @@ export const useLocalServerConfig = Context.memo(async () => {
|
|
|
20
20
|
});
|
|
21
21
|
return {
|
|
22
22
|
port,
|
|
23
|
-
url: `https://console.sst.dev/${project.config.name}/${project.config.stage}${port !== 13557 ? `?
|
|
23
|
+
url: `https://console.sst.dev/${project.config.name}/${project.config.stage}${port !== 13557 ? `?_port=${port}` : ""}`,
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
26
|
export async function useLocalServer(opts) {
|
package/cli/sst.js
CHANGED
|
@@ -8,6 +8,10 @@ import dotenv from "dotenv";
|
|
|
8
8
|
dotenv.config({
|
|
9
9
|
override: true,
|
|
10
10
|
});
|
|
11
|
+
dotenv.config({
|
|
12
|
+
path: ".env.local",
|
|
13
|
+
override: true,
|
|
14
|
+
});
|
|
11
15
|
import { env } from "./commands/env.js";
|
|
12
16
|
import { dev } from "./commands/dev.js";
|
|
13
17
|
import { bind } from "./commands/bind.js";
|
package/cli/ui/deploy.js
CHANGED
|
@@ -45,9 +45,11 @@ export const DeploymentUI = (props) => {
|
|
|
45
45
|
return "yellow";
|
|
46
46
|
}
|
|
47
47
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
48
|
-
Object.entries(resources)
|
|
48
|
+
Object.entries(resources)
|
|
49
|
+
.slice(0, process.stdout.rows - 2)
|
|
50
|
+
.map(([_, evt], index) => {
|
|
49
51
|
const readable = logicalIdToCdkPath(props.assembly, evt.StackName, evt.LogicalResourceId);
|
|
50
|
-
return (React.createElement(Box, { key:
|
|
52
|
+
return (React.createElement(Box, { key: index },
|
|
51
53
|
React.createElement(Text, null,
|
|
52
54
|
React.createElement(Spinner, null),
|
|
53
55
|
" ",
|
|
@@ -113,7 +115,6 @@ function logicalIdToCdkPath(assembly, stack, logicalId) {
|
|
|
113
115
|
return found.split("/").filter(Boolean).slice(1, -1).join("/");
|
|
114
116
|
}
|
|
115
117
|
function getHelper(error) {
|
|
116
|
-
return `This is a common deploy error. Check out this GitHub issue for more details - https://github.com/serverless-stack/sst/issues/125`;
|
|
117
118
|
return (getApiAccessLogPermissionsHelper(error) ||
|
|
118
119
|
getAppSyncMultiResolverHelper(error) ||
|
|
119
120
|
getApiLogRoleHelper(error));
|
package/constructs/Api.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import * as apigV2Cors from "./util/apiGatewayV2Cors.js";
|
|
|
14
14
|
import * as apigV2Domain from "./util/apiGatewayV2Domain.js";
|
|
15
15
|
import * as apigV2AccessLog from "./util/apiGatewayV2AccessLog.js";
|
|
16
16
|
declare const PayloadFormatVersions: readonly ["1.0", "2.0"];
|
|
17
|
-
export type ApiPayloadFormatVersion = typeof PayloadFormatVersions[number];
|
|
17
|
+
export type ApiPayloadFormatVersion = (typeof PayloadFormatVersions)[number];
|
|
18
18
|
export type ApiAuthorizer = ApiUserPoolAuthorizer | ApiJwtAuthorizer | ApiLambdaAuthorizer;
|
|
19
19
|
interface ApiBaseAuthorizer {
|
|
20
20
|
/**
|
package/constructs/Api.js
CHANGED
|
@@ -127,8 +127,7 @@ export class Api extends Construct {
|
|
|
127
127
|
const route = this.routesData[this.normalizeRouteKey(routeKey)];
|
|
128
128
|
if (!route)
|
|
129
129
|
return;
|
|
130
|
-
if (route.type === "function" ||
|
|
131
|
-
route.type === "graphql") {
|
|
130
|
+
if (route.type === "function" || route.type === "graphql") {
|
|
132
131
|
return route.function;
|
|
133
132
|
}
|
|
134
133
|
}
|
|
@@ -143,8 +142,7 @@ export class Api extends Construct {
|
|
|
143
142
|
*/
|
|
144
143
|
bind(constructs) {
|
|
145
144
|
for (const route of Object.values(this.routesData)) {
|
|
146
|
-
if (route.type === "function" ||
|
|
147
|
-
route.type === "graphql") {
|
|
145
|
+
if (route.type === "function" || route.type === "graphql") {
|
|
148
146
|
route.function.bind(constructs);
|
|
149
147
|
}
|
|
150
148
|
}
|
|
@@ -183,8 +181,7 @@ export class Api extends Construct {
|
|
|
183
181
|
*/
|
|
184
182
|
attachPermissions(permissions) {
|
|
185
183
|
for (const route of Object.values(this.routesData)) {
|
|
186
|
-
if (route.type === "function" ||
|
|
187
|
-
route.type === "graphql") {
|
|
184
|
+
if (route.type === "function" || route.type === "graphql") {
|
|
188
185
|
route.function.attachPermissions(permissions);
|
|
189
186
|
}
|
|
190
187
|
}
|
|
@@ -665,7 +665,7 @@ export class ApiGatewayV1Api extends Construct {
|
|
|
665
665
|
const [routeProps, lambda] = (() => {
|
|
666
666
|
if (Fn.isInlineDefinition(routeValue)) {
|
|
667
667
|
const routeProps = {
|
|
668
|
-
function: routeValue
|
|
668
|
+
function: routeValue,
|
|
669
669
|
};
|
|
670
670
|
return [
|
|
671
671
|
routeProps,
|
|
@@ -709,7 +709,7 @@ export class ApiGatewayV1Api extends Construct {
|
|
|
709
709
|
const root = scope.node.root;
|
|
710
710
|
if (root.local) {
|
|
711
711
|
lambda.addEnvironment("SST_DEBUG_IS_API_ROUTE", "1", {
|
|
712
|
-
removeInEdge: true
|
|
712
|
+
removeInEdge: true,
|
|
713
713
|
});
|
|
714
714
|
}
|
|
715
715
|
this.functions[routeKey] = lambda;
|
package/constructs/App.js
CHANGED
|
@@ -207,7 +207,6 @@ export class App extends cdk.App {
|
|
|
207
207
|
Auth.injectConfig();
|
|
208
208
|
this.ensureUniqueConstructIds();
|
|
209
209
|
this.codegenTypes();
|
|
210
|
-
this.buildConstructsMetadata();
|
|
211
210
|
this.createBindingSsmParameters();
|
|
212
211
|
this.removeGovCloudUnsupportedResourceProperties();
|
|
213
212
|
for (const child of this.node.children) {
|
|
@@ -231,6 +230,7 @@ export class App extends cdk.App {
|
|
|
231
230
|
}
|
|
232
231
|
async finish() {
|
|
233
232
|
await useDeferredTasks().run();
|
|
233
|
+
this.buildConstructsMetadata();
|
|
234
234
|
}
|
|
235
235
|
isRunningSSTTest() {
|
|
236
236
|
// Check the env var set inside test/setup-tests.js
|
package/constructs/Auth.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as ssm from "aws-cdk-lib/aws-ssm";
|
|
|
2
2
|
import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
3
3
|
import { Construct } from "constructs";
|
|
4
4
|
import { Stack } from "./Stack.js";
|
|
5
|
-
import { ENVIRONMENT_PLACEHOLDER, getEnvironmentKey, getParameterPath } from "./util/functionBinding.js";
|
|
5
|
+
import { ENVIRONMENT_PLACEHOLDER, getEnvironmentKey, getParameterPath, } from "./util/functionBinding.js";
|
|
6
6
|
import { CustomResource } from "aws-cdk-lib";
|
|
7
7
|
const PUBLIC_KEY_PROP = "publicKey";
|
|
8
8
|
const PRIVATE_KEY_PROP = "privateKey";
|
|
@@ -42,15 +42,15 @@ export class Auth extends Construct {
|
|
|
42
42
|
resourceType: "Custom::AuthKeys",
|
|
43
43
|
properties: {
|
|
44
44
|
publicPath: getParameterPath(this, PUBLIC_KEY_PROP),
|
|
45
|
-
privatePath: getParameterPath(this, PRIVATE_KEY_PROP)
|
|
46
|
-
}
|
|
45
|
+
privatePath: getParameterPath(this, PRIVATE_KEY_PROP),
|
|
46
|
+
},
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
/** @internal */
|
|
50
50
|
getConstructMetadata() {
|
|
51
51
|
return {
|
|
52
52
|
type: "Auth",
|
|
53
|
-
data: {}
|
|
53
|
+
data: {},
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
/** @internal */
|
|
@@ -62,14 +62,14 @@ export class Auth extends Construct {
|
|
|
62
62
|
publicKey: {
|
|
63
63
|
environment: ENVIRONMENT_PLACEHOLDER,
|
|
64
64
|
// SSM parameters will be created by the custom resource
|
|
65
|
-
parameter: undefined
|
|
66
|
-
}
|
|
65
|
+
parameter: undefined,
|
|
66
|
+
},
|
|
67
67
|
},
|
|
68
68
|
permissions: {
|
|
69
69
|
"ssm:GetParameters": [
|
|
70
|
-
`arn:${Stack.of(this).partition}:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, PUBLIC_KEY_PROP)}
|
|
71
|
-
]
|
|
72
|
-
}
|
|
70
|
+
`arn:${Stack.of(this).partition}:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, PUBLIC_KEY_PROP)}`,
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
@@ -93,7 +93,7 @@ export class Auth extends Construct {
|
|
|
93
93
|
throw new Error("This Auth construct has already been attached to this Api construct.");
|
|
94
94
|
}
|
|
95
95
|
// Validate: one Api can only have one Auth attached to it
|
|
96
|
-
if (Array.from(Auth.list).some(auth => auth.apis.has(props.api))) {
|
|
96
|
+
if (Array.from(Auth.list).some((auth) => auth.apis.has(props.api))) {
|
|
97
97
|
throw new Error("This Api construct already has an Auth construct attached.");
|
|
98
98
|
}
|
|
99
99
|
const prefix = props.prefix || "/auth";
|
|
@@ -101,8 +101,8 @@ export class Auth extends Construct {
|
|
|
101
101
|
props.api.addRoutes(scope, {
|
|
102
102
|
[path]: {
|
|
103
103
|
type: "function",
|
|
104
|
-
function: this.authenticator
|
|
105
|
-
}
|
|
104
|
+
function: this.authenticator,
|
|
105
|
+
},
|
|
106
106
|
});
|
|
107
107
|
// Auth construct has two types of Function bindinds:
|
|
108
108
|
// - Api routes: bindings defined in `getFunctionBinding()`
|
|
@@ -117,9 +117,9 @@ export class Auth extends Construct {
|
|
|
117
117
|
actions: ["ssm:GetParameters"],
|
|
118
118
|
effect: Effect.ALLOW,
|
|
119
119
|
resources: [
|
|
120
|
-
`arn:${Stack.of(this).partition}:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, "*")}
|
|
121
|
-
]
|
|
122
|
-
})
|
|
120
|
+
`arn:${Stack.of(this).partition}:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, "*")}`,
|
|
121
|
+
],
|
|
122
|
+
}),
|
|
123
123
|
]);
|
|
124
124
|
}
|
|
125
125
|
// Create a parameter for prefix
|
|
@@ -128,7 +128,7 @@ export class Auth extends Construct {
|
|
|
128
128
|
if (this.apis.size === 0) {
|
|
129
129
|
new ssm.StringParameter(this, "prefix", {
|
|
130
130
|
parameterName: getParameterPath(this, PREFIX_PROP),
|
|
131
|
-
stringValue: prefix
|
|
131
|
+
stringValue: prefix,
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
this.apis.add(props.api);
|
package/constructs/Cognito.js
CHANGED
|
@@ -2,9 +2,9 @@ import { Construct } from "constructs";
|
|
|
2
2
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
3
3
|
import * as cognito from "aws-cdk-lib/aws-cognito";
|
|
4
4
|
import { Stack } from "./Stack.js";
|
|
5
|
-
import { getFunctionRef, isCDKConstruct } from "./Construct.js";
|
|
6
|
-
import { Function as Fn } from "./Function.js";
|
|
7
|
-
import { attachPermissionsToRole, attachPermissionsToPolicy } from "./util/permission.js";
|
|
5
|
+
import { getFunctionRef, isCDKConstruct, } from "./Construct.js";
|
|
6
|
+
import { Function as Fn, } from "./Function.js";
|
|
7
|
+
import { attachPermissionsToRole, attachPermissionsToPolicy, } from "./util/permission.js";
|
|
8
8
|
const CognitoUserPoolTriggerOperationMapping = {
|
|
9
9
|
createAuthChallenge: cognito.UserPoolOperation.CREATE_AUTH_CHALLENGE,
|
|
10
10
|
customEmailSender: cognito.UserPoolOperation.CUSTOM_EMAIL_SENDER,
|
|
@@ -17,7 +17,7 @@ const CognitoUserPoolTriggerOperationMapping = {
|
|
|
17
17
|
preSignUp: cognito.UserPoolOperation.PRE_SIGN_UP,
|
|
18
18
|
preTokenGeneration: cognito.UserPoolOperation.PRE_TOKEN_GENERATION,
|
|
19
19
|
userMigration: cognito.UserPoolOperation.USER_MIGRATION,
|
|
20
|
-
verifyAuthChallengeResponse: cognito.UserPoolOperation.VERIFY_AUTH_CHALLENGE_RESPONSE
|
|
20
|
+
verifyAuthChallengeResponse: cognito.UserPoolOperation.VERIFY_AUTH_CHALLENGE_RESPONSE,
|
|
21
21
|
};
|
|
22
22
|
/////////////////////
|
|
23
23
|
// Construct
|
|
@@ -79,7 +79,7 @@ export class Cognito extends Construct {
|
|
|
79
79
|
return this.attachPermissionsForUsers(this.cdk.unauthRole, arg1, arg2);
|
|
80
80
|
}
|
|
81
81
|
bindForTriggers(constructs) {
|
|
82
|
-
Object.values(this.functions).forEach(fn => fn.bind(constructs));
|
|
82
|
+
Object.values(this.functions).forEach((fn) => fn.bind(constructs));
|
|
83
83
|
}
|
|
84
84
|
bindForTrigger(triggerKey, constructs) {
|
|
85
85
|
const fn = this.getFunction(triggerKey);
|
|
@@ -89,7 +89,7 @@ export class Cognito extends Construct {
|
|
|
89
89
|
fn.bind(constructs);
|
|
90
90
|
}
|
|
91
91
|
attachPermissionsForTriggers(permissions) {
|
|
92
|
-
Object.values(this.functions).forEach(fn => fn.attachPermissions(permissions));
|
|
92
|
+
Object.values(this.functions).forEach((fn) => fn.attachPermissions(permissions));
|
|
93
93
|
}
|
|
94
94
|
attachPermissionsForTrigger(triggerKey, permissions) {
|
|
95
95
|
const fn = this.getFunction(triggerKey);
|
|
@@ -109,9 +109,9 @@ export class Cognito extends Construct {
|
|
|
109
109
|
userPoolId: this.cdk.userPool.userPoolId,
|
|
110
110
|
triggers: Object.entries(this.functions).map(([name, fun]) => ({
|
|
111
111
|
name,
|
|
112
|
-
fn: getFunctionRef(fun)
|
|
113
|
-
}))
|
|
114
|
-
}
|
|
112
|
+
fn: getFunctionRef(fun),
|
|
113
|
+
})),
|
|
114
|
+
},
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
/** @internal */
|
|
@@ -169,7 +169,7 @@ export class Cognito extends Construct {
|
|
|
169
169
|
selfSignUpEnabled: true,
|
|
170
170
|
signInCaseSensitive: false,
|
|
171
171
|
signInAliases: this.buildSignInAliases(login),
|
|
172
|
-
...cognitoUserPoolProps
|
|
172
|
+
...cognitoUserPoolProps,
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
}
|
|
@@ -183,7 +183,7 @@ export class Cognito extends Construct {
|
|
|
183
183
|
{});
|
|
184
184
|
this.cdk.userPoolClient = new cognito.UserPoolClient(this, "UserPoolClient", {
|
|
185
185
|
userPool: this.cdk.userPool,
|
|
186
|
-
...clientProps
|
|
186
|
+
...clientProps,
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
189
|
}
|
|
@@ -203,7 +203,7 @@ export class Cognito extends Construct {
|
|
|
203
203
|
const urlSuffix = Stack.of(this).urlSuffix;
|
|
204
204
|
cognitoIdentityProviders.push({
|
|
205
205
|
providerName: `cognito-idp.${app.region}.${urlSuffix}/${this.cdk.userPool.userPoolId}`,
|
|
206
|
-
clientId: this.cdk.userPoolClient.userPoolClientId
|
|
206
|
+
clientId: this.cdk.userPoolClient.userPoolClientId,
|
|
207
207
|
});
|
|
208
208
|
if (typeof identityPoolFederation === "object") {
|
|
209
209
|
const { auth0, amazon, apple, facebook, google, twitter } = identityPoolFederation;
|
|
@@ -221,7 +221,7 @@ export class Cognito extends Construct {
|
|
|
221
221
|
url: auth0.domain.startsWith("https://")
|
|
222
222
|
? auth0.domain
|
|
223
223
|
: `https://${auth0.domain}`,
|
|
224
|
-
clientIds: [auth0.clientId]
|
|
224
|
+
clientIds: [auth0.clientId],
|
|
225
225
|
});
|
|
226
226
|
openIdConnectProviderArns.push(provider.openIdConnectProviderArn);
|
|
227
227
|
}
|
|
@@ -272,7 +272,7 @@ export class Cognito extends Construct {
|
|
|
272
272
|
cognitoIdentityProviders,
|
|
273
273
|
supportedLoginProviders,
|
|
274
274
|
openIdConnectProviderArns,
|
|
275
|
-
...identityPoolProps
|
|
275
|
+
...identityPoolProps,
|
|
276
276
|
});
|
|
277
277
|
this.cdk.authRole = this.createAuthRole(this.cdk.cfnIdentityPool);
|
|
278
278
|
this.cdk.unauthRole = this.createUnauthRole(this.cdk.cfnIdentityPool);
|
|
@@ -281,8 +281,8 @@ export class Cognito extends Construct {
|
|
|
281
281
|
identityPoolId: this.cdk.cfnIdentityPool.ref,
|
|
282
282
|
roles: {
|
|
283
283
|
authenticated: this.cdk.authRole.roleArn,
|
|
284
|
-
unauthenticated: this.cdk.unauthRole.roleArn
|
|
285
|
-
}
|
|
284
|
+
unauthenticated: this.cdk.unauthRole.roleArn,
|
|
285
|
+
},
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
288
|
addTriggers() {
|
|
@@ -315,21 +315,21 @@ export class Cognito extends Construct {
|
|
|
315
315
|
const role = new iam.Role(this, "IdentityPoolAuthRole", {
|
|
316
316
|
assumedBy: new iam.FederatedPrincipal("cognito-identity.amazonaws.com", {
|
|
317
317
|
StringEquals: {
|
|
318
|
-
"cognito-identity.amazonaws.com:aud": identityPool.ref
|
|
318
|
+
"cognito-identity.amazonaws.com:aud": identityPool.ref,
|
|
319
319
|
},
|
|
320
320
|
"ForAnyValue:StringLike": {
|
|
321
|
-
"cognito-identity.amazonaws.com:amr": "authenticated"
|
|
322
|
-
}
|
|
323
|
-
}, "sts:AssumeRoleWithWebIdentity")
|
|
321
|
+
"cognito-identity.amazonaws.com:amr": "authenticated",
|
|
322
|
+
},
|
|
323
|
+
}, "sts:AssumeRoleWithWebIdentity"),
|
|
324
324
|
});
|
|
325
325
|
role.addToPolicy(new iam.PolicyStatement({
|
|
326
326
|
effect: iam.Effect.ALLOW,
|
|
327
327
|
actions: [
|
|
328
328
|
"mobileanalytics:PutEvents",
|
|
329
329
|
"cognito-sync:*",
|
|
330
|
-
"cognito-identity:*"
|
|
330
|
+
"cognito-identity:*",
|
|
331
331
|
],
|
|
332
|
-
resources: ["*"]
|
|
332
|
+
resources: ["*"],
|
|
333
333
|
}));
|
|
334
334
|
return role;
|
|
335
335
|
}
|
|
@@ -337,17 +337,17 @@ export class Cognito extends Construct {
|
|
|
337
337
|
const role = new iam.Role(this, "IdentityPoolUnauthRole", {
|
|
338
338
|
assumedBy: new iam.FederatedPrincipal("cognito-identity.amazonaws.com", {
|
|
339
339
|
StringEquals: {
|
|
340
|
-
"cognito-identity.amazonaws.com:aud": identityPool.ref
|
|
340
|
+
"cognito-identity.amazonaws.com:aud": identityPool.ref,
|
|
341
341
|
},
|
|
342
342
|
"ForAnyValue:StringLike": {
|
|
343
|
-
"cognito-identity.amazonaws.com:amr": "unauthenticated"
|
|
344
|
-
}
|
|
345
|
-
}, "sts:AssumeRoleWithWebIdentity")
|
|
343
|
+
"cognito-identity.amazonaws.com:amr": "unauthenticated",
|
|
344
|
+
},
|
|
345
|
+
}, "sts:AssumeRoleWithWebIdentity"),
|
|
346
346
|
});
|
|
347
347
|
role.addToPolicy(new iam.PolicyStatement({
|
|
348
348
|
effect: iam.Effect.ALLOW,
|
|
349
349
|
actions: ["mobileanalytics:PutEvents", "cognito-sync:*"],
|
|
350
|
-
resources: ["*"]
|
|
350
|
+
resources: ["*"],
|
|
351
351
|
}));
|
|
352
352
|
return role;
|
|
353
353
|
}
|
|
@@ -359,7 +359,7 @@ export class Cognito extends Construct {
|
|
|
359
359
|
email: login.includes("email"),
|
|
360
360
|
phone: login.includes("phone"),
|
|
361
361
|
username: login.includes("username"),
|
|
362
|
-
preferredUsername: login.includes("preferredUsername")
|
|
362
|
+
preferredUsername: login.includes("preferredUsername"),
|
|
363
363
|
};
|
|
364
364
|
}
|
|
365
365
|
}
|
|
@@ -7,7 +7,7 @@ import * as iam from "aws-cdk-lib/aws-iam";
|
|
|
7
7
|
import * as lambda from "aws-cdk-lib/aws-lambda";
|
|
8
8
|
import * as s3Assets from "aws-cdk-lib/aws-s3-assets";
|
|
9
9
|
import { AwsCliLayer } from "aws-cdk-lib/lambda-layer-awscli";
|
|
10
|
-
import { Lazy, Duration, CustomResource
|
|
10
|
+
import { Lazy, Duration, CustomResource } from "aws-cdk-lib";
|
|
11
11
|
import { Stack } from "./Stack.js";
|
|
12
12
|
import { attachPermissionsToRole } from "./util/permission.js";
|
|
13
13
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
@@ -171,7 +171,9 @@ ${exports}
|
|
|
171
171
|
provider.role?.addToPrincipalPolicy(new iam.PolicyStatement({
|
|
172
172
|
effect: iam.Effect.ALLOW,
|
|
173
173
|
actions: ["s3:*"],
|
|
174
|
-
resources: [
|
|
174
|
+
resources: [
|
|
175
|
+
`arn:${stack.partition}:s3:::${asset.s3BucketName}/${asset.s3ObjectKey}`,
|
|
176
|
+
],
|
|
175
177
|
}));
|
|
176
178
|
// Create custom resource to replace the code
|
|
177
179
|
const resource = new CustomResource(this.scope, resId, {
|
|
@@ -182,11 +184,13 @@ ${exports}
|
|
|
182
184
|
BucketName: asset.s3BucketName,
|
|
183
185
|
ObjectKey: asset.s3ObjectKey,
|
|
184
186
|
},
|
|
185
|
-
ReplaceValues: [
|
|
187
|
+
ReplaceValues: [
|
|
188
|
+
{
|
|
186
189
|
files: `index-wrapper.${format === "esm" ? "mjs" : "cjs"}`,
|
|
187
190
|
search: '"{{ _SST_EDGE_FUNCTION_ENVIRONMENT_ }}"',
|
|
188
191
|
replace: JSON.stringify(this.props.environment || {}),
|
|
189
|
-
}
|
|
192
|
+
},
|
|
193
|
+
],
|
|
190
194
|
},
|
|
191
195
|
});
|
|
192
196
|
return resource;
|