sst 2.24.12 → 2.24.14

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.
@@ -145,7 +145,7 @@ export interface ApiGatewayV1ApiProps<Authorizers extends Record<string, ApiGate
145
145
  * });
146
146
  * ```
147
147
  */
148
- authorizer?: "none" | "iam" | (string extends AuthorizerKeys ? never : AuthorizerKeys);
148
+ authorizer?: "none" | "iam" | (string extends AuthorizerKeys ? Omit<AuthorizerKeys, "none" | "iam"> : AuthorizerKeys);
149
149
  /**
150
150
  * An array of scopes to include in the authorization when using `user_pool` or `jwt` authorizers. These will be merged with the scopes from the attached authorizer.
151
151
  * @default []
@@ -220,7 +220,7 @@ export type ApiGatewayV1ApiRouteProps<AuthorizerKeys> = FunctionInlineDefinition
220
220
  */
221
221
  export interface ApiGatewayV1ApiFunctionRouteProps<AuthorizerKeys = never> {
222
222
  function?: FunctionDefinition;
223
- authorizer?: "none" | "iam" | (string extends AuthorizerKeys ? never : AuthorizerKeys);
223
+ authorizer?: "none" | "iam" | (string extends AuthorizerKeys ? Omit<AuthorizerKeys, "none" | "iam"> : AuthorizerKeys);
224
224
  authorizationScopes?: string[];
225
225
  cdk?: {
226
226
  method?: Omit<apig.MethodOptions, "authorizer" | "authorizationType" | "authorizationScopes">;
@@ -735,7 +735,8 @@ export class ApiGatewayV1Api extends Construct {
735
735
  ...routeProps.cdk?.method,
736
736
  };
737
737
  }
738
- if (!this.props.authorizers || !this.props.authorizers[authorizerKey]) {
738
+ if (!this.props.authorizers ||
739
+ !this.props.authorizers[authorizerKey]) {
739
740
  throw new Error(`Cannot find authorizer "${authorizerKey.toString()}"`);
740
741
  }
741
742
  const authorizer = this.authorizersData[authorizerKey];
package/constructs/App.js CHANGED
@@ -2,19 +2,20 @@ import path from "path";
2
2
  import fs from "fs";
3
3
  import { Stack } from "./Stack.js";
4
4
  import { isSSTConstruct, isStackConstruct, } from "./Construct.js";
5
+ import { useFunctions } from "./Function.js";
5
6
  import { bindParameters, bindType } from "./util/functionBinding.js";
6
7
  import { stack } from "./FunctionalStack.js";
7
- import { createRequire } from "module";
8
8
  import { Auth } from "./Auth.js";
9
9
  import { useDeferredTasks } from "./deferred_task.js";
10
10
  import { AppContext } from "./context.js";
11
11
  import { useProject } from "../project.js";
12
12
  import { Logger } from "../logger.js";
13
- import { App as CDKApp, Tags, CfnResource, RemovalPolicy, Aspects, } from "aws-cdk-lib/core";
13
+ import { App as CDKApp, Tags, CfnResource, RemovalPolicy, CustomResource, Aspects, } from "aws-cdk-lib/core";
14
14
  import { CfnFunction } from "aws-cdk-lib/aws-lambda";
15
15
  import { Bucket } from "aws-cdk-lib/aws-s3";
16
+ import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
16
17
  import { CfnLogGroup } from "aws-cdk-lib/aws-logs";
17
- const require = createRequire(import.meta.url);
18
+ import { useBootstrap } from "../bootstrap.js";
18
19
  function exitWithMessage(message) {
19
20
  console.error(message);
20
21
  process.exit(1);
@@ -177,6 +178,7 @@ export class App extends CDKApp {
177
178
  if (this.isFinished)
178
179
  return;
179
180
  this.isFinished = true;
181
+ const { config, paths } = useProject();
180
182
  Auth.injectConfig();
181
183
  this.buildConstructsMetadata();
182
184
  this.ensureUniqueConstructIds();
@@ -189,12 +191,43 @@ export class App extends CDKApp {
189
191
  await useDeferredTasks().run();
190
192
  this.createBindingSsmParameters();
191
193
  this.removeGovCloudUnsupportedResourceProperties();
192
- const { config } = useProject();
194
+ const bootstrap = await useBootstrap();
193
195
  for (const child of this.node.children) {
194
196
  if (isStackConstruct(child)) {
195
197
  // Tag stacks
196
198
  Tags.of(child).add("sst:app", this.name);
197
199
  Tags.of(child).add("sst:stage", this.stage);
200
+ if (child instanceof Stack) {
201
+ const functions = useFunctions();
202
+ const sourcemaps = functions.sourcemaps.forStack(child.stackName);
203
+ if (sourcemaps.length) {
204
+ const policy = new Policy(child, "FunctionSourcemapUploaderPolicy", {
205
+ statements: [
206
+ new PolicyStatement({
207
+ effect: Effect.ALLOW,
208
+ actions: ["s3:GetObject", "s3:PutObject"],
209
+ resources: [
210
+ sourcemaps[0].bucket.bucketArn + "/*",
211
+ `arn:${child.partition}:s3:::${bootstrap.bucket}/*`,
212
+ ],
213
+ }),
214
+ ],
215
+ });
216
+ child.customResourceHandler.role?.attachInlinePolicy(policy);
217
+ const resource = new CustomResource(child, "FunctionSourcemapUploader", {
218
+ serviceToken: child.customResourceHandler.functionArn,
219
+ resourceType: "Custom::FunctionSourcemapUploader",
220
+ properties: {
221
+ app: this.name,
222
+ stage: this.stage,
223
+ bootstrap: bootstrap.bucket,
224
+ bucket: sourcemaps[0].bucket.bucketName,
225
+ functions: sourcemaps.map((s) => [s.arn, s.key]),
226
+ },
227
+ });
228
+ resource.node.addDependency(policy);
229
+ }
230
+ }
198
231
  // Set removal policy
199
232
  this.applyRemovalPolicy(child);
200
233
  // Stack names need to be parameterized with the stage name
@@ -10,6 +10,7 @@ import * as functionUrlCors from "./util/functionUrlCors.js";
10
10
  import { Architecture, Function as CDKFunction, FunctionOptions, ILayerVersion, Runtime as CDKRuntime, Tracing } from "aws-cdk-lib/aws-lambda";
11
11
  import { RetentionDays } from "aws-cdk-lib/aws-logs";
12
12
  import { Size as CDKSize, Duration as CDKDuration } from "aws-cdk-lib/core";
13
+ import { IBucket } from "aws-cdk-lib/aws-s3";
13
14
  declare const supportedRuntimes: {
14
15
  container: CDKRuntime;
15
16
  rust: CDKRuntime;
@@ -657,6 +658,18 @@ export declare class Function extends CDKFunction implements SSTConstruct {
657
658
  static mergeProps(baseProps?: FunctionProps, props?: FunctionProps): FunctionProps;
658
659
  }
659
660
  export declare const useFunctions: () => {
661
+ sourcemaps: {
662
+ add(stack: string, source: {
663
+ arn: string;
664
+ bucket: IBucket;
665
+ key: string;
666
+ }): void;
667
+ forStack(stack: string): {
668
+ arn: string;
669
+ bucket: IBucket;
670
+ key: string;
671
+ }[];
672
+ };
660
673
  fromID(id: string): FunctionProps | undefined;
661
674
  add(name: string, props: FunctionProps): void;
662
675
  readonly all: Record<string, FunctionProps>;
@@ -1,6 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types */
2
2
  // Note: disabling ban-type rule so we don't get an error referencing the class Function
3
3
  import path from "path";
4
+ import fs from "fs/promises";
5
+ import zlib from "zlib";
4
6
  import { Stack } from "./Stack.js";
5
7
  import { Job } from "./Job.js";
6
8
  import { Secret } from "./Config.js";
@@ -24,8 +26,7 @@ import { StringParameter } from "aws-cdk-lib/aws-ssm";
24
26
  import { Platform } from "aws-cdk-lib/aws-ecr-assets";
25
27
  import { useBootstrap } from "../bootstrap.js";
26
28
  import { Colors } from "../cli/colors.js";
27
- import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment";
28
- import { Bucket } from "aws-cdk-lib/aws-s3";
29
+ import { Asset } from "aws-cdk-lib/aws-s3-assets";
29
30
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
30
31
  const supportedRuntimes = {
31
32
  container: CDKRuntime.FROM_IMAGE,
@@ -231,6 +232,7 @@ export class Function extends CDKFunction {
231
232
  useDeferredTasks().add(async () => {
232
233
  if (props.runtime === "container")
233
234
  Colors.line(`➜ Building the container image for the "${this.node.id}" function...`);
235
+ const project = useProject();
234
236
  // Build function
235
237
  const result = await useRuntimeHandlers().build(this.node.addr, "deploy");
236
238
  if (result.type === "error") {
@@ -242,19 +244,23 @@ export class Function extends CDKFunction {
242
244
  // No need to update code if runtime is container
243
245
  if (props.runtime === "container")
244
246
  return;
247
+ if (result.sourcemap) {
248
+ const data = await fs.readFile(result.sourcemap);
249
+ await fs.writeFile(result.sourcemap, zlib.gzipSync(data));
250
+ const asset = new Asset(stack, this.id + "-Sourcemap", {
251
+ path: result.sourcemap,
252
+ });
253
+ await fs.rm(result.sourcemap);
254
+ useFunctions().sourcemaps.add(stack.stackName, {
255
+ bucket: asset.bucket,
256
+ key: asset.s3ObjectKey,
257
+ arn: this.functionArn,
258
+ });
259
+ }
245
260
  // Update code
246
261
  const cfnFunction = this.node.defaultChild;
247
262
  const code = AssetCode.fromAsset(result.out);
248
263
  const codeConfig = code.bind(this);
249
- const bootstrap = await useBootstrap();
250
- if (result.sourcemap)
251
- new BucketDeployment(this, "Sourcemap", {
252
- sources: [Source.asset(result.sourcemap)],
253
- contentEncoding: "gzip",
254
- contentType: "application/json",
255
- destinationBucket: Bucket.fromBucketName(this, "BootstrapBucket", bootstrap.bucket),
256
- destinationKeyPrefix: `sourcemap/${app.name}/${app.stage}/${this.functionArn}/`,
257
- });
258
264
  cfnFunction.code = {
259
265
  s3Bucket: codeConfig.s3Location?.bucketName,
260
266
  s3Key: codeConfig.s3Location?.objectKey,
@@ -548,7 +554,19 @@ export class Function extends CDKFunction {
548
554
  }
549
555
  export const useFunctions = createAppContext(() => {
550
556
  const functions = {};
557
+ const sourcemaps = {};
551
558
  return {
559
+ sourcemaps: {
560
+ add(stack, source) {
561
+ let arr = sourcemaps[stack];
562
+ if (!arr)
563
+ sourcemaps[stack] = arr = [];
564
+ arr.push(source);
565
+ },
566
+ forStack(stack) {
567
+ return sourcemaps[stack] || [];
568
+ },
569
+ },
552
570
  fromID(id) {
553
571
  const result = functions[id];
554
572
  if (!result)
@@ -2,6 +2,7 @@ import { OidcBasicConfig } from "./oidc.js";
2
2
  type MicrosoftConfig = OidcBasicConfig & {
3
3
  mode: "oidc";
4
4
  prompt?: "login" | "none" | "consent" | "select_account";
5
+ tenantID?: string;
5
6
  };
6
7
  export declare function MicrosoftAdapter(config: MicrosoftConfig): () => Promise<{
7
8
  type: "success";
@@ -1,13 +1,15 @@
1
1
  import { Issuer } from "openid-client";
2
2
  import { OidcAdapter } from "./oidc.js";
3
- // These are the different Microsoft auth urls for different types of accounts:
4
- // Common: https://login.microsoftonline.com/common/v2.0 (both business and private)
5
- // Business: https://login.microsoftonline.com/{tenant}/v2.0
6
- // Private: https://login.microsoftonline.com/consumers/v2.0
7
- const issuer = await Issuer.discover("https://login.microsoftonline.com/common/v2.0");
8
3
  export function MicrosoftAdapter(config) {
4
+ const authority = config?.tenantID ?? "common";
5
+ const issuer = `https://login.microsoftonline.com/${authority}`;
9
6
  return OidcAdapter({
10
- issuer,
7
+ issuer: new Issuer({
8
+ issuer: `${issuer}/v2.0`,
9
+ authorization_endpoint: `${issuer}/oauth2/v2.0/authorize`,
10
+ token_endpoint: `${issuer}/oauth2/v2.0/token`,
11
+ jwks_uri: `${issuer}/discovery/v2.0/keys`,
12
+ }),
11
13
  scope: "openid email profile",
12
14
  ...config,
13
15
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "sideEffects": false,
3
3
  "name": "sst",
4
- "version": "2.24.12",
4
+ "version": "2.24.14",
5
5
  "bin": {
6
6
  "sst": "cli/sst.js"
7
7
  },
@@ -158,7 +158,14 @@ export const useNodeHandler = Context.memo(async () => {
158
158
  : undefined,
159
159
  }),
160
160
  outfile: target,
161
- sourcemap: input.mode === "start" ? "linked" : true,
161
+ // always generate sourcemaps in local
162
+ // never generate sourcemaps if explicitly false
163
+ // otherwise generate sourcemaps
164
+ sourcemap: input.mode === "start"
165
+ ? "linked"
166
+ : nodejs.sourcemap === false
167
+ ? false
168
+ : true,
162
169
  minify: nodejs.minify,
163
170
  ...override,
164
171
  };
@@ -1,11 +1,9 @@
1
1
  import { Context } from "../context/context.js";
2
2
  import { Logger } from "../logger.js";
3
3
  import path from "path";
4
- import zlib from "zlib";
5
4
  import fs from "fs/promises";
6
5
  import { useWatcher } from "../watcher.js";
7
6
  import { useBus } from "../bus.js";
8
- import crypto from "crypto";
9
7
  import { useProject } from "../project.js";
10
8
  import { useFunctions } from "../constructs/Function.js";
11
9
  export const useRuntimeHandlers = Context.memo(() => {
@@ -77,22 +75,11 @@ export const useRuntimeHandlers = Context.memo(() => {
77
75
  }
78
76
  if (func.hooks?.afterBuild)
79
77
  await func.hooks.afterBuild(func, out);
80
- let sourcemap;
81
- if (built.sourcemap && mode === "deploy") {
82
- const data = await fs.readFile(built.sourcemap);
83
- await fs.rm(built.sourcemap);
84
- const hash = crypto.createHash("md5").update(data).digest("hex");
85
- const dir = path.join(project.paths.artifacts, "sourcemaps", functionID);
86
- await fs.rm(dir, { recursive: true, force: true });
87
- await fs.mkdir(dir, { recursive: true });
88
- sourcemap = dir;
89
- await fs.writeFile(path.join(dir, `${hash}.map`), zlib.gzipSync(data));
90
- }
91
78
  bus.publish("function.build.success", { functionID });
92
79
  return {
93
80
  ...built,
94
81
  out,
95
- sourcemap,
82
+ sourcemap: built.sourcemap,
96
83
  };
97
84
  }
98
85
  if (pendingBuilds.has(functionID)) {
@@ -132,8 +119,8 @@ export const useFunctionBuilder = Context.memo(() => {
132
119
  watcher.subscribe("file.changed", async (evt) => {
133
120
  try {
134
121
  const functions = useFunctions();
135
- for (const [functionID, props] of Object.entries(functions.all)) {
136
- const handler = handlers.for(props.runtime);
122
+ for (const [functionID, info] of Object.entries(functions.all)) {
123
+ const handler = handlers.for(info.runtime);
137
124
  if (!handler?.shouldBuild({
138
125
  functionID,
139
126
  file: evt.properties.file,