sst 2.30.3 → 2.31.0

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.
@@ -1,7 +1,7 @@
1
1
  import path from "path";
2
2
  import url from "url";
3
3
  import fs from "fs";
4
- import glob from "glob";
4
+ import { globSync } from "glob";
5
5
  import crypto from "crypto";
6
6
  import spawn from "cross-spawn";
7
7
  import { execSync } from "child_process";
@@ -12,7 +12,6 @@ import { Effect, Role, Policy, PolicyStatement, AccountPrincipal, ServicePrincip
12
12
  import { Function as CdkFunction, Code, Runtime, FunctionUrlAuthType, InvokeMode, } from "aws-cdk-lib/aws-lambda";
13
13
  import { Asset } from "aws-cdk-lib/aws-s3-assets";
14
14
  import { ViewerProtocolPolicy, AllowedMethods, CachedMethods, LambdaEdgeEventType, CachePolicy, CacheQueryStringBehavior, CacheHeaderBehavior, CacheCookieBehavior, OriginRequestPolicy, Function as CfFunction, FunctionCode as CfFunctionCode, FunctionEventType as CfFunctionEventType, } from "aws-cdk-lib/aws-cloudfront";
15
- import { AwsCliLayer } from "aws-cdk-lib/lambda-layer-awscli";
16
15
  import { S3Origin, HttpOrigin, OriginGroup, } from "aws-cdk-lib/aws-cloudfront-origins";
17
16
  import { Rule, Schedule } from "aws-cdk-lib/aws-events";
18
17
  import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
@@ -67,10 +66,11 @@ export class SsrSite extends Construct {
67
66
  const app = scope.node.root;
68
67
  const stack = Stack.of(this);
69
68
  const self = this;
70
- const { path: sitePath, typesPath, buildCommand, runtime, timeout, memorySize, edge, regional, dev, cache, nodejs, permissions, environment, bind, customDomain, waitForInvalidation, fileOptions, warm, cdk, } = props;
69
+ const { path: sitePath, typesPath, buildCommand, runtime, timeout, memorySize, edge, regional, dev, assets, nodejs, permissions, environment, bind, customDomain, waitForInvalidation, warm, cdk, } = props;
71
70
  this.doNotDeploy = !stack.isActive || (app.mode === "dev" && !dev?.deploy);
72
71
  validateSiteExists();
73
72
  validateTimeout();
73
+ validateDeprecatedFileOptions();
74
74
  writeTypesFile(typesPath);
75
75
  useSites().add(stack.stackName, id, this.constructor.name, props);
76
76
  if (this.doNotDeploy) {
@@ -82,7 +82,6 @@ export class SsrSite extends Construct {
82
82
  }
83
83
  let s3DeployCRs = [];
84
84
  let ssrFunctions = [];
85
- let singletonAwsCliLayer;
86
85
  let singletonUrlSigner;
87
86
  let singletonCachePolicy;
88
87
  let singletonOriginRequestPolicy;
@@ -110,7 +109,7 @@ export class SsrSite extends Construct {
110
109
  app.registerTypes(this);
111
110
  function validateSiteExists() {
112
111
  if (!fs.existsSync(sitePath)) {
113
- throw new Error(`No site found at "${path.resolve(sitePath)}"`);
112
+ throw new VisibleError(`No site found at "${path.resolve(sitePath)}"`);
114
113
  }
115
114
  }
116
115
  function validateTimeout() {
@@ -119,9 +118,15 @@ export class SsrSite extends Construct {
119
118
  : toCdkDuration(timeout).toSeconds();
120
119
  const limit = edge ? 30 : 180;
121
120
  if (num > limit) {
122
- throw new Error(edge
123
- ? `Timeout must be less than or equal to 30 seconds when the "edge" flag is enabled.`
124
- : `Timeout must be less than or equal to 180 seconds.`);
121
+ throw new VisibleError(edge
122
+ ? `In the "${id}" construct, timeout must be less than or equal to 30 seconds when the "edge" flag is enabled.`
123
+ : `In the "${id}" construct, timeout must be less than or equal to 180 seconds.`);
124
+ }
125
+ }
126
+ function validateDeprecatedFileOptions() {
127
+ // @ts-expect-error
128
+ if (props.fileOptions) {
129
+ throw new VisibleError(`In the "${id}" construct, the "fileOptions" property has been replaced by "assets.fileOptions". More details on upgrading - https://docs.sst.dev/upgrade-guide#upgrade-to-v2310`);
125
130
  }
126
131
  }
127
132
  function writeTypesFile(typesPath) {
@@ -411,8 +416,7 @@ function handler(event) {
411
416
  originPath: "/" + (props.originPath ?? ""),
412
417
  });
413
418
  const assets = createS3OriginAssets(props.copy);
414
- const assetFileOptions = fileOptions || createS3OriginAssetFileOptions(props.copy, cache);
415
- const s3deployCR = createS3OriginDeployment(assets, assetFileOptions);
419
+ const s3deployCR = createS3OriginDeployment(props.copy, assets);
416
420
  s3DeployCRs.push(s3deployCR);
417
421
  return s3Origin;
418
422
  }
@@ -562,185 +566,44 @@ function handler(event) {
562
566
  }
563
567
  return assets;
564
568
  }
565
- function createS3OriginAssetFileOptions(copy, cache) {
566
- const fileOptions = [];
567
- const textEncoding = cache?.textEncoding ?? "UTF-8";
568
- const nonVersionedFilesTTL = typeof cache?.nonVersionedFilesTTL === "number"
569
- ? cache.nonVersionedFilesTTL
570
- : toCdkDuration(cache?.nonVersionedFilesTTL ?? "1 day").toSeconds();
571
- const staleWhileRevalidateTTL = Math.max(Math.floor(nonVersionedFilesTTL / 10), 30);
572
- const nonVersionedFilesCacheHeader = cache?.nonVersionedFilesCacheHeader ??
573
- `public,max-age=0,s-maxage=${nonVersionedFilesTTL},stale-while-revalidate=${staleWhileRevalidateTTL}`;
574
- const versionedFilesTTL = typeof cache?.versionedFilesTTL === "number"
575
- ? cache.versionedFilesTTL
576
- : toCdkDuration(cache?.versionedFilesTTL ?? "365 days").toSeconds();
577
- const versionedFilesCacheHeader = cache?.versionedFilesCacheHeader ??
578
- `public,max-age=${versionedFilesTTL},immutable`;
579
- const commonWebFileExtensions = {
580
- txt: { mime: "text/plain", isText: true },
581
- htm: { mime: "text/html", isText: true },
582
- html: { mime: "text/html", isText: true },
583
- xhtml: { mime: "application/xhtml+xml", isText: true },
584
- css: { mime: "text/css", isText: true },
585
- js: { mime: "text/javascript", isText: true },
586
- mjs: { mime: "text/javascript", isText: true },
587
- apng: { mime: "image/apng", isText: false },
588
- avif: { mime: "image/avif", isText: false },
589
- gif: { mime: "image/gif", isText: false },
590
- jpeg: { mime: "image/jpeg", isText: false },
591
- jpg: { mime: "image/jpeg", isText: false },
592
- png: { mime: "image/png", isText: false },
593
- svg: { mime: "image/svg+xml", isText: true },
594
- bmp: { mime: "image/bmp", isText: false },
595
- tiff: { mime: "image/tiff", isText: false },
596
- webp: { mime: "image/webp", isText: false },
597
- ico: { mime: "image/vnd.microsoft.icon", isText: false },
598
- eot: { mime: "application/vnd.ms-fontobject", isText: false },
599
- ttf: { mime: "font/ttf", isText: false },
600
- otf: { mime: "font/otf", isText: false },
601
- woff: { mime: "font/woff", isText: false },
602
- woff2: { mime: "font/woff2", isText: false },
603
- json: { mime: "application/json", isText: true },
604
- jsonld: { mime: "application/ld+json", isText: true },
605
- xml: { mime: "application/xml", isText: true },
606
- pdf: { mime: "application/pdf", isText: false },
607
- zip: { mime: "application/zip", isText: false },
608
- };
609
- copy.forEach((files) => {
610
- if (!files.cached)
611
- return;
612
- for (const [extension, contentType] of Object.entries(commonWebFileExtensions)) {
613
- // Create a file option for: common extension + unversioned files
614
- fileOptions.push({
615
- filters: [
616
- { exclude: "*" },
617
- { include: `${path.posix.join(files.to, "*")}.${extension}` },
618
- ...(files.versionedSubDir
619
- ? [
620
- {
621
- exclude: path.posix.join(files.to, files.versionedSubDir, "*"),
622
- },
623
- ]
624
- : []),
625
- ],
626
- cacheControl: nonVersionedFilesCacheHeader,
627
- contentType: `${contentType.mime}${contentType.isText && textEncoding !== "none"
628
- ? `;charset=${textEncoding}`
629
- : ""}`,
630
- });
631
- // Create a file option for: common extension + versioned files
632
- if (files.versionedSubDir) {
633
- fileOptions.push({
634
- filters: [
635
- { exclude: "*" },
636
- {
637
- include: path.posix.join(files.to, files.versionedSubDir, `*.${extension}`),
638
- },
639
- ],
640
- cacheControl: versionedFilesCacheHeader,
641
- contentType: `${contentType.mime}${contentType.isText && textEncoding !== "none"
642
- ? `;charset=${textEncoding}`
643
- : ""}`,
644
- });
645
- }
646
- }
647
- // Create a file option for: other extensions + unversioned files
648
- fileOptions.push({
649
- filters: [
650
- { include: "*" },
651
- ...(files.versionedSubDir
652
- ? [
653
- {
654
- exclude: path.posix.join(files.to, files.versionedSubDir, "*"),
655
- },
656
- ]
657
- : []),
658
- ...Object.entries(commonWebFileExtensions).map(([ext]) => ({
659
- exclude: `*.${ext}`,
660
- })),
661
- ],
662
- cacheControl: nonVersionedFilesCacheHeader,
663
- });
664
- // Create a file option for: other extensions + versioned files
665
- if (files.versionedSubDir) {
666
- fileOptions.push({
667
- filters: [
668
- {
669
- include: path.posix.join(files.to, files.versionedSubDir, "*"),
670
- },
671
- ...Object.entries(commonWebFileExtensions).map(([ext]) => ({
672
- exclude: `*.${ext}`,
673
- })),
674
- ],
675
- cacheControl: versionedFilesCacheHeader,
676
- });
677
- }
678
- });
679
- if (cache?.fileOptions) {
680
- fileOptions.push(...cache.fileOptions);
681
- }
682
- return fileOptions;
683
- }
684
- function createS3OriginDeployment(assets, fileOptions) {
685
- // Create a Lambda function that will be doing the uploading
686
- const uploader = new CdkFunction(self, "S3Uploader", {
687
- code: Code.fromAsset(path.join(__dirname, "../support/base-site-custom-resource")),
688
- layers: [useAwsCliLayer()],
689
- runtime: Runtime.PYTHON_3_11,
690
- handler: "s3-upload.handler",
691
- timeout: CdkDuration.minutes(15),
692
- memorySize: 1024,
693
- });
694
- bucket.grantReadWrite(uploader);
695
- assets.forEach((asset) => asset.grantRead(uploader));
696
- // Create the custom resource function
697
- const handler = new CdkFunction(self, "S3Handler", {
698
- code: Code.fromAsset(path.join(__dirname, "../support/base-site-custom-resource")),
699
- layers: [useAwsCliLayer()],
700
- runtime: Runtime.PYTHON_3_11,
701
- handler: "s3-handler.handler",
702
- timeout: CdkDuration.minutes(15),
703
- memorySize: 1024,
704
- environment: {
705
- UPLOADER_FUNCTION_NAME: uploader.functionName,
706
- },
569
+ function createS3OriginDeployment(copy, s3Assets) {
570
+ const policy = new Policy(self, "S3UploaderPolicy", {
571
+ statements: [
572
+ new PolicyStatement({
573
+ effect: Effect.ALLOW,
574
+ actions: ["lambda:InvokeFunction"],
575
+ resources: [stack.customResourceHandler.functionArn],
576
+ }),
577
+ new PolicyStatement({
578
+ effect: Effect.ALLOW,
579
+ actions: ["s3:ListBucket", "s3:PutObject", "s3:DeleteObject"],
580
+ resources: [bucket.bucketArn, `${bucket.bucketArn}/*`],
581
+ }),
582
+ new PolicyStatement({
583
+ effect: Effect.ALLOW,
584
+ actions: ["s3:GetObject"],
585
+ resources: [`${s3Assets[0].bucket.bucketArn}/*`],
586
+ }),
587
+ ],
707
588
  });
708
- bucket.grantReadWrite(handler);
709
- uploader.grantInvoke(handler);
710
- // Create custom resource
711
- return new CustomResource(self, "S3Deployment", {
712
- serviceToken: handler.functionArn,
713
- resourceType: "Custom::SSTBucketDeployment",
589
+ stack.customResourceHandler.role?.attachInlinePolicy(policy);
590
+ const resource = new CustomResource(self, "S3Uploader", {
591
+ serviceToken: stack.customResourceHandler.functionArn,
592
+ resourceType: "Custom::S3Uploader",
714
593
  properties: {
715
- Sources: assets.map((asset) => ({
716
- BucketName: asset.s3BucketName,
717
- ObjectKey: asset.s3ObjectKey,
594
+ sources: s3Assets.map((s3Asset) => ({
595
+ bucketName: s3Asset.s3BucketName,
596
+ objectKey: s3Asset.s3ObjectKey,
718
597
  })),
719
- DestinationBucketName: bucket.bucketName,
720
- FileOptions: (fileOptions || []).map((o) => {
721
- const { filters, cacheControl, contentType, contentEncoding } = o;
722
- const { include, exclude } = o;
723
- return [
724
- ...(typeof exclude === "string" ? [exclude] : exclude ?? [])
725
- .map((entry) => ["--exclude", entry])
726
- .flat(2),
727
- ...(typeof include === "string" ? [include] : include ?? [])
728
- .map((entry) => ["--include", entry])
729
- .flat(2),
730
- ...(filters || [])
731
- .map((filter) => Object.entries(filter).map(([key, value]) => [
732
- `--${key}`,
733
- value,
734
- ]))
735
- .flat(2),
736
- cacheControl ? ["--cache-control", cacheControl] : [],
737
- contentType ? ["--content-type", contentType] : [],
738
- contentEncoding ? ["--content-encoding", contentEncoding] : [],
739
- ].flat();
740
- }),
741
- ReplaceValues: getS3ContentReplaceValues(),
598
+ destinationBucketName: bucket.bucketName,
599
+ concurrency: assets?._uploadConcurrency,
600
+ textEncoding: assets?.textEncoding ?? "utf-8",
601
+ fileOptions: getS3FileOptions(copy),
602
+ replaceValues: getS3ContentReplaceValues(),
742
603
  },
743
604
  });
605
+ resource.node.addDependency(policy);
606
+ return resource;
744
607
  }
745
608
  function useFunctionUrlSigningFunction() {
746
609
  singletonUrlSigner =
@@ -768,10 +631,40 @@ function handler(event) {
768
631
  OriginRequestPolicy.fromOriginRequestPolicyId(self, "ServerOriginRequestPolicy", "b689b0a8-53d0-40ab-baf2-68738e2966ac");
769
632
  return singletonOriginRequestPolicy;
770
633
  }
771
- function useAwsCliLayer() {
772
- singletonAwsCliLayer =
773
- singletonAwsCliLayer ?? new AwsCliLayer(self, "AwsCliLayer");
774
- return singletonAwsCliLayer;
634
+ function getS3FileOptions(copy) {
635
+ const fileOptions = [];
636
+ const nonVersionedFilesTTL = typeof assets?.nonVersionedFilesTTL === "number"
637
+ ? assets.nonVersionedFilesTTL
638
+ : toCdkDuration(assets?.nonVersionedFilesTTL ?? "1 day").toSeconds();
639
+ const staleWhileRevalidateTTL = Math.max(Math.floor(nonVersionedFilesTTL / 10), 30);
640
+ const versionedFilesTTL = typeof assets?.versionedFilesTTL === "number"
641
+ ? assets.versionedFilesTTL
642
+ : toCdkDuration(assets?.versionedFilesTTL ?? "365 days").toSeconds();
643
+ copy.forEach(({ cached, to, versionedSubDir }) => {
644
+ if (!cached)
645
+ return;
646
+ // Create a default file option for: unversioned files
647
+ fileOptions.push({
648
+ files: "**",
649
+ ignore: versionedSubDir
650
+ ? path.posix.join(to, versionedSubDir, "**")
651
+ : undefined,
652
+ cacheControl: assets?.nonVersionedFilesCacheHeader ??
653
+ `public,max-age=0,s-maxage=${nonVersionedFilesTTL},stale-while-revalidate=${staleWhileRevalidateTTL}`,
654
+ });
655
+ // Create a default file option for: versioned files
656
+ if (versionedSubDir) {
657
+ fileOptions.push({
658
+ files: path.posix.join(to, versionedSubDir, "**"),
659
+ cacheControl: assets?.versionedFilesCacheHeader ??
660
+ `public,max-age=${versionedFilesTTL},immutable`,
661
+ });
662
+ }
663
+ });
664
+ if (assets?.fileOptions) {
665
+ fileOptions.push(...assets.fileOptions);
666
+ }
667
+ return fileOptions;
775
668
  }
776
669
  function getS3ContentReplaceValues() {
777
670
  const replaceValues = [];
@@ -796,7 +689,7 @@ function handler(event) {
796
689
  return replaceValues;
797
690
  }
798
691
  function createDistributionInvalidation() {
799
- const cdnInvalidationStrategy = cache?.cdnInvalidationStrategy ?? "all";
692
+ const cdnInvalidationStrategy = assets?.cdnInvalidationStrategy ?? "all";
800
693
  if (cdnInvalidationStrategy === "never")
801
694
  return;
802
695
  if (plan.buildId) {
@@ -833,31 +726,26 @@ function handler(event) {
833
726
  // The below options are needed to support following symlinks when building zip files:
834
727
  // - nodir: This will prevent symlinks themselves from being copied into the zip.
835
728
  // - follow: This will follow symlinks and copy the files within.
836
- const globOptions = {
837
- dot: true,
838
- nodir: true,
839
- follow: true,
840
- cwd: path.resolve(sitePath, item.from),
841
- };
842
729
  // For versioned files, use file path for digest since file version in name should change on content change
843
730
  if (item.versionedSubDir) {
844
- glob
845
- .sync("**", {
846
- ...globOptions,
731
+ globSync("**", {
732
+ dot: true,
733
+ nodir: true,
734
+ follow: true,
847
735
  cwd: path.resolve(sitePath, item.from, item.versionedSubDir),
848
- })
849
- .forEach((filePath) => hash.update(filePath));
736
+ }).forEach((filePath) => hash.update(filePath));
850
737
  }
851
738
  // For non-versioned files, use file content for digest
852
739
  if (cdnInvalidationStrategy === "all") {
853
- glob
854
- .sync("**", {
855
- ...globOptions,
740
+ globSync("**", {
856
741
  ignore: item.versionedSubDir
857
742
  ? [path.posix.join(item.versionedSubDir, "**")]
858
743
  : undefined,
859
- })
860
- .forEach((filePath) => hash.update(fs.readFileSync(path.resolve(sitePath, item.from, filePath))));
744
+ dot: true,
745
+ nodir: true,
746
+ follow: true,
747
+ cwd: path.resolve(sitePath, item.from),
748
+ }).forEach((filePath) => hash.update(fs.readFileSync(path.resolve(sitePath, item.from, filePath))));
861
749
  }
862
750
  });
863
751
  const buildId = hash.digest("hex");
@@ -2,7 +2,7 @@ import { Construct } from "constructs";
2
2
  import { Bucket, BucketProps, IBucket } from "aws-cdk-lib/aws-s3";
3
3
  import { IDistribution } from "aws-cdk-lib/aws-cloudfront";
4
4
  import { DistributionDomainProps } from "./Distribution.js";
5
- import { BaseSiteFileOptions, BaseSiteFileOptionsFilter, BaseSiteReplaceProps, BaseSiteCdkDistributionProps, BaseSiteFileOptionsDeprecated } from "./BaseSite.js";
5
+ import { BaseSiteFileOptions, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
6
6
  import { SSTConstruct } from "./Construct.js";
7
7
  import { FunctionBindingProps } from "./util/functionBinding.js";
8
8
  export interface StaticSiteProps {
@@ -67,33 +67,6 @@ export interface StaticSiteProps {
67
67
  * ```
68
68
  */
69
69
  buildOutput?: string;
70
- /**
71
- * Pass in a list of file options to configure cache control for different files. Behind the scenes, the `StaticSite` construct uses a combination of the `s3 cp` and `s3 sync` commands to upload the website content to the S3 bucket. An `s3 cp` command is run for each file option block, and the options are passed in as the command options.
72
- * @default No cache control for HTML files, and a 1 year cache control for JS/CSS files.
73
- * ```js
74
- * [
75
- * {
76
- * filters: [{ exclude: "*" }, { include: "*.html" }],
77
- * cacheControl: "max-age=0,no-cache,no-store,must-revalidate",
78
- * },
79
- * {
80
- * filters: [{ exclude: "*" }, { include: "*.js" }, { include: "*.css" }],
81
- * cacheControl: "max-age=31536000,public,immutable",
82
- * },
83
- * ]
84
- * ```
85
- * @example
86
- * ```js
87
- * new StaticSite(stack, "Site", {
88
- * buildOutput: "dist",
89
- * fileOptions: [{
90
- * filters: [{ exclude: "*" }, { include: "*.js" }],
91
- * cacheControl: "max-age=31536000,public,immutable",
92
- * }]
93
- * });
94
- * ```
95
- */
96
- fileOptions?: StaticSiteFileOptions[] | StaticSiteFileOptionsDeprecated[];
97
70
  /**
98
71
  * Pass in a list of placeholder values to be replaced in the website content. For example, the follow configuration:
99
72
  *
@@ -169,6 +142,50 @@ export interface StaticSiteProps {
169
142
  * ```
170
143
  */
171
144
  purgeFiles?: boolean;
145
+ assets?: {
146
+ /**
147
+ * Character encoding for text based assets uploaded to S3 (ex: html, css, js, etc.). If "none" is specified, no charset will be returned in header.
148
+ * @default utf-8
149
+ * @example
150
+ * ```js
151
+ * assets: {
152
+ * textEncoding: "iso-8859-1"
153
+ * }
154
+ * ```
155
+ */
156
+ textEncoding?: "utf-8" | "iso-8859-1" | "windows-1252" | "ascii" | "none";
157
+ /**
158
+ * Pass in a list of file options to configure cache control for different files. Behind the scenes, the `StaticSite` construct uses a combination of the `s3 cp` and `s3 sync` commands to upload the website content to the S3 bucket. An `s3 cp` command is run for each file option block, and the options are passed in as the command options.
159
+ * @default No cache control for HTML files, and a 1 year cache control for JS/CSS files.
160
+ * ```js
161
+ * assets: {
162
+ * fileOptions: [
163
+ * {
164
+ * files: "**",
165
+ * cacheControl: "max-age=0,no-cache,no-store,must-revalidate",
166
+ * },
167
+ * {
168
+ * files: "**\/*.{js,css}",
169
+ * cacheControl: "max-age=31536000,public,immutable",
170
+ * },
171
+ * ],
172
+ * }
173
+ * ```
174
+ * @example
175
+ * ```js
176
+ * assets: {
177
+ * fileOptions: [
178
+ * {
179
+ * files: "**\/*.zip",
180
+ * cacheControl: "private,no-cache,no-store,must-revalidate",
181
+ * contentType: "application/zip",
182
+ * },
183
+ * ],
184
+ * }
185
+ * ```
186
+ */
187
+ fileOptions?: StaticSiteFileOptions[];
188
+ };
172
189
  dev?: {
173
190
  /**
174
191
  * When running `sst dev, site is not deployed. This is to ensure `sst dev` can start up quickly.
@@ -263,12 +280,7 @@ export interface StaticSiteProps {
263
280
  }
264
281
  export interface StaticSiteDomainProps extends DistributionDomainProps {
265
282
  }
266
- export interface StaticSiteFileOptionsFilter extends BaseSiteFileOptionsFilter {
267
- }
268
283
  export interface StaticSiteFileOptions extends BaseSiteFileOptions {
269
- filters: StaticSiteFileOptionsFilter[];
270
- }
271
- export interface StaticSiteFileOptionsDeprecated extends BaseSiteFileOptionsDeprecated {
272
284
  }
273
285
  export interface StaticSiteReplaceProps extends BaseSiteReplaceProps {
274
286
  }
@@ -327,6 +339,7 @@ export declare class StaticSite extends Construct implements SSTConstruct {
327
339
  };
328
340
  /** @internal */
329
341
  getFunctionBinding(): FunctionBindingProps;
342
+ private validateDeprecatedFileOptions;
330
343
  private generateViteTypes;
331
344
  private buildApp;
332
345
  private createS3Assets;