sst 2.1.16 → 2.1.18

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 (53) hide show
  1. package/bootstrap.js +1 -1
  2. package/cli/commands/bind.js +1 -1
  3. package/cli/commands/env.js +1 -1
  4. package/constructs/App.js +3 -3
  5. package/constructs/AstroSite.js +8 -41
  6. package/constructs/EdgeFunction.d.ts +19 -21
  7. package/constructs/EdgeFunction.js +235 -167
  8. package/constructs/Function.d.ts +1 -1
  9. package/constructs/Function.js +3 -3
  10. package/constructs/Job.js +2 -2
  11. package/constructs/NextjsSite.d.ts +6 -5
  12. package/constructs/NextjsSite.js +5 -3
  13. package/constructs/RDS.js +1 -1
  14. package/constructs/RemixSite.d.ts +2 -3
  15. package/constructs/RemixSite.js +42 -71
  16. package/constructs/SolidStartSite.js +8 -41
  17. package/constructs/SsrFunction.d.ts +9 -6
  18. package/constructs/SsrFunction.js +61 -50
  19. package/constructs/SsrSite.d.ts +6 -4
  20. package/constructs/SsrSite.js +0 -4
  21. package/constructs/Stack.js +2 -1
  22. package/constructs/future/Auth.d.ts +79 -0
  23. package/constructs/future/Auth.js +116 -0
  24. package/constructs/future/index.d.ts +1 -0
  25. package/constructs/future/index.js +1 -0
  26. package/context/handler.d.ts +1 -1
  27. package/node/api/index.d.ts +27 -4
  28. package/node/api/index.js +64 -2
  29. package/node/auth/index.d.ts +3 -0
  30. package/node/auth/index.js +3 -0
  31. package/node/future/auth/adapter/adapter.d.ts +10 -0
  32. package/node/future/auth/adapter/adapter.js +1 -0
  33. package/node/future/auth/adapter/github.d.ts +16 -0
  34. package/node/future/auth/adapter/github.js +22 -0
  35. package/node/future/auth/adapter/google.d.ts +20 -0
  36. package/node/future/auth/adapter/google.js +10 -0
  37. package/node/future/auth/adapter/link.d.ts +11 -0
  38. package/node/future/auth/adapter/link.js +48 -0
  39. package/node/future/auth/adapter/oauth.d.ts +34 -0
  40. package/node/future/auth/adapter/oauth.js +66 -0
  41. package/node/future/auth/adapter/oidc.d.ts +26 -0
  42. package/node/future/auth/adapter/oidc.js +62 -0
  43. package/node/future/auth/handler.d.ts +18 -0
  44. package/node/future/auth/handler.js +189 -0
  45. package/node/future/auth/index.d.ts +10 -0
  46. package/node/future/auth/index.js +10 -0
  47. package/node/future/auth/session.d.ts +46 -0
  48. package/node/future/auth/session.js +99 -0
  49. package/node/util/index.js +1 -1
  50. package/package.json +4 -1
  51. package/runtime/handlers/node.js +1 -1
  52. package/sst.mjs +4 -4
  53. package/support/nodejs-runtime/index.mjs +62 -14629
@@ -1,18 +1,12 @@
1
1
  import fs from "fs";
2
2
  import url from "url";
3
3
  import path from "path";
4
- import * as esbuild from "esbuild";
5
4
  import { createRequire } from "module";
6
5
  const require = createRequire(import.meta.url);
7
- import { Duration as CdkDuration, RemovalPolicy } from "aws-cdk-lib";
8
- import * as logs from "aws-cdk-lib/aws-logs";
9
- import * as lambda from "aws-cdk-lib/aws-lambda";
10
- import { Logger } from "../logger.js";
6
+ import { Architecture } from "aws-cdk-lib/aws-lambda";
11
7
  import { SsrSite } from "./SsrSite.js";
12
- import { useProject } from "../project.js";
8
+ import { Function } from "./Function.js";
13
9
  import { EdgeFunction } from "./EdgeFunction.js";
14
- import { toCdkSize } from "./util/size.js";
15
- import { toCdkDuration } from "./util/duration.js";
16
10
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
17
11
  /**
18
12
  * The `RemixSite` construct is a higher level CDK construct that makes it easy to create a Remix app.
@@ -60,7 +54,7 @@ export class RemixSite extends SsrSite {
60
54
  clientBuildVersionedSubDir: "build",
61
55
  };
62
56
  }
63
- createServerLambdaBundle(wrapperFile, external) {
57
+ createServerLambdaBundle(wrapperFile) {
64
58
  // Create a Lambda@Edge handler for the Remix server bundle.
65
59
  //
66
60
  // Note: Remix does perform their own internal ESBuild process, but it
@@ -77,84 +71,61 @@ export class RemixSite extends SsrSite {
77
71
  // appropriate Lambda@Edge handler. We will utilise an internal asset
78
72
  // template to create this wrapper within the "core server build" output
79
73
  // directory.
80
- Logger.debug(`Creating Lambda@Edge handler for server`);
81
- // Resolve the path to create the server lambda handler at.
82
- const serverPath = path.join(this.props.path, "build/server.js");
83
- // Write the server lambda
84
- const templatePath = path.resolve(__dirname, `../support/remix-site-function/${wrapperFile}`);
85
- fs.copyFileSync(templatePath, serverPath);
86
- Logger.debug(`Bundling server`);
87
- // Create a directory that we will use to create the bundled version
88
- // of the "core server build" along with our custom Lamba server handler.
89
- const outputPath = path.resolve(path.join(useProject().paths.artifacts, `RemixSiteFunction-${this.node.id}-${this.node.addr}`));
74
+ // Copy the server lambda handler
75
+ const handler = path.join(this.props.path, "build", "server.js");
76
+ fs.copyFileSync(path.resolve(__dirname, `../support/remix-site-function/${wrapperFile}`), handler);
90
77
  // Copy the Remix polyfil to the server build directory
91
- const polyfillSource = path.resolve(__dirname, "../support/remix-site-function/polyfill.js");
78
+ //
79
+ // Note: We need to ensure that the polyfills are injected above other code that
80
+ // will depend on them. Importing them within the top of the lambda code
81
+ // doesn't appear to guarantee this, we therefore leverage ESBUild's
82
+ // `inject` option to ensure that the polyfills are injected at the top of
83
+ // the bundle.
92
84
  const polyfillDest = path.join(this.props.path, "build/polyfill.js");
93
- fs.copyFileSync(polyfillSource, polyfillDest);
94
- const result = esbuild.buildSync({
95
- entryPoints: [serverPath],
96
- bundle: true,
97
- target: "node16",
98
- platform: "node",
99
- external,
100
- outfile: path.join(outputPath, "server.js"),
101
- // We need to ensure that the polyfills are injected above other code that
102
- // will depend on them. Importing them within the top of the lambda code
103
- // doesn't appear to guarantee this, we therefore leverage ESBUild's
104
- // `inject` option to ensure that the polyfills are injected at the top of
105
- // the bundle.
106
- inject: [polyfillDest],
107
- });
108
- if (result.errors.length > 0) {
109
- result.errors.forEach((error) => console.error(error));
110
- throw new Error(`There was a problem bundling the server.`);
111
- }
112
- return outputPath;
85
+ fs.copyFileSync(path.resolve(__dirname, "../support/remix-site-function/polyfill.js"), polyfillDest);
86
+ return {
87
+ handler: path.join(this.props.path, "build", "server.handler"),
88
+ esbuild: { inject: [polyfillDest] },
89
+ };
113
90
  }
114
91
  createFunctionForRegional() {
115
- const { runtime: runtimeRaw, timeout, memorySize, environment, cdk, } = this.props;
116
- const runtime = this.normalizeRuntime(runtimeRaw);
117
- const bundlePath = this.createServerLambdaBundle("regional-server.js", runtime === "nodejs18.x" ? [] : ["aws-sdk"]);
118
- return new lambda.Function(this, `ServerFunction`, {
119
- description: "Server handler for Remix",
120
- handler: "server.handler",
121
- currentVersionOptions: {
122
- removalPolicy: RemovalPolicy.DESTROY,
92
+ const { runtime, timeout, memorySize, permissions, environment, bind, cdk, } = this.props;
93
+ const { handler, esbuild } = this.createServerLambdaBundle("regional-server.js");
94
+ const fn = new Function(this, `ServerFunction`, {
95
+ description: "Server handler",
96
+ handler,
97
+ logRetention: "three_days",
98
+ runtime,
99
+ memorySize,
100
+ timeout,
101
+ nodejs: {
102
+ format: "cjs",
103
+ install: ["sharp"],
104
+ esbuild,
123
105
  },
124
- logRetention: logs.RetentionDays.THREE_DAYS,
125
- code: lambda.Code.fromAsset(bundlePath),
126
- runtime: runtime === "nodejs14.x"
127
- ? lambda.Runtime.NODEJS_14_X
128
- : runtime === "nodejs16.x"
129
- ? lambda.Runtime.NODEJS_16_X
130
- : lambda.Runtime.NODEJS_18_X,
131
- memorySize: typeof memorySize === "string"
132
- ? toCdkSize(memorySize).toMebibytes()
133
- : memorySize,
134
- timeout: typeof timeout === "string"
135
- ? toCdkDuration(timeout)
136
- : CdkDuration.seconds(timeout),
106
+ bind,
137
107
  environment,
108
+ permissions,
138
109
  ...cdk?.server,
110
+ architecture: cdk?.server?.architecture === Architecture.ARM_64 ? "arm_64" : "x86_64",
139
111
  });
112
+ fn._doNotAllowOthersToBind = true;
113
+ return fn;
140
114
  }
141
115
  createFunctionForEdge() {
142
- const { runtime: runtimeRaw, timeout, memorySize, permissions, environment, } = this.props;
143
- const runtime = this.normalizeRuntime(runtimeRaw);
144
- const bundlePath = this.createServerLambdaBundle("edge-server.js", runtime === "nodejs18.x" ? [] : ["aws-sdk"]);
116
+ const { runtime, timeout, memorySize, bind, permissions, environment } = this.props;
117
+ const { handler, esbuild } = this.createServerLambdaBundle("edge-server.js");
145
118
  return new EdgeFunction(this, `Server`, {
146
119
  scopeOverride: this,
147
- format: "cjs",
148
- bundlePath,
149
- handler: "server.handler",
120
+ handler,
150
121
  runtime,
151
122
  timeout,
152
123
  memorySize,
153
- permissions,
124
+ bind,
154
125
  environment,
126
+ permissions,
127
+ format: "cjs",
128
+ esbuild,
155
129
  });
156
130
  }
157
- normalizeRuntime(runtime) {
158
- return runtime || "nodejs18.x";
159
- }
160
131
  }
@@ -1,10 +1,7 @@
1
- import fs from "fs";
2
1
  import path from "path";
3
- import { buildSync } from "esbuild";
4
2
  import { Architecture } from "aws-cdk-lib/aws-lambda";
5
3
  import { SsrSite } from "./SsrSite.js";
6
4
  import { Function } from "./Function.js";
7
- import { useProject } from "../project.js";
8
5
  import { EdgeFunction } from "./EdgeFunction.js";
9
6
  /**
10
7
  * The `SolidStartSite` construct is a higher level CDK construct that makes it easy to create a SolidStart app.
@@ -26,13 +23,11 @@ export class SolidStartSite extends SsrSite {
26
23
  };
27
24
  }
28
25
  createFunctionForRegional() {
29
- const { runtime, timeout, memorySize, environment, cdk } = this.props;
30
- // Bundle code
31
- const handler = path.join(this.props.path, "dist", "server", "index.handler");
26
+ const { runtime, timeout, memorySize, bind, permissions, environment, cdk, } = this.props;
32
27
  // Create function
33
28
  const fn = new Function(this, `ServerFunction`, {
34
29
  description: "Server handler",
35
- handler,
30
+ handler: path.join(this.props.path, "dist", "server", "index.handler"),
36
31
  logRetention: "three_days",
37
32
  runtime,
38
33
  memorySize,
@@ -40,52 +35,24 @@ export class SolidStartSite extends SsrSite {
40
35
  nodejs: {
41
36
  format: "esm",
42
37
  },
38
+ bind,
43
39
  environment,
40
+ permissions,
44
41
  ...cdk?.server,
45
42
  architecture: cdk?.server?.architecture === Architecture.ARM_64 ? "arm_64" : "x86_64",
46
43
  });
47
- fn._disableBind = true;
44
+ fn._doNotAllowOthersToBind = true;
48
45
  return fn;
49
46
  }
50
47
  createFunctionForEdge() {
51
- const { runtime, timeout, memorySize, permissions, environment } = this.props;
52
- // Create a directory that we will use to create the bundled version
53
- // of the "core server build" along with our custom Lamba server handler.
54
- const outputPath = path.resolve(path.join(useProject().paths.artifacts, `SolidStartSiteFunction-${this.node.id}-${this.node.addr}`));
55
- // Bundle code
56
- const result = buildSync({
57
- entryPoints: [
58
- path.join(this.props.path, this.buildConfig.serverBuildOutputFile),
59
- ],
60
- target: "esnext",
61
- format: "esm",
62
- platform: "node",
63
- metafile: true,
64
- bundle: true,
65
- write: true,
66
- allowOverwrite: true,
67
- outfile: path.join(outputPath, "server.mjs"),
68
- banner: {
69
- js: [
70
- `import { createRequire as topLevelCreateRequire } from 'module';`,
71
- `const require = topLevelCreateRequire(import.meta.url);`,
72
- ].join(""),
73
- },
74
- });
75
- if (result.errors.length > 0) {
76
- result.errors.forEach((error) => console.error(error));
77
- throw new Error(`There was a problem bundling the function code for the ${this.id} SolidStartSite.`);
78
- }
79
- // Create package.json
80
- fs.writeFileSync(path.join(outputPath, "package.json"), `{"type":"module"}`);
81
- // Create function
48
+ const { runtime, timeout, memorySize, bind, permissions, environment } = this.props;
82
49
  return new EdgeFunction(this, `Server`, {
83
50
  scopeOverride: this,
84
- bundlePath: outputPath,
85
- handler: "server.handler",
51
+ handler: path.join(this.props.path, "dist", "server", "index.handler"),
86
52
  runtime,
87
53
  timeout,
88
54
  memorySize,
55
+ bind,
89
56
  permissions,
90
57
  environment,
91
58
  format: "esm",
@@ -1,23 +1,26 @@
1
1
  import { Construct } from "constructs";
2
- import * as lambda from "aws-cdk-lib/aws-lambda";
2
+ import { FunctionOptions, Function as CdkFunction } from "aws-cdk-lib/aws-lambda";
3
+ import { SSTConstruct } from "./Construct.js";
3
4
  import { Permissions } from "./util/permission.js";
4
5
  import { Size } from "./util/size.js";
5
6
  import { Duration } from "./util/duration.js";
6
- import { FunctionOptions } from "aws-cdk-lib/aws-lambda";
7
7
  export interface SsrFunctionProps extends Omit<FunctionOptions, "memorySize" | "timeout" | "runtime"> {
8
- bundlePath: string;
8
+ bundle: string;
9
9
  handler: string;
10
10
  runtime?: "nodejs14.x" | "nodejs16.x" | "nodejs18.x";
11
11
  timeout: number | Duration;
12
12
  memorySize: number | Size;
13
13
  permissions?: Permissions;
14
+ environment?: Record<string, string>;
15
+ bind?: SSTConstruct[];
14
16
  }
15
17
  export declare class SsrFunction extends Construct {
16
- function: lambda.Function;
18
+ function: CdkFunction;
17
19
  private props;
18
20
  constructor(scope: Construct, id: string, props: SsrFunctionProps);
19
21
  attachPermissions(permissions: Permissions): void;
22
+ private createCodeAsset;
20
23
  private createFunction;
21
- private createLambdaCodeReplacer;
22
- private getLambdaContentReplaceValues;
24
+ private createCodeReplacer;
25
+ private bind;
23
26
  }
@@ -3,12 +3,13 @@ import path from "path";
3
3
  import spawn from "cross-spawn";
4
4
  import { Construct } from "constructs";
5
5
  import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
6
- import * as logs from "aws-cdk-lib/aws-logs";
7
- import * as lambda from "aws-cdk-lib/aws-lambda";
8
- import * as s3Assets from "aws-cdk-lib/aws-s3-assets";
6
+ import { RetentionDays } from "aws-cdk-lib/aws-logs";
7
+ import { Architecture, Runtime, Code, Function as CdkFunction, } from "aws-cdk-lib/aws-lambda";
8
+ import { Asset } from "aws-cdk-lib/aws-s3-assets";
9
9
  import { Duration as CdkDuration, CustomResource } from "aws-cdk-lib";
10
- import { Stack } from "./Stack.js";
11
10
  import { useProject } from "../project.js";
11
+ import { Stack } from "./Stack.js";
12
+ import { bindEnvironment, bindPermissions, getReferencedSecrets, } from "./util/functionBinding.js";
12
13
  import { attachPermissionsToRole } from "./util/permission.js";
13
14
  import { toCdkSize } from "./util/size.js";
14
15
  import { toCdkDuration } from "./util/duration.js";
@@ -21,48 +22,52 @@ export class SsrFunction extends Construct {
21
22
  props;
22
23
  constructor(scope, id, props) {
23
24
  super(scope, id);
24
- this.props = props;
25
- const { permissions } = props;
26
- this.function = this.createFunction();
27
- this.attachPermissions(permissions || []);
25
+ this.props = {
26
+ ...props,
27
+ environment: props.environment || {},
28
+ permissions: props.permissions || [],
29
+ };
30
+ const asset = this.createCodeAsset();
31
+ const assetReplacer = this.createCodeReplacer(asset);
32
+ this.function = this.createFunction(asset);
33
+ this.attachPermissions(props.permissions || []);
34
+ this.bind(props.bind || []);
35
+ this.function.node.addDependency(assetReplacer);
28
36
  }
29
37
  attachPermissions(permissions) {
30
38
  attachPermissionsToRole(this.function.role, permissions);
31
39
  }
32
- createFunction() {
33
- const { runtime, timeout, memorySize, handler, bundlePath } = this.props;
34
- // Note: cannot point the bundlePath to the `.open-next/server-function`
40
+ createCodeAsset() {
41
+ const { bundle } = this.props;
42
+ // Note: cannot point the bundle to the `.open-next/server-function`
35
43
  // b/c the folder contains node_modules. And pnpm node_modules
36
44
  // contains symlinks. CDK cannot zip symlinks correctly.
37
45
  // https://github.com/aws/aws-cdk/issues/9251
38
46
  // We will zip the folder ourselves.
39
- const zipOutDir = path.resolve(useProject().paths.artifacts, `Site-${this.node.id}-${this.node.addr}`);
47
+ const outputPath = path.resolve(useProject().paths.artifacts, `SsrFunction-${this.node.id}-${this.node.addr}`);
40
48
  const script = path.resolve(__dirname, "../support/ssr-site-function-archiver.mjs");
41
- const result = spawn.sync("node", [
42
- script,
43
- path.join(bundlePath),
44
- path.join(zipOutDir, "server-function.zip"),
45
- ], { stdio: "inherit" });
49
+ const result = spawn.sync("node", [script, path.join(bundle), path.join(outputPath, "server-function.zip")], { stdio: "inherit" });
46
50
  if (result.status !== 0) {
47
51
  throw new Error(`There was a problem generating the assets package.`);
48
52
  }
49
53
  // Create asset
50
- const asset = new s3Assets.Asset(this, "Asset", {
51
- path: path.join(zipOutDir, "server-function.zip"),
54
+ return new Asset(this, "Asset", {
55
+ path: path.join(outputPath, "server-function.zip"),
52
56
  });
53
- // Deploy after the code is updated
54
- const replacer = this.createLambdaCodeReplacer(asset);
55
- const fn = new lambda.Function(this, `ServerFunction`, {
57
+ }
58
+ createFunction(asset) {
59
+ const { runtime, timeout, memorySize, handler } = this.props;
60
+ return new CdkFunction(this, `ServerFunction`, {
56
61
  ...this.props,
57
62
  handler,
58
- logRetention: logs.RetentionDays.THREE_DAYS,
59
- code: lambda.Code.fromBucket(asset.bucket, asset.s3ObjectKey),
63
+ logRetention: RetentionDays.THREE_DAYS,
64
+ code: Code.fromBucket(asset.bucket, asset.s3ObjectKey),
60
65
  runtime: runtime === "nodejs14.x"
61
- ? lambda.Runtime.NODEJS_14_X
66
+ ? Runtime.NODEJS_14_X
62
67
  : runtime === "nodejs16.x"
63
- ? lambda.Runtime.NODEJS_16_X
64
- : lambda.Runtime.NODEJS_18_X,
65
- architecture: lambda.Architecture.ARM_64,
68
+ ? Runtime.NODEJS_16_X
69
+ : Runtime.NODEJS_18_X,
70
+ architecture: Architecture.ARM_64,
66
71
  memorySize: typeof memorySize === "string"
67
72
  ? toCdkSize(memorySize).toMebibytes()
68
73
  : memorySize,
@@ -70,10 +75,9 @@ export class SsrFunction extends Construct {
70
75
  ? toCdkDuration(timeout)
71
76
  : CdkDuration.seconds(timeout),
72
77
  });
73
- fn.node.addDependency(replacer);
74
- return fn;
75
78
  }
76
- createLambdaCodeReplacer(asset) {
79
+ createCodeReplacer(asset) {
80
+ const { environment } = this.props;
77
81
  // Note: Source code for the Lambda functions have "{{ ENV_KEY }}" in them.
78
82
  // They need to be replaced with real values before the Lambda
79
83
  // functions get deployed.
@@ -94,30 +98,37 @@ export class SsrFunction extends Construct {
94
98
  properties: {
95
99
  bucket: asset.s3BucketName,
96
100
  key: asset.s3ObjectKey,
97
- replacements: this.getLambdaContentReplaceValues(),
101
+ replacements: Object.entries(environment).map(([key, value]) => ({
102
+ files: "**/*.*js",
103
+ search: `{{ ${key} }}`,
104
+ replace: value,
105
+ })),
98
106
  },
99
107
  });
100
108
  resource.node.addDependency(policy);
101
109
  return resource;
102
110
  }
103
- getLambdaContentReplaceValues() {
104
- const replaceValues = [];
105
- Object.entries(this.props.environment || {}).forEach(([key, value]) => {
106
- const token = `{{ ${key} }}`;
107
- replaceValues.push({
108
- files: "**/*.js",
109
- search: token,
110
- replace: value,
111
- }, {
112
- files: "**/*.cjs",
113
- search: token,
114
- replace: value,
115
- }, {
116
- files: "**/*.mjs",
117
- search: token,
118
- replace: value,
119
- });
111
+ bind(constructs) {
112
+ const app = this.node.root;
113
+ this.function.addEnvironment("SST_APP", app.name);
114
+ this.function.addEnvironment("SST_STAGE", app.stage);
115
+ this.function.addEnvironment("SST_SSM_PREFIX", useProject().config.ssmPrefix);
116
+ // Get referenced secrets
117
+ const referencedSecrets = [];
118
+ constructs.forEach((c) => referencedSecrets.push(...getReferencedSecrets(c)));
119
+ [...constructs, ...referencedSecrets].forEach((c) => {
120
+ // Bind environment
121
+ const env = bindEnvironment(c);
122
+ Object.entries(env).forEach(([key, value]) => this.function.addEnvironment(key, value));
123
+ // Bind permissions
124
+ const permissions = bindPermissions(c);
125
+ Object.entries(permissions).forEach(([action, resources]) => this.attachPermissions([
126
+ new PolicyStatement({
127
+ actions: [action],
128
+ effect: Effect.ALLOW,
129
+ resources,
130
+ }),
131
+ ]));
120
132
  });
121
- return replaceValues;
122
133
  }
123
134
  }
@@ -179,10 +179,12 @@ export interface SsrSiteProps {
179
179
  */
180
180
  export declare class SsrSite extends Construct implements SSTConstruct {
181
181
  readonly id: string;
182
- protected props: Omit<SsrSiteProps, "path"> & {
183
- path: string;
184
- timeout: number | Duration;
185
- memorySize: number | Size;
182
+ protected props: SsrSiteProps & {
183
+ path: Exclude<SsrSiteProps["path"], undefined>;
184
+ runtime: Exclude<SsrSiteProps["runtime"], undefined>;
185
+ timeout: Exclude<SsrSiteProps["timeout"], undefined>;
186
+ memorySize: Exclude<SsrSiteProps["memorySize"], undefined>;
187
+ waitForInvalidation: Exclude<SsrSiteProps["waitForInvalidation"], undefined>;
186
188
  };
187
189
  private doNotDeploy;
188
190
  protected buildConfig: SsrBuildConfig;
@@ -398,11 +398,7 @@ export class SsrSite extends Construct {
398
398
  return {};
399
399
  }
400
400
  createFunctionPermissionsForRegional() {
401
- const { permissions } = this.props;
402
401
  this.bucket.grantReadWrite(this.serverLambdaForRegional.role);
403
- if (permissions) {
404
- attachPermissionsToRole(this.serverLambdaForRegional.role, permissions);
405
- }
406
402
  }
407
403
  createFunctionPermissionsForEdge() {
408
404
  this.bucket.grantReadWrite(this.serverLambdaForEdge.role);
@@ -175,7 +175,8 @@ export class Stack extends cdk.Stack {
175
175
  const output = typeof value === "string"
176
176
  ? new cdk.CfnOutput(this, `SSTStackOutput${key}`, { value })
177
177
  : new cdk.CfnOutput(this, `SSTStackOutput${key}`, value);
178
- output.overrideLogicalId(key);
178
+ // CloudFormation only allows alphanumeric characters in the output name.
179
+ output.overrideLogicalId(key.replace(/[^A-Za-z0-9]/g, ""));
179
180
  });
180
181
  }
181
182
  createCustomResourceHandler() {
@@ -0,0 +1,79 @@
1
+ import { Construct } from "constructs";
2
+ import { Api, ApiProps } from "../Api.js";
3
+ import { FunctionDefinition } from "../Function.js";
4
+ import { SSTConstruct } from "../Construct.js";
5
+ import { FunctionBindingProps } from "../util/functionBinding.js";
6
+ export interface AuthProps {
7
+ /**
8
+ * The function that will handle authentication
9
+ */
10
+ authenticator: FunctionDefinition;
11
+ customDomain?: ApiProps["customDomain"];
12
+ cdk?: {
13
+ /**
14
+ * Allows you to override default id for this construct.
15
+ */
16
+ id?: string;
17
+ };
18
+ }
19
+ export interface ApiAttachmentProps {
20
+ /**
21
+ * The API to attach auth routes to
22
+ *
23
+ * @example
24
+ * ```js
25
+ * const api = new Api(stack, "Api", {});
26
+ * const auth = new Auth(stack, "Auth", {
27
+ * authenticator: "functions/authenticator.handler"
28
+ * })
29
+ * auth.attach(stack, {
30
+ * api
31
+ * })
32
+ * ```
33
+ */
34
+ api: Api;
35
+ /**
36
+ * Optionally specify the prefix to mount authentication routes
37
+ *
38
+ * @default "/auth"
39
+ *
40
+ * @example
41
+ * ```js
42
+ * const api = new Api(stack, "Api", {});
43
+ * const auth = new Auth(stack, "Auth", {
44
+ * authenticator: "functions/authenticator.handler"
45
+ * })
46
+ * auth.attach(stack, {
47
+ * api,
48
+ * prefix: "/custom/prefix"
49
+ * })
50
+ * ```
51
+ */
52
+ prefix?: string;
53
+ }
54
+ /**
55
+ * SST Auth is a lightweight authentication solution for your applications. With a simple set of configuration you can deploy a function attached to your API that can handle various authentication flows. *
56
+ * @example
57
+ * ```
58
+ * import { Auth } from "@serverless-stack/resources"
59
+ *
60
+ * new Auth(stack, "auth", {
61
+ * authenticator: "functions/authenticator.handler"
62
+ * })
63
+ */
64
+ export declare class Auth extends Construct implements SSTConstruct {
65
+ readonly id: string;
66
+ private readonly authenticator;
67
+ private api;
68
+ private publicKey;
69
+ private privateKey;
70
+ constructor(scope: Construct, id: string, props: AuthProps);
71
+ get url(): string;
72
+ /** @internal */
73
+ getConstructMetadata(): {
74
+ type: "Auth";
75
+ data: {};
76
+ };
77
+ /** @internal */
78
+ getFunctionBinding(): FunctionBindingProps;
79
+ }