sst 2.1.20 → 2.1.22

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.
@@ -13,3 +13,11 @@ export declare const dev: (program: Program) => import("yargs").Argv<{
13
13
  } & {
14
14
  "increase-timeout": boolean | undefined;
15
15
  }>;
16
+ declare module "../../bus.js" {
17
+ interface Events {
18
+ "cli.dev": {
19
+ app: string;
20
+ stage: string;
21
+ };
22
+ }
23
+ }
@@ -29,6 +29,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
29
29
  const { useRDSWarmer } = await import("./plugins/warmer.js");
30
30
  const { useProject } = await import("../../project.js");
31
31
  const { useMetadata } = await import("../../stacks/metadata.js");
32
+ const { useIOT } = await import("../../iot.js");
32
33
  const { clear } = await import("../terminal.js");
33
34
  if (args._[0] === "start") {
34
35
  console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
@@ -223,6 +224,27 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
223
224
  });
224
225
  await build();
225
226
  });
227
+ const useDisconnector = Context.memo(async () => {
228
+ const bus = useBus();
229
+ const project = useProject();
230
+ const iot = await useIOT();
231
+ bus.subscribe("cli.dev", async (evt) => {
232
+ const topic = `${iot.prefix}/events`;
233
+ iot.publish(topic, "cli.dev", evt.properties);
234
+ });
235
+ bus.publish("cli.dev", {
236
+ stage: project.config.stage,
237
+ app: project.config.name,
238
+ });
239
+ bus.subscribe("cli.dev", async (evt) => {
240
+ if (evt.properties.stage !== project.config.stage)
241
+ return;
242
+ if (evt.properties.app !== project.config.name)
243
+ return;
244
+ Colors.line(Colors.danger(`➜ `), "Another sst dev session has been started up for this stage. Exiting");
245
+ process.exit(0);
246
+ });
247
+ });
226
248
  const [appMetadata] = await Promise.all([
227
249
  useAppMetadata(),
228
250
  useLocalServer({
@@ -240,6 +262,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
240
262
  clear();
241
263
  await printHeader({ console: true, hint: "ready!" });
242
264
  await Promise.all([
265
+ useDisconnector(),
243
266
  useRuntimeWorkers(),
244
267
  useIOTBridge(),
245
268
  useRuntimeServer(),
@@ -32,7 +32,7 @@ export class AstroSite extends SsrSite {
32
32
  super.validateBuildOutput();
33
33
  }
34
34
  createFunctionForRegional() {
35
- const { runtime, timeout, memorySize, permissions, environment, bind, cdk, } = this.props;
35
+ const { runtime, timeout, memorySize, permissions, environment, nodejs, bind, cdk, } = this.props;
36
36
  const fn = new Function(this, `ServerFunction`, {
37
37
  description: "Server handler",
38
38
  handler: path.join(this.props.path, "dist", "server", "entry.handler"),
@@ -42,6 +42,7 @@ export class AstroSite extends SsrSite {
42
42
  timeout,
43
43
  nodejs: {
44
44
  format: "esm",
45
+ ...nodejs,
45
46
  },
46
47
  bind,
47
48
  environment,
@@ -53,7 +54,7 @@ export class AstroSite extends SsrSite {
53
54
  return fn;
54
55
  }
55
56
  createFunctionForEdge() {
56
- const { runtime, timeout, memorySize, bind, permissions, environment } = this.props;
57
+ const { runtime, timeout, memorySize, bind, permissions, environment, nodejs, } = this.props;
57
58
  return new EdgeFunction(this, `Server`, {
58
59
  scopeOverride: this,
59
60
  handler: path.join(this.props.path, "dist", "server", "entry.handler"),
@@ -63,7 +64,10 @@ export class AstroSite extends SsrSite {
63
64
  bind,
64
65
  environment,
65
66
  permissions,
66
- format: "esm",
67
+ nodejs: {
68
+ format: "esm",
69
+ ...nodejs,
70
+ },
67
71
  });
68
72
  }
69
73
  }
@@ -1,8 +1,8 @@
1
- import { BuildOptions } from "esbuild";
2
1
  import { Construct, IConstruct } from "constructs";
3
2
  import { Role } from "aws-cdk-lib/aws-iam";
4
3
  import { IVersion } from "aws-cdk-lib/aws-lambda";
5
4
  import { SSTConstruct } from "./Construct.js";
5
+ import { NodeJSProps } from "./Function.js";
6
6
  import { Size } from "./util/size.js";
7
7
  import { Duration } from "./util/duration.js";
8
8
  import { Permissions } from "./util/permission.js";
@@ -15,13 +15,15 @@ export interface EdgeFunctionProps {
15
15
  permissions?: Permissions;
16
16
  environment?: Record<string, string>;
17
17
  bind?: SSTConstruct[];
18
- esbuild?: BuildOptions;
19
- format: "cjs" | "esm";
18
+ nodejs?: NodeJSProps;
20
19
  scopeOverride?: IConstruct;
21
20
  }
22
21
  export declare class EdgeFunction extends Construct {
23
22
  role: Role;
24
23
  functionArn: string;
24
+ private function;
25
+ private assetReplacer;
26
+ private assetReplacerPolicy;
25
27
  private scope;
26
28
  private versionId;
27
29
  private bindingEnvs;
@@ -29,14 +31,15 @@ export declare class EdgeFunction extends Construct {
29
31
  constructor(scope: Construct, id: string, props: EdgeFunctionProps);
30
32
  get currentVersion(): IVersion;
31
33
  attachPermissions(permissions: Permissions): void;
32
- private buildBundle;
33
- private updateBundleWithEnvWrapper;
34
+ private buildAssetFromHandler;
35
+ private buildAssetFromBundle;
34
36
  private bind;
35
- private createCodeAsset;
36
37
  private createCodeReplacer;
38
+ private updateCodeReplacer;
37
39
  private createRole;
38
40
  private createSingletonBucketInUsEast1;
39
41
  private createFunctionInUsEast1;
42
+ private updateFunctionInUsEast1;
40
43
  private createVersionInUsEast1;
41
44
  private getHandlerExtension;
42
45
  private trimFromStart;
@@ -2,14 +2,16 @@ import fs from "fs";
2
2
  import url from "url";
3
3
  import path from "path";
4
4
  import crypto from "crypto";
5
- import { buildSync } from "esbuild";
6
5
  import { Construct } from "constructs";
7
6
  import { Effect, Role, Policy, PolicyStatement, CompositePrincipal, ServicePrincipal, ManagedPolicy, } from "aws-cdk-lib/aws-iam";
8
7
  import { Version, Code, Runtime, Function as CdkFunction, } from "aws-cdk-lib/aws-lambda";
9
8
  import { Asset } from "aws-cdk-lib/aws-s3-assets";
10
9
  import { Lazy, Duration as CdkDuration, CustomResource, } from "aws-cdk-lib";
11
10
  import { useProject } from "../project.js";
11
+ import { useRuntimeHandlers } from "../runtime/handlers.js";
12
12
  import { Stack } from "./Stack.js";
13
+ import { useFunctions } from "./Function.js";
14
+ import { useDeferredTasks } from "./deferred_task.js";
13
15
  import { bindEnvironment, bindPermissions, getReferencedSecrets, } from "./util/functionBinding.js";
14
16
  import { toCdkSize } from "./util/size.js";
15
17
  import { toCdkDuration } from "./util/duration.js";
@@ -21,6 +23,9 @@ const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
21
23
  export class EdgeFunction extends Construct {
22
24
  role;
23
25
  functionArn;
26
+ function;
27
+ assetReplacer;
28
+ assetReplacerPolicy;
24
29
  scope;
25
30
  versionId;
26
31
  bindingEnvs;
@@ -36,29 +41,46 @@ export class EdgeFunction extends Construct {
36
41
  this.scope = props.scopeOverride || this;
37
42
  this.props = {
38
43
  ...props,
39
- bundle: props.bundle || "placeholder",
40
44
  environment: props.environment || {},
41
45
  permissions: props.permissions || [],
42
46
  };
43
- // Build bundle if not prebuilt
44
- const { bundle, handler, handlerFilename } = props.bundle
45
- ? this.updateBundleWithEnvWrapper()
46
- : this.buildBundle();
47
- this.props.bundle = bundle;
48
- this.props.handler = handler;
47
+ const { assetBucket, assetKey, handlerFilename } = (props.bundle
48
+ ? // Case: bundle is pre-built
49
+ () => {
50
+ const { asset, handlerFilename } = this.buildAssetFromBundle(props.bundle, props.handler);
51
+ return {
52
+ assetBucket: asset.s3BucketName,
53
+ assetKey: asset.s3ObjectKey,
54
+ handlerFilename,
55
+ };
56
+ }
57
+ : // Case: bundle is NOT pre-built
58
+ () => {
59
+ this.buildAssetFromHandler((asset, handlerFilename) => {
60
+ this.updateCodeReplacer(asset.s3BucketName, asset.s3ObjectKey, handlerFilename);
61
+ this.updateFunctionInUsEast1(asset.s3BucketName, asset.s3ObjectKey);
62
+ });
63
+ return {
64
+ assetBucket: "placeholder",
65
+ assetKey: "placeholder",
66
+ handlerFilename: "placeholder",
67
+ };
68
+ })();
49
69
  // Bind first b/e function's environment variables cannot be added after
50
70
  this.bindingEnvs = {};
51
71
  this.bind(props.bind || []);
52
- const asset = this.createCodeAsset();
53
- const assetReplacer = this.createCodeReplacer(asset, handlerFilename);
72
+ const { assetReplacer, assetReplacerPolicy } = this.createCodeReplacer(assetBucket, assetKey, handlerFilename);
54
73
  this.role = this.createRole();
55
- const bucket = this.createSingletonBucketInUsEast1();
56
- const { fn, fnArn } = this.createFunctionInUsEast1(asset, bucket);
74
+ const lambdaBucket = this.createSingletonBucketInUsEast1();
75
+ const { fn, fnArn } = this.createFunctionInUsEast1(assetBucket, assetKey, lambdaBucket);
57
76
  const { versionId } = this.createVersionInUsEast1(fn, fnArn);
58
77
  // Deploy after the code is updated
59
78
  fn.node.addDependency(assetReplacer);
79
+ this.function = fn;
60
80
  this.functionArn = fnArn;
61
81
  this.versionId = versionId;
82
+ this.assetReplacer = assetReplacer;
83
+ this.assetReplacerPolicy = assetReplacerPolicy;
62
84
  }
63
85
  get currentVersion() {
64
86
  return Version.fromVersionArn(this, `${this.node.id}FunctionVersion`, `${this.functionArn}:${this.versionId}`);
@@ -66,60 +88,35 @@ export class EdgeFunction extends Construct {
66
88
  attachPermissions(permissions) {
67
89
  attachPermissionsToRole(this.role, permissions);
68
90
  }
69
- buildBundle() {
70
- const { handler, format, esbuild, runtime } = this.props;
71
- const isESM = format === "esm";
72
- const { dir: inputPath, base: inputHandler, name: inputFilename, ext: inputHandlerFunction, } = path.parse(handler);
73
- const inputFileExt = this.getHandlerExtension(path.join(inputPath, inputFilename));
74
- // Create a directory that we will use to create the bundled version
75
- // of the "core server build" along with our custom Lamba server handler.
76
- const outputPath = path.resolve(path.join(useProject().paths.artifacts, `EdgeFunction-${this.node.id}-${this.node.addr}`));
77
- const outputHandler = inputHandler;
78
- const outputFilename = inputFilename;
79
- const outputFileExt = isESM ? ".mjs" : ".cjs";
80
- const { external, ...override } = esbuild || {};
81
- const result = buildSync({
82
- entryPoints: [handler.replace(inputHandlerFunction, inputFileExt)],
83
- platform: "node",
84
- external: [
85
- ...(isESM || runtime === "nodejs18.x" ? [] : ["aws-sdk"]),
86
- ...(external || []),
87
- ],
88
- metafile: true,
89
- bundle: true,
90
- ...(isESM
91
- ? {
92
- format: "esm",
93
- target: "esnext",
94
- mainFields: ["module", "main"],
95
- banner: {
96
- js: [
97
- `import { createRequire as topLevelCreateRequire } from 'module';`,
98
- `const require = topLevelCreateRequire(import.meta.url);`,
99
- `import { fileURLToPath as topLevelFileUrlToPath } from "url"`,
100
- `const __dirname = topLevelFileUrlToPath(new URL(".", import.meta.url))`,
101
- `process.env = { ...process.env, ..."{{ _SST_FUNCTION_ENVIRONMENT_ }}" };`,
102
- ].join("\n"),
103
- },
104
- }
105
- : {
106
- format: "cjs",
107
- target: "node14",
108
- }),
109
- outfile: path.join(outputPath, outputFilename + outputFileExt),
110
- ...override,
91
+ buildAssetFromHandler(onBundled) {
92
+ const { nodejs } = this.props;
93
+ useFunctions().add(this.node.addr, {
94
+ ...this.props,
95
+ nodejs: {
96
+ ...nodejs,
97
+ banner: [
98
+ `process.env = { ...process.env, ..."{{ _SST_FUNCTION_ENVIRONMENT_ }}" };`,
99
+ nodejs?.banner || "",
100
+ ].join("\n"),
101
+ },
102
+ });
103
+ useDeferredTasks().add(async () => {
104
+ // Build function
105
+ const bundle = await useRuntimeHandlers().build(this.node.addr, "deploy");
106
+ // create wrapper that calls the handler
107
+ if (bundle.type === "error")
108
+ throw new Error(`There was a problem bundling the SSR function for the "${this.scope.node.id}" Site.`);
109
+ const asset = new Asset(this.scope, `FunctionAsset`, {
110
+ path: bundle.out,
111
+ });
112
+ // Get handler filename
113
+ const isESM = (nodejs?.format || "esm") === "esm";
114
+ const parsed = path.parse(bundle.handler);
115
+ const handlerFilename = `${parsed.dir}/${parsed.name}${isESM ? ".mjs" : ".cjs"}`;
116
+ onBundled(asset, handlerFilename);
111
117
  });
112
- if (result.errors.length > 0) {
113
- result.errors.forEach((error) => console.error(error));
114
- throw new Error(`There was a problem bundling the SSR function for the "${this.scope.node.id}" Site.`);
115
- }
116
- return {
117
- bundle: outputPath,
118
- handler: outputHandler,
119
- handlerFilename: outputFilename + outputFileExt,
120
- };
121
118
  }
122
- updateBundleWithEnvWrapper() {
119
+ buildAssetFromBundle(bundle, handler) {
123
120
  // We expose an environment variable token which is used by the code
124
121
  // replacer to inject the environment variables assigned to the
125
122
  // EdgeFunction construct.
@@ -132,14 +129,17 @@ export class EdgeFunction extends Construct {
132
129
  // support runtime environment variables. A downside of this approach
133
130
  // is that environment variables cannot be toggled after deployment,
134
131
  // each change to one requires a redeployment.
135
- const { bundle, handler } = this.props;
136
132
  const { dir: inputPath, name: inputFilename, ext: inputHandlerFunction, } = path.parse(handler);
137
133
  const inputFileExt = this.getHandlerExtension(path.join(bundle, inputPath, inputFilename));
138
134
  const handlerFilename = handler.replace(inputHandlerFunction, inputFileExt);
139
135
  const filePath = path.join(bundle, handlerFilename);
140
136
  const fileData = fs.readFileSync(filePath, "utf8");
141
137
  fs.writeFileSync(filePath, `process.env = { ...process.env, ..."{{ _SST_FUNCTION_ENVIRONMENT_ }}" };\n${fileData}`);
142
- return { bundle, handler, handlerFilename };
138
+ // Create asset
139
+ const asset = new Asset(this.scope, `FunctionAsset`, {
140
+ path: bundle,
141
+ });
142
+ return { handlerFilename, asset };
143
143
  }
144
144
  bind(constructs) {
145
145
  const app = this.node.root;
@@ -168,13 +168,7 @@ export class EdgeFunction extends Construct {
168
168
  }
169
169
  });
170
170
  }
171
- createCodeAsset() {
172
- const { bundle } = this.props;
173
- return new Asset(this.scope, `FunctionAsset`, {
174
- path: bundle,
175
- });
176
- }
177
- createCodeReplacer(asset, handlerFilename) {
171
+ createCodeReplacer(assetBucket, assetKey, handlerFilename) {
178
172
  const { environment } = this.props;
179
173
  const replacements = [
180
174
  {
@@ -200,7 +194,7 @@ export class EdgeFunction extends Construct {
200
194
  new PolicyStatement({
201
195
  effect: Effect.ALLOW,
202
196
  actions: ["s3:GetObject", "s3:PutObject"],
203
- resources: [`arn:${stack.partition}:s3:::${asset.s3BucketName}/*`],
197
+ resources: [`arn:${stack.partition}:s3:::${assetBucket}/*`],
204
198
  }),
205
199
  ],
206
200
  });
@@ -209,13 +203,23 @@ export class EdgeFunction extends Construct {
209
203
  serviceToken: stack.customResourceHandler.functionArn,
210
204
  resourceType: "Custom::AssetReplacer",
211
205
  properties: {
212
- bucket: asset.s3BucketName,
213
- key: asset.s3ObjectKey,
206
+ bucket: assetBucket,
207
+ key: assetKey,
214
208
  replacements,
215
209
  },
216
210
  });
217
211
  resource.node.addDependency(policy);
218
- return resource;
212
+ return { assetReplacer: resource, assetReplacerPolicy: policy };
213
+ }
214
+ updateCodeReplacer(assetBucket, assetKey, handlerFilename) {
215
+ const stack = Stack.of(this);
216
+ const cfnReplacer = this.assetReplacer.node
217
+ .defaultChild;
218
+ cfnReplacer.addPropertyOverride("bucket", assetBucket);
219
+ cfnReplacer.addPropertyOverride("key", assetKey);
220
+ cfnReplacer.addPropertyOverride("replacements.0.files", handlerFilename);
221
+ const cfnPolicy = this.assetReplacerPolicy.node.defaultChild;
222
+ cfnPolicy.addPropertyOverride("PolicyDocument.Statement.0.Resource", `arn:${stack.partition}:s3:::${assetBucket}/*`);
219
223
  }
220
224
  createRole() {
221
225
  const { permissions } = this.props;
@@ -268,7 +272,7 @@ export class EdgeFunction extends Construct {
268
272
  });
269
273
  return resource;
270
274
  }
271
- createFunctionInUsEast1(asset, bucket) {
275
+ createFunctionInUsEast1(assetBucket, assetKey, lambdaBucket) {
272
276
  const { handler, runtime, timeout, memorySize } = this.props;
273
277
  // Do not recreate if exist
274
278
  const providerId = "EdgeLambdaProvider";
@@ -301,13 +305,13 @@ export class EdgeFunction extends Construct {
301
305
  resourceType: "Custom::SSTEdgeLambda",
302
306
  properties: {
303
307
  FunctionNamePrefix: `${Stack.of(this).stackName}-${resId}`,
304
- FunctionBucket: bucket.getAttString("BucketName"),
308
+ FunctionBucket: lambdaBucket.getAttString("BucketName"),
305
309
  FunctionParams: {
306
310
  Description: `${this.node.id} handler`,
307
311
  Handler: handler,
308
312
  Code: {
309
- S3Bucket: asset.s3BucketName,
310
- S3Key: asset.s3ObjectKey,
313
+ S3Bucket: assetBucket,
314
+ S3Key: assetKey,
311
315
  },
312
316
  Runtime: runtime === "nodejs14.x"
313
317
  ? Runtime.NODEJS_14_X.name
@@ -326,6 +330,13 @@ export class EdgeFunction extends Construct {
326
330
  });
327
331
  return { fn, fnArn: fn.getAttString("FunctionArn") };
328
332
  }
333
+ updateFunctionInUsEast1(assetBucket, assetKey) {
334
+ const cfnLambda = this.function.node.defaultChild;
335
+ cfnLambda.addPropertyOverride("FunctionParams.Code", {
336
+ S3Bucket: assetBucket,
337
+ S3Key: assetKey,
338
+ });
339
+ }
329
340
  createVersionInUsEast1(fn, fnArn) {
330
341
  // Do not recreate if exist
331
342
  const providerId = "EdgeLambdaVersionProvider";
@@ -1,9 +1,9 @@
1
1
  import { Construct } from "constructs";
2
- import * as lambda from "aws-cdk-lib/aws-lambda";
3
- import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
2
+ import { Function as CdkFunction } from "aws-cdk-lib/aws-lambda";
3
+ import { Distribution, CachePolicy } from "aws-cdk-lib/aws-cloudfront";
4
4
  import { SsrSite, SsrSiteProps } from "./SsrSite.js";
5
5
  import { Size } from "./util/size.js";
6
- export interface NextjsSiteProps extends Omit<SsrSiteProps, "edge"> {
6
+ export interface NextjsSiteProps extends Omit<SsrSiteProps, "edge" | "nodejs"> {
7
7
  imageOptimization?: {
8
8
  /**
9
9
  * The amount of memory in MB allocated for image optimization function.
@@ -41,10 +41,10 @@ export declare class NextjsSite extends SsrSite {
41
41
  clientBuildOutputDir: string;
42
42
  clientBuildVersionedSubDir: string;
43
43
  };
44
- protected createFunctionForRegional(): lambda.Function;
44
+ protected createFunctionForRegional(): CdkFunction;
45
45
  private createImageOptimizationFunctionForRegional;
46
46
  private createMiddlewareEdgeFunctionForRegional;
47
- protected createCloudFrontDistributionForRegional(): cloudfront.Distribution;
48
- protected createCloudFrontServerCachePolicy(): cloudfront.CachePolicy;
47
+ protected createCloudFrontDistributionForRegional(): Distribution;
48
+ protected createCloudFrontServerCachePolicy(): CachePolicy;
49
49
  protected generateBuildId(): string;
50
50
  }
@@ -2,10 +2,10 @@ import fs from "fs";
2
2
  import url from "url";
3
3
  import path from "path";
4
4
  import { Fn, Duration as CdkDuration, RemovalPolicy } from "aws-cdk-lib";
5
- import * as logs from "aws-cdk-lib/aws-logs";
6
- import * as lambda from "aws-cdk-lib/aws-lambda";
7
- import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
8
- import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
5
+ import { RetentionDays } from "aws-cdk-lib/aws-logs";
6
+ import { Function as CdkFunction, Code, Runtime, Architecture, FunctionUrlAuthType, } from "aws-cdk-lib/aws-lambda";
7
+ import { Distribution, ViewerProtocolPolicy, AllowedMethods, LambdaEdgeEventType, CachedMethods, CachePolicy, CacheQueryStringBehavior, CacheCookieBehavior, CacheHeaderBehavior, } from "aws-cdk-lib/aws-cloudfront";
8
+ import { S3Origin, HttpOrigin, OriginGroup, } from "aws-cdk-lib/aws-cloudfront-origins";
9
9
  import { SsrFunction } from "./SsrFunction.js";
10
10
  import { EdgeFunction } from "./EdgeFunction.js";
11
11
  import { SsrSite } from "./SsrSite.js";
@@ -55,22 +55,22 @@ export class NextjsSite extends SsrSite {
55
55
  }
56
56
  createImageOptimizationFunctionForRegional() {
57
57
  const { imageOptimization, path: sitePath } = this.props;
58
- return new lambda.Function(this, `ImageFunction`, {
58
+ return new CdkFunction(this, `ImageFunction`, {
59
59
  description: "Image optimization handler for Next.js",
60
60
  handler: "index.handler",
61
61
  currentVersionOptions: {
62
62
  removalPolicy: RemovalPolicy.DESTROY,
63
63
  },
64
- logRetention: logs.RetentionDays.THREE_DAYS,
65
- code: lambda.Code.fromAsset(path.join(sitePath, ".open-next/image-optimization-function")),
66
- runtime: lambda.Runtime.NODEJS_18_X,
64
+ logRetention: RetentionDays.THREE_DAYS,
65
+ code: Code.fromAsset(path.join(sitePath, ".open-next/image-optimization-function")),
66
+ runtime: Runtime.NODEJS_18_X,
67
67
  memorySize: imageOptimization?.memorySize
68
68
  ? typeof imageOptimization.memorySize === "string"
69
69
  ? toCdkSize(imageOptimization.memorySize).toMebibytes()
70
70
  : imageOptimization.memorySize
71
71
  : 1536,
72
72
  timeout: CdkDuration.seconds(25),
73
- architecture: lambda.Architecture.ARM_64,
73
+ architecture: Architecture.ARM_64,
74
74
  environment: {
75
75
  BUCKET_NAME: this.cdk.bucket.bucketName,
76
76
  },
@@ -94,29 +94,31 @@ export class NextjsSite extends SsrSite {
94
94
  memorySize: 128,
95
95
  permissions,
96
96
  environment,
97
- format: "esm",
97
+ nodejs: {
98
+ format: "esm",
99
+ },
98
100
  });
99
101
  }
100
102
  }
101
103
  createCloudFrontDistributionForRegional() {
102
104
  const { cdk } = this.props;
103
105
  const cfDistributionProps = cdk?.distribution || {};
104
- const s3Origin = new origins.S3Origin(this.cdk.bucket);
106
+ const s3Origin = new S3Origin(this.cdk.bucket);
105
107
  // Create server behavior
106
108
  const middlewareFn = this.createMiddlewareEdgeFunctionForRegional();
107
109
  const serverFnUrl = this.serverLambdaForRegional.addFunctionUrl({
108
- authType: lambda.FunctionUrlAuthType.NONE,
110
+ authType: FunctionUrlAuthType.NONE,
109
111
  });
110
112
  const serverBehavior = {
111
- viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
112
- origin: new origins.HttpOrigin(Fn.parseDomainName(serverFnUrl.url)),
113
- allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
114
- cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
113
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
114
+ origin: new HttpOrigin(Fn.parseDomainName(serverFnUrl.url)),
115
+ allowedMethods: AllowedMethods.ALLOW_ALL,
116
+ cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS,
115
117
  compress: true,
116
118
  cachePolicy: cdk?.serverCachePolicy ?? this.createCloudFrontServerCachePolicy(),
117
119
  edgeLambdas: middlewareFn && [
118
120
  {
119
- eventType: cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
121
+ eventType: LambdaEdgeEventType.VIEWER_REQUEST,
120
122
  functionVersion: middlewareFn.currentVersion,
121
123
  },
122
124
  ],
@@ -124,37 +126,37 @@ export class NextjsSite extends SsrSite {
124
126
  // Create image optimization behavior
125
127
  const imageFn = this.createImageOptimizationFunctionForRegional();
126
128
  const imageFnUrl = imageFn.addFunctionUrl({
127
- authType: lambda.FunctionUrlAuthType.NONE,
129
+ authType: FunctionUrlAuthType.NONE,
128
130
  });
129
131
  const imageBehavior = {
130
- viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
131
- origin: new origins.HttpOrigin(Fn.parseDomainName(imageFnUrl.url)),
132
- allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
133
- cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
132
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
133
+ origin: new HttpOrigin(Fn.parseDomainName(imageFnUrl.url)),
134
+ allowedMethods: AllowedMethods.ALLOW_ALL,
135
+ cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS,
134
136
  compress: true,
135
137
  cachePolicy: serverBehavior.cachePolicy,
136
138
  };
137
139
  // Create statics behavior
138
140
  const staticFileBehaviour = {
139
141
  origin: s3Origin,
140
- viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
141
- allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
142
- cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
142
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
143
+ allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
144
+ cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS,
143
145
  compress: true,
144
- cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
146
+ cachePolicy: CachePolicy.CACHING_OPTIMIZED,
145
147
  };
146
148
  // Create default behavior
147
149
  // default handler for requests that don't match any other path:
148
150
  // - try lambda handler first first
149
151
  // - if failed, fall back to S3
150
- const fallbackOriginGroup = new origins.OriginGroup({
152
+ const fallbackOriginGroup = new OriginGroup({
151
153
  primaryOrigin: serverBehavior.origin,
152
154
  fallbackOrigin: s3Origin,
153
155
  fallbackStatusCodes: [404],
154
156
  });
155
157
  const defaultBehavior = {
156
158
  origin: fallbackOriginGroup,
157
- viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
159
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
158
160
  compress: true,
159
161
  cachePolicy: serverBehavior.cachePolicy,
160
162
  edgeLambdas: serverBehavior.edgeLambdas,
@@ -208,7 +210,7 @@ export class NextjsSite extends SsrSite {
208
210
  * - Cache-Control: public, max-age=0, must-revalidate
209
211
  * - x-vercel-cache: MISS
210
212
  */
211
- return new cloudfront.Distribution(this, "Distribution", {
213
+ return new Distribution(this, "Distribution", {
212
214
  // these values can be overwritten by cfDistributionProps
213
215
  defaultRootObject: "",
214
216
  // Override props.
@@ -227,16 +229,16 @@ export class NextjsSite extends SsrSite {
227
229
  });
228
230
  }
229
231
  createCloudFrontServerCachePolicy() {
230
- return new cloudfront.CachePolicy(this, "ServerCache", {
231
- queryStringBehavior: cloudfront.CacheQueryStringBehavior.all(),
232
- headerBehavior: cloudfront.CacheHeaderBehavior.allowList(
232
+ return new CachePolicy(this, "ServerCache", {
233
+ queryStringBehavior: CacheQueryStringBehavior.all(),
234
+ headerBehavior: CacheHeaderBehavior.allowList(
233
235
  // required by image optimization request
234
236
  "accept",
235
237
  // required by server request
236
238
  "x-op-middleware-request-headers", "x-op-middleware-response-headers", "x-nextjs-data", "x-middleware-prefetch",
237
239
  // required by server request (in-place routing)
238
240
  "rsc", "next-router-prefetch", "next-router-state-tree"),
239
- cookieBehavior: cloudfront.CacheCookieBehavior.all(),
241
+ cookieBehavior: CacheCookieBehavior.all(),
240
242
  defaultTtl: CdkDuration.days(0),
241
243
  maxTtl: CdkDuration.days(365),
242
244
  minTtl: CdkDuration.days(0),
@@ -89,7 +89,7 @@ export class RemixSite extends SsrSite {
89
89
  };
90
90
  }
91
91
  createFunctionForRegional() {
92
- const { runtime, timeout, memorySize, permissions, environment, bind, cdk, } = this.props;
92
+ const { runtime, timeout, memorySize, permissions, environment, bind, nodejs, cdk, } = this.props;
93
93
  const { handler, esbuild } = this.createServerLambdaBundle("regional-server.js");
94
94
  const fn = new Function(this, `ServerFunction`, {
95
95
  description: "Server handler",
@@ -100,8 +100,12 @@ export class RemixSite extends SsrSite {
100
100
  timeout,
101
101
  nodejs: {
102
102
  format: "cjs",
103
- install: ["sharp"],
104
- esbuild,
103
+ ...nodejs,
104
+ esbuild: {
105
+ ...esbuild,
106
+ ...nodejs?.esbuild,
107
+ inject: [...(nodejs?.esbuild?.inject || []), ...esbuild.inject],
108
+ },
105
109
  },
106
110
  bind,
107
111
  environment,
@@ -113,7 +117,7 @@ export class RemixSite extends SsrSite {
113
117
  return fn;
114
118
  }
115
119
  createFunctionForEdge() {
116
- const { runtime, timeout, memorySize, bind, permissions, environment } = this.props;
120
+ const { runtime, timeout, memorySize, bind, permissions, environment, nodejs, } = this.props;
117
121
  const { handler, esbuild } = this.createServerLambdaBundle("edge-server.js");
118
122
  return new EdgeFunction(this, `Server`, {
119
123
  scopeOverride: this,
@@ -124,8 +128,15 @@ export class RemixSite extends SsrSite {
124
128
  bind,
125
129
  environment,
126
130
  permissions,
127
- format: "cjs",
128
- esbuild,
131
+ nodejs: {
132
+ format: "cjs",
133
+ ...nodejs,
134
+ esbuild: {
135
+ ...esbuild,
136
+ ...nodejs?.esbuild,
137
+ inject: [...(nodejs?.esbuild?.inject || []), ...esbuild.inject],
138
+ },
139
+ },
129
140
  });
130
141
  }
131
142
  }
@@ -23,7 +23,7 @@ export class SolidStartSite extends SsrSite {
23
23
  };
24
24
  }
25
25
  createFunctionForRegional() {
26
- const { runtime, timeout, memorySize, bind, permissions, environment, cdk, } = this.props;
26
+ const { runtime, timeout, memorySize, bind, nodejs, permissions, environment, cdk, } = this.props;
27
27
  // Create function
28
28
  const fn = new Function(this, `ServerFunction`, {
29
29
  description: "Server handler",
@@ -34,6 +34,7 @@ export class SolidStartSite extends SsrSite {
34
34
  timeout,
35
35
  nodejs: {
36
36
  format: "esm",
37
+ ...nodejs,
37
38
  },
38
39
  bind,
39
40
  environment,
@@ -45,7 +46,7 @@ export class SolidStartSite extends SsrSite {
45
46
  return fn;
46
47
  }
47
48
  createFunctionForEdge() {
48
- const { runtime, timeout, memorySize, bind, permissions, environment } = this.props;
49
+ const { runtime, timeout, memorySize, bind, permissions, environment, nodejs, } = this.props;
49
50
  return new EdgeFunction(this, `Server`, {
50
51
  scopeOverride: this,
51
52
  handler: path.join(this.props.path, "dist", "server", "index.handler"),
@@ -55,7 +56,10 @@ export class SolidStartSite extends SsrSite {
55
56
  bind,
56
57
  permissions,
57
58
  environment,
58
- format: "esm",
59
+ nodejs: {
60
+ format: "esm",
61
+ ...nodejs,
62
+ },
59
63
  });
60
64
  }
61
65
  }
@@ -6,6 +6,7 @@ import { Distribution, ICachePolicy, BehaviorOptions, CachePolicy } from "aws-cd
6
6
  import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
7
7
  import { S3Origin } from "aws-cdk-lib/aws-cloudfront-origins";
8
8
  import { SSTConstruct } from "./Construct.js";
9
+ import { NodeJSProps } from "./Function.js";
9
10
  import { EdgeFunction } from "./EdgeFunction.js";
10
11
  import { BaseSiteDomainProps, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
11
12
  import { Size } from "./util/size.js";
@@ -17,6 +18,8 @@ export type SsrBuildConfig = {
17
18
  clientBuildOutputDir: string;
18
19
  clientBuildVersionedSubDir: string;
19
20
  };
21
+ export interface SsrSiteNodeJSProps extends NodeJSProps {
22
+ }
20
23
  export interface SsrDomainProps extends BaseSiteDomainProps {
21
24
  }
22
25
  export interface SsrSiteReplaceProps extends BaseSiteReplaceProps {
@@ -103,6 +106,10 @@ export interface SsrSiteProps {
103
106
  * ```
104
107
  */
105
108
  runtime?: "nodejs14.x" | "nodejs16.x" | "nodejs18.x";
109
+ /**
110
+ * Used to configure nodejs function properties
111
+ */
112
+ nodejs?: SsrSiteNodeJSProps;
106
113
  /**
107
114
  * Attaches the given list of permissions to the SSR function. Configuring this property is equivalent to calling `attachPermissions()` after the site is created.
108
115
  * @example
@@ -19,12 +19,7 @@ const SessionMemo = /* @__PURE__ */ Context.memo(() => {
19
19
  })(token);
20
20
  return jwt;
21
21
  }
22
- catch {
23
- return {
24
- type: "public",
25
- properties: {},
26
- };
27
- }
22
+ catch { }
28
23
  }
29
24
  return {
30
25
  type: "public",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sst",
3
- "version": "2.1.20",
3
+ "version": "2.1.22",
4
4
  "bin": {
5
5
  "sst": "cli/sst.js"
6
6
  },
@@ -99,11 +99,16 @@ export const useNodeHandler = Context.memo(async () => {
99
99
  };
100
100
  }
101
101
  const { external, ...override } = nodejs.esbuild || {};
102
+ const forceExternal = [
103
+ "sharp",
104
+ "pg-native",
105
+ ...(isESM || input.props.runtime === "nodejs18.x" ? [] : ["aws-sdk"]),
106
+ ];
102
107
  const options = {
103
108
  entryPoints: [file],
104
109
  platform: "node",
105
110
  external: [
106
- ...(isESM || input.props.runtime === "nodejs18.x" ? [] : ["aws-sdk"]),
111
+ ...forceExternal,
107
112
  ...(nodejs.install || []),
108
113
  ...(external || []),
109
114
  ],
@@ -144,39 +149,57 @@ export const useNodeHandler = Context.memo(async () => {
144
149
  try {
145
150
  const result = await esbuild.build(options);
146
151
  // Install node_modules
147
- if (options.external?.length) {
148
- async function find(dir, target) {
149
- if (dir === "/")
150
- throw new VisibleError("Could not find a package.json file");
151
- if (await fs
152
- .access(path.join(dir, target))
153
- .then(() => true)
154
- .catch(() => false))
155
- return dir;
156
- return find(path.join(dir, ".."), target);
152
+ const installPackages = [
153
+ ...(nodejs.install || []),
154
+ ...forceExternal
155
+ .filter((pkg) => pkg !== "aws-sdk")
156
+ .filter((pkg) => !external?.includes(pkg))
157
+ .filter((pkg) => Object.values(result.metafile?.inputs || {}).some(({ imports }) => imports.some(({ path }) => path === pkg))),
158
+ ];
159
+ // TODO bubble up the warnings
160
+ const warnings = [];
161
+ Object.entries(result.metafile?.inputs || {}).forEach(([inputPath, { imports }]) => imports
162
+ .filter(({ path }) => path.includes("sst/constructs"))
163
+ .forEach(({ path }) => {
164
+ warnings.push(`You are importing from "${path}" in "${inputPath}". Did you mean to import from "sst/node"?`);
165
+ }));
166
+ async function find(dir, target) {
167
+ if (dir === "/")
168
+ throw new VisibleError("Could not find a package.json file");
169
+ if (await fs
170
+ .access(path.join(dir, target))
171
+ .then(() => true)
172
+ .catch(() => false))
173
+ return dir;
174
+ return find(path.join(dir, ".."), target);
175
+ }
176
+ if (input.mode === "deploy" && installPackages) {
177
+ const src = await find(parsed.dir, "package.json");
178
+ const json = JSON.parse(await fs
179
+ .readFile(path.join(src, "package.json"))
180
+ .then((x) => x.toString()));
181
+ fs.writeFile(path.join(input.out, "package.json"), JSON.stringify({
182
+ dependencies: Object.fromEntries(installPackages.map((x) => [x, json.dependencies?.[x] || "*"])),
183
+ }));
184
+ const cmd = ["npm install"];
185
+ if (installPackages.includes("sharp")) {
186
+ cmd.push("--platform=linux", input.props.architecture === "arm_64"
187
+ ? "--arch=arm64"
188
+ : "--arch=x64");
157
189
  }
158
- if (input.mode === "deploy" && nodejs.install) {
159
- const src = await find(parsed.dir, "package.json");
160
- const json = JSON.parse(await fs
161
- .readFile(path.join(src, "package.json"))
162
- .then((x) => x.toString()));
163
- fs.writeFile(path.join(input.out, "package.json"), JSON.stringify({
164
- dependencies: Object.fromEntries(nodejs.install?.map((x) => [x, json.dependencies?.[x] || "*"])),
165
- }));
166
- await new Promise((resolve) => {
167
- const process = exec("npm install", {
168
- cwd: input.out,
169
- });
170
- process.on("exit", () => resolve());
190
+ await new Promise((resolve) => {
191
+ const process = exec(cmd.join(" "), {
192
+ cwd: input.out,
171
193
  });
194
+ process.on("exit", () => resolve());
195
+ });
196
+ }
197
+ if (input.mode === "start") {
198
+ const dir = path.join(await find(parsed.dir, "package.json"), "node_modules");
199
+ try {
200
+ await fs.symlink(path.resolve(dir), path.resolve(path.join(input.out, "node_modules")), "dir");
172
201
  }
173
- if (input.mode === "start") {
174
- const dir = path.join(await find(parsed.dir, "package.json"), "node_modules");
175
- try {
176
- await fs.symlink(path.resolve(dir), path.resolve(path.join(input.out, "node_modules")), "dir");
177
- }
178
- catch { }
179
- }
202
+ catch { }
180
203
  }
181
204
  cache[input.functionID] = result;
182
205
  return {
package/sst.mjs CHANGED
@@ -2603,6 +2603,11 @@ var init_workers = __esm({
2603
2603
  });
2604
2604
 
2605
2605
  // src/iot.ts
2606
+ var iot_exports = {};
2607
+ __export(iot_exports, {
2608
+ useIOT: () => useIOT,
2609
+ useIOTEndpoint: () => useIOTEndpoint
2610
+ });
2606
2611
  import { IoTClient, DescribeEndpointCommand } from "@aws-sdk/client-iot";
2607
2612
  import iot from "aws-iot-device-sdk";
2608
2613
  function encode(input) {
@@ -2721,8 +2726,8 @@ var init_iot = __esm({
2721
2726
  });
2722
2727
 
2723
2728
  // src/runtime/iot.ts
2724
- var iot_exports = {};
2725
- __export(iot_exports, {
2729
+ var iot_exports2 = {};
2730
+ __export(iot_exports2, {
2726
2731
  useIOTBridge: () => useIOTBridge
2727
2732
  });
2728
2733
  var useIOTBridge;
@@ -4974,11 +4979,16 @@ var init_node = __esm({
4974
4979
  };
4975
4980
  }
4976
4981
  const { external, ...override } = nodejs.esbuild || {};
4982
+ const forceExternal = [
4983
+ "sharp",
4984
+ "pg-native",
4985
+ ...isESM || input.props.runtime === "nodejs18.x" ? [] : ["aws-sdk"]
4986
+ ];
4977
4987
  const options = {
4978
4988
  entryPoints: [file],
4979
4989
  platform: "node",
4980
4990
  external: [
4981
- ...isESM || input.props.runtime === "nodejs18.x" ? [] : ["aws-sdk"],
4991
+ ...forceExternal,
4982
4992
  ...nodejs.install || [],
4983
4993
  ...external || []
4984
4994
  ],
@@ -5014,47 +5024,68 @@ var init_node = __esm({
5014
5024
  };
5015
5025
  try {
5016
5026
  const result = await esbuild2.build(options);
5017
- if (options.external?.length) {
5018
- async function find2(dir, target2) {
5019
- if (dir === "/")
5020
- throw new VisibleError("Could not find a package.json file");
5021
- if (await fs10.access(path10.join(dir, target2)).then(() => true).catch(() => false))
5022
- return dir;
5023
- return find2(path10.join(dir, ".."), target2);
5024
- }
5025
- if (input.mode === "deploy" && nodejs.install) {
5026
- const src = await find2(parsed.dir, "package.json");
5027
- const json = JSON.parse(
5028
- await fs10.readFile(path10.join(src, "package.json")).then((x) => x.toString())
5027
+ const installPackages = [
5028
+ ...nodejs.install || [],
5029
+ ...forceExternal.filter((pkg) => pkg !== "aws-sdk").filter((pkg) => !external?.includes(pkg)).filter(
5030
+ (pkg) => Object.values(result.metafile?.inputs || {}).some(
5031
+ ({ imports }) => imports.some(({ path: path20 }) => path20 === pkg)
5032
+ )
5033
+ )
5034
+ ];
5035
+ const warnings = [];
5036
+ Object.entries(result.metafile?.inputs || {}).forEach(
5037
+ ([inputPath, { imports }]) => imports.filter(({ path: path20 }) => path20.includes("sst/constructs")).forEach(({ path: path20 }) => {
5038
+ warnings.push(
5039
+ `You are importing from "${path20}" in "${inputPath}". Did you mean to import from "sst/node"?`
5029
5040
  );
5030
- fs10.writeFile(
5031
- path10.join(input.out, "package.json"),
5032
- JSON.stringify({
5033
- dependencies: Object.fromEntries(
5034
- nodejs.install?.map((x) => [x, json.dependencies?.[x] || "*"])
5035
- )
5036
- })
5041
+ })
5042
+ );
5043
+ async function find2(dir, target2) {
5044
+ if (dir === "/")
5045
+ throw new VisibleError("Could not find a package.json file");
5046
+ if (await fs10.access(path10.join(dir, target2)).then(() => true).catch(() => false))
5047
+ return dir;
5048
+ return find2(path10.join(dir, ".."), target2);
5049
+ }
5050
+ if (input.mode === "deploy" && installPackages) {
5051
+ const src = await find2(parsed.dir, "package.json");
5052
+ const json = JSON.parse(
5053
+ await fs10.readFile(path10.join(src, "package.json")).then((x) => x.toString())
5054
+ );
5055
+ fs10.writeFile(
5056
+ path10.join(input.out, "package.json"),
5057
+ JSON.stringify({
5058
+ dependencies: Object.fromEntries(
5059
+ installPackages.map((x) => [x, json.dependencies?.[x] || "*"])
5060
+ )
5061
+ })
5062
+ );
5063
+ const cmd = ["npm install"];
5064
+ if (installPackages.includes("sharp")) {
5065
+ cmd.push(
5066
+ "--platform=linux",
5067
+ input.props.architecture === "arm_64" ? "--arch=arm64" : "--arch=x64"
5037
5068
  );
5038
- await new Promise((resolve) => {
5039
- const process2 = exec2("npm install", {
5040
- cwd: input.out
5041
- });
5042
- process2.on("exit", () => resolve());
5043
- });
5044
5069
  }
5045
- if (input.mode === "start") {
5046
- const dir = path10.join(
5047
- await find2(parsed.dir, "package.json"),
5048
- "node_modules"
5070
+ await new Promise((resolve) => {
5071
+ const process2 = exec2(cmd.join(" "), {
5072
+ cwd: input.out
5073
+ });
5074
+ process2.on("exit", () => resolve());
5075
+ });
5076
+ }
5077
+ if (input.mode === "start") {
5078
+ const dir = path10.join(
5079
+ await find2(parsed.dir, "package.json"),
5080
+ "node_modules"
5081
+ );
5082
+ try {
5083
+ await fs10.symlink(
5084
+ path10.resolve(dir),
5085
+ path10.resolve(path10.join(input.out, "node_modules")),
5086
+ "dir"
5049
5087
  );
5050
- try {
5051
- await fs10.symlink(
5052
- path10.resolve(dir),
5053
- path10.resolve(path10.join(input.out, "node_modules")),
5054
- "dir"
5055
- );
5056
- } catch {
5057
- }
5088
+ } catch {
5058
5089
  }
5059
5090
  }
5060
5091
  cache[input.functionID] = result;
@@ -6742,7 +6773,7 @@ var dev = (program2) => program2.command(
6742
6773
  const { mapValues, omitBy: omitBy2, pipe: pipe3 } = await import("remeda");
6743
6774
  const path20 = await import("path");
6744
6775
  const { useRuntimeWorkers: useRuntimeWorkers2 } = await Promise.resolve().then(() => (init_workers(), workers_exports));
6745
- const { useIOTBridge: useIOTBridge2 } = await Promise.resolve().then(() => (init_iot2(), iot_exports));
6776
+ const { useIOTBridge: useIOTBridge2 } = await Promise.resolve().then(() => (init_iot2(), iot_exports2));
6746
6777
  const { useRuntimeServer: useRuntimeServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
6747
6778
  const { useBus: useBus2 } = await Promise.resolve().then(() => (init_bus(), bus_exports));
6748
6779
  const { useWatcher: useWatcher2 } = await Promise.resolve().then(() => (init_watcher(), watcher_exports));
@@ -6764,6 +6795,7 @@ var dev = (program2) => program2.command(
6764
6795
  const { useRDSWarmer: useRDSWarmer2 } = await Promise.resolve().then(() => (init_warmer(), warmer_exports));
6765
6796
  const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
6766
6797
  const { useMetadata: useMetadata2 } = await Promise.resolve().then(() => (init_metadata(), metadata_exports));
6798
+ const { useIOT: useIOT2 } = await Promise.resolve().then(() => (init_iot(), iot_exports));
6767
6799
  const { clear: clear2 } = await Promise.resolve().then(() => (init_terminal(), terminal_exports));
6768
6800
  if (args._[0] === "start") {
6769
6801
  console.log(
@@ -6985,6 +7017,30 @@ var dev = (program2) => program2.command(
6985
7017
  });
6986
7018
  await build2();
6987
7019
  });
7020
+ const useDisconnector = Context2.memo(async () => {
7021
+ const bus = useBus2();
7022
+ const project = useProject2();
7023
+ const iot2 = await useIOT2();
7024
+ bus.subscribe("cli.dev", async (evt) => {
7025
+ const topic = `${iot2.prefix}/events`;
7026
+ iot2.publish(topic, "cli.dev", evt.properties);
7027
+ });
7028
+ bus.publish("cli.dev", {
7029
+ stage: project.config.stage,
7030
+ app: project.config.name
7031
+ });
7032
+ bus.subscribe("cli.dev", async (evt) => {
7033
+ if (evt.properties.stage !== project.config.stage)
7034
+ return;
7035
+ if (evt.properties.app !== project.config.name)
7036
+ return;
7037
+ Colors2.line(
7038
+ Colors2.danger(`\u279C `),
7039
+ "Another sst dev session has been started up for this stage. Exiting"
7040
+ );
7041
+ process.exit(0);
7042
+ });
7043
+ });
6988
7044
  const [appMetadata] = await Promise.all([
6989
7045
  useAppMetadata2(),
6990
7046
  useLocalServer2({
@@ -7001,6 +7057,7 @@ var dev = (program2) => program2.command(
7001
7057
  clear2();
7002
7058
  await printHeader2({ console: true, hint: "ready!" });
7003
7059
  await Promise.all([
7060
+ useDisconnector(),
7004
7061
  useRuntimeWorkers2(),
7005
7062
  useIOTBridge2(),
7006
7063
  useRuntimeServer2(),
@@ -30082,7 +30082,7 @@ var require_StandardRetryStrategy = __commonJS({
30082
30082
  var config_1 = require_config2();
30083
30083
  var constants_1 = require_constants3();
30084
30084
  var defaultRetryToken_1 = require_defaultRetryToken();
30085
- var StandardRetryStrategy = class {
30085
+ var StandardRetryStrategy2 = class {
30086
30086
  constructor(maxAttemptsProvider) {
30087
30087
  this.maxAttemptsProvider = maxAttemptsProvider;
30088
30088
  this.mode = config_1.RETRY_MODES.STANDARD;
@@ -30120,8 +30120,8 @@ var require_StandardRetryStrategy = __commonJS({
30120
30120
  return errorType === "THROTTLING" || errorType === "TRANSIENT";
30121
30121
  }
30122
30122
  };
30123
- __name(StandardRetryStrategy, "StandardRetryStrategy");
30124
- exports.StandardRetryStrategy = StandardRetryStrategy;
30123
+ __name(StandardRetryStrategy2, "StandardRetryStrategy");
30124
+ exports.StandardRetryStrategy = StandardRetryStrategy2;
30125
30125
  }
30126
30126
  });
30127
30127
 
@@ -30283,7 +30283,7 @@ var require_StandardRetryStrategy2 = __commonJS({
30283
30283
  var delayDecider_1 = require_delayDecider();
30284
30284
  var retryDecider_1 = require_retryDecider();
30285
30285
  var util_1 = require_util();
30286
- var StandardRetryStrategy = class {
30286
+ var StandardRetryStrategy2 = class {
30287
30287
  constructor(maxAttemptsProvider, options) {
30288
30288
  var _a, _b, _c;
30289
30289
  this.maxAttemptsProvider = maxAttemptsProvider;
@@ -30351,8 +30351,8 @@ var require_StandardRetryStrategy2 = __commonJS({
30351
30351
  }
30352
30352
  }
30353
30353
  };
30354
- __name(StandardRetryStrategy, "StandardRetryStrategy");
30355
- exports.StandardRetryStrategy = StandardRetryStrategy;
30354
+ __name(StandardRetryStrategy2, "StandardRetryStrategy");
30355
+ exports.StandardRetryStrategy = StandardRetryStrategy2;
30356
30356
  var getDelayFromRetryAfterHeader = /* @__PURE__ */ __name((response) => {
30357
30357
  if (!protocol_http_1.HttpResponse.isInstance(response))
30358
30358
  return;
@@ -103057,7 +103057,7 @@ var require_StandardRetryStrategy3 = __commonJS({
103057
103057
  var defaultRetryQuota_1 = require_defaultRetryQuota2();
103058
103058
  var delayDecider_1 = require_delayDecider2();
103059
103059
  var retryDecider_1 = require_retryDecider2();
103060
- var StandardRetryStrategy = class {
103060
+ var StandardRetryStrategy2 = class {
103061
103061
  constructor(maxAttemptsProvider, options) {
103062
103062
  var _a, _b, _c;
103063
103063
  this.maxAttemptsProvider = maxAttemptsProvider;
@@ -103125,8 +103125,8 @@ var require_StandardRetryStrategy3 = __commonJS({
103125
103125
  }
103126
103126
  }
103127
103127
  };
103128
- __name(StandardRetryStrategy, "StandardRetryStrategy");
103129
- exports.StandardRetryStrategy = StandardRetryStrategy;
103128
+ __name(StandardRetryStrategy2, "StandardRetryStrategy");
103129
+ exports.StandardRetryStrategy = StandardRetryStrategy2;
103130
103130
  var getDelayFromRetryAfterHeader = /* @__PURE__ */ __name((response) => {
103131
103131
  if (!protocol_http_1.HttpResponse.isInstance(response))
103132
103132
  return;
@@ -164635,7 +164635,22 @@ __name(wait, "wait");
164635
164635
  // support/custom-resources/apigateway-cloudwatch-role.ts
164636
164636
  var import_client_api_gateway = __toESM(require_dist_cjs111(), 1);
164637
164637
  var import_client_iam = __toESM(require_dist_cjs112(), 1);
164638
- var apig = new import_client_api_gateway.APIGatewayClient({ logger: console });
164638
+ var import_middleware_retry = __toESM(require_dist_cjs17(), 1);
164639
+ var apig = new import_client_api_gateway.APIGatewayClient({
164640
+ logger: console,
164641
+ retryStrategy: new import_middleware_retry.StandardRetryStrategy(async () => 1e4, {
164642
+ retryDecider: (e) => {
164643
+ if (e.name === "TooManyRequestsException" && e.message === "Too Many Requests") {
164644
+ console.log("Retry on error", e.name);
164645
+ return true;
164646
+ }
164647
+ return false;
164648
+ },
164649
+ delayDecider: (_, attempts) => {
164650
+ return Math.min(1.5 ** attempts * 100, 3e3);
164651
+ }
164652
+ })
164653
+ });
164639
164654
  var iam = new import_client_iam.IAMClient({ logger: console });
164640
164655
  async function ApiGatewayCloudWatchRole(cfnRequest) {
164641
164656
  switch (cfnRequest.RequestType) {
@@ -164702,17 +164717,28 @@ async function createRole(roleName) {
164702
164717
  __name(createRole, "createRole");
164703
164718
  async function attachRoleToApiGateway(roleArn) {
164704
164719
  console.log("attachRoleToApiGateway");
164705
- await apig.send(
164706
- new import_client_api_gateway.UpdateAccountCommand({
164707
- patchOperations: [
164708
- {
164709
- op: "replace",
164710
- path: "/cloudwatchRoleArn",
164711
- value: roleArn
164712
- }
164713
- ]
164714
- })
164715
- );
164720
+ try {
164721
+ await apig.send(
164722
+ new import_client_api_gateway.UpdateAccountCommand({
164723
+ patchOperations: [
164724
+ {
164725
+ op: "replace",
164726
+ path: "/cloudwatchRoleArn",
164727
+ value: roleArn
164728
+ }
164729
+ ]
164730
+ })
164731
+ );
164732
+ } catch (e) {
164733
+ console.log(e);
164734
+ if (e.name === "BadRequestException" && e.message === "The role ARN does not have required permissions configured. Please grant trust permission for API Gateway and add the required role policy.") {
164735
+ console.log("Retry after 1 second");
164736
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
164737
+ await attachRoleToApiGateway(roleArn);
164738
+ return;
164739
+ }
164740
+ throw e;
164741
+ }
164716
164742
  }
164717
164743
  __name(attachRoleToApiGateway, "attachRoleToApiGateway");
164718
164744
 
@@ -9,9 +9,9 @@ installGlobals();
9
9
  import {
10
10
  Headers as NodeHeaders,
11
11
  Request as NodeRequest,
12
+ createRequestHandler as createNodeRequestHandler,
12
13
  readableStreamToString,
13
14
  } from "@remix-run/node";
14
- import { createRequestHandler as createRemixRequestHandler } from "@remix-run/server-runtime";
15
15
  import { URL } from "url";
16
16
 
17
17
  // Import the server build that was produced by `remix build`;
@@ -146,7 +146,7 @@ async function convertNodeResponseToCf(nodeResponse) {
146
146
  }
147
147
 
148
148
  function createCfHandler(build) {
149
- const requestHandler = createRemixRequestHandler(build, process.env.NODE_ENV);
149
+ const requestHandler = createNodeRequestHandler(build, process.env.NODE_ENV);
150
150
 
151
151
  return async (event) => {
152
152
  const request = convertCfRequestToNode(event);