effortless-aws 0.15.0 → 0.16.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.
package/dist/cli/index.js CHANGED
@@ -72096,6 +72096,13 @@ var syncFiles = (input) => Effect_exports.gen(function* () {
72096
72096
  yield* Effect_exports.logDebug(`S3 sync: ${uploaded} uploaded, ${deleted} deleted, ${unchanged} unchanged`);
72097
72097
  return { uploaded, deleted, unchanged };
72098
72098
  });
72099
+ var putObject = (input) => s3_exports.make("put_object", {
72100
+ Bucket: input.bucketName,
72101
+ Key: input.key,
72102
+ Body: typeof input.body === "string" ? Buffer.from(input.body) : input.body,
72103
+ ContentType: input.contentType,
72104
+ CacheControl: input.cacheControl ?? "public, max-age=0, must-revalidate"
72105
+ });
72099
72106
  var putBucketPolicyForOAC = (bucketName, distributionArn) => Effect_exports.gen(function* () {
72100
72107
  const policy = JSON.stringify({
72101
72108
  Version: "2012-10-17",
@@ -72232,6 +72239,9 @@ var findCertificate = (domain) => Effect_exports.gen(function* () {
72232
72239
 
72233
72240
  // src/aws/cloudfront.ts
72234
72241
  var CACHING_OPTIMIZED_POLICY_ID = "658327ea-f89d-4fab-a63d-7e88639e58f6";
72242
+ var CACHING_DISABLED_POLICY_ID = "4135ea2d-bfcb-4884-b0c3-f7c1dc6e36b4";
72243
+ var ALL_VIEWER_EXCEPT_HOST_HEADER_POLICY_ID = "b689b0a8-53d0-40ab-baf2-68738e2966ac";
72244
+ var SECURITY_HEADERS_POLICY_ID = "67f7725c-6f97-4210-82d7-5512b31e9d03";
72235
72245
  var ensureOAC = (input) => Effect_exports.gen(function* () {
72236
72246
  const { name } = input;
72237
72247
  const result = yield* cloudfront_exports.make("list_origin_access_controls", {});
@@ -72330,7 +72340,7 @@ var ensureViewerRequestFunction = (name, config2) => Effect_exports.gen(function
72330
72340
  });
72331
72341
  var makeDistComment = (project2, stage, handlerName) => `effortless: ${project2}/${stage}/${handlerName}`;
72332
72342
  var ensureDistribution = (input) => Effect_exports.gen(function* () {
72333
- const { project: project2, stage, handlerName, bucketName, bucketRegion, oacId, spa, index, tags: tags2, urlRewriteFunctionArn, lambdaEdgeArn, aliases, acmCertificateArn } = input;
72343
+ const { project: project2, stage, handlerName, bucketName, bucketRegion, oacId, spa, index, tags: tags2, urlRewriteFunctionArn, lambdaEdgeArn, aliases, acmCertificateArn, apiOriginDomain, routePatterns } = input;
72334
72344
  const aliasesConfig = aliases && aliases.length > 0 ? { Quantity: aliases.length, Items: aliases } : { Quantity: 0, Items: [] };
72335
72345
  const viewerCertificate = acmCertificateArn ? {
72336
72346
  ACMCertificateArn: acmCertificateArn,
@@ -72340,8 +72350,51 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72340
72350
  const functionAssociations = !lambdaEdgeArn && urlRewriteFunctionArn ? { Quantity: 1, Items: [{ FunctionARN: urlRewriteFunctionArn, EventType: "viewer-request" }] } : { Quantity: 0, Items: [] };
72341
72351
  const lambdaFunctionAssociations = lambdaEdgeArn ? { Quantity: 1, Items: [{ EventType: "viewer-request", LambdaFunctionARN: lambdaEdgeArn, IncludeBody: false }] } : { Quantity: 0, Items: [] };
72342
72352
  const comment = makeDistComment(project2, stage, handlerName);
72343
- const originId = `S3-${bucketName}`;
72344
- const originDomain = `${bucketName}.s3.${bucketRegion}.amazonaws.com`;
72353
+ const s3OriginId = `S3-${bucketName}`;
72354
+ const s3OriginDomain = `${bucketName}.s3.${bucketRegion}.amazonaws.com`;
72355
+ const hasApiRoutes = apiOriginDomain && routePatterns && routePatterns.length > 0;
72356
+ const apiOriginId = hasApiRoutes ? `API-${project2}-${stage}` : void 0;
72357
+ const originsItems = [
72358
+ {
72359
+ Id: s3OriginId,
72360
+ DomainName: s3OriginDomain,
72361
+ OriginPath: "",
72362
+ OriginAccessControlId: oacId,
72363
+ S3OriginConfig: { OriginAccessIdentity: "" },
72364
+ CustomHeaders: { Quantity: 0, Items: [] }
72365
+ },
72366
+ ...hasApiRoutes ? [{
72367
+ Id: apiOriginId,
72368
+ DomainName: apiOriginDomain,
72369
+ OriginPath: "",
72370
+ CustomOriginConfig: {
72371
+ HTTPPort: 80,
72372
+ HTTPSPort: 443,
72373
+ OriginProtocolPolicy: "https-only",
72374
+ OriginSslProtocols: { Quantity: 1, Items: ["TLSv1.2"] }
72375
+ },
72376
+ CustomHeaders: { Quantity: 0, Items: [] }
72377
+ }] : []
72378
+ ];
72379
+ const API_METHODS = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"];
72380
+ const CACHED_METHODS = ["GET", "HEAD"];
72381
+ const cacheBehaviors = hasApiRoutes ? {
72382
+ Quantity: routePatterns.length,
72383
+ Items: routePatterns.map((pattern2) => ({
72384
+ PathPattern: pattern2,
72385
+ TargetOriginId: apiOriginId,
72386
+ ViewerProtocolPolicy: "redirect-to-https",
72387
+ AllowedMethods: {
72388
+ Quantity: 7,
72389
+ Items: [...API_METHODS],
72390
+ CachedMethods: { Quantity: 2, Items: [...CACHED_METHODS] }
72391
+ },
72392
+ Compress: true,
72393
+ CachePolicyId: CACHING_DISABLED_POLICY_ID,
72394
+ OriginRequestPolicyId: ALL_VIEWER_EXCEPT_HOST_HEADER_POLICY_ID
72395
+ }))
72396
+ } : { Quantity: 0, Items: [] };
72397
+ const { errorPagePath } = input;
72345
72398
  const customErrorResponses = spa ? {
72346
72399
  Quantity: 2,
72347
72400
  Items: [
@@ -72358,6 +72411,22 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72358
72411
  ErrorCachingMinTTL: 0
72359
72412
  }
72360
72413
  ]
72414
+ } : errorPagePath ? {
72415
+ Quantity: 2,
72416
+ Items: [
72417
+ {
72418
+ ErrorCode: 403,
72419
+ ResponseCode: "404",
72420
+ ResponsePagePath: errorPagePath,
72421
+ ErrorCachingMinTTL: 0
72422
+ },
72423
+ {
72424
+ ErrorCode: 404,
72425
+ ResponseCode: "404",
72426
+ ResponsePagePath: errorPagePath,
72427
+ ErrorCachingMinTTL: 0
72428
+ }
72429
+ ]
72361
72430
  } : { Quantity: 0, Items: [] };
72362
72431
  const existing = yield* findDistributionByTags(project2, stage, handlerName);
72363
72432
  if (existing) {
@@ -72373,7 +72442,12 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72373
72442
  const aliasesMatch = currentAliases.length === desiredAliases.length && desiredAliases.every((a) => currentAliases.includes(a));
72374
72443
  const certMatch = currentConfig.ViewerCertificate?.ACMCertificateArn === (acmCertificateArn ?? void 0);
72375
72444
  const currentLambdaEdgeArn = currentConfig.DefaultCacheBehavior?.LambdaFunctionAssociations?.Items?.[0]?.LambdaFunctionARN;
72376
- const needsUpdate = currentOrigin?.DomainName !== originDomain || currentOrigin?.OriginAccessControlId !== oacId || currentConfig.DefaultRootObject !== index || currentConfig.DefaultCacheBehavior?.CachePolicyId !== CACHING_OPTIMIZED_POLICY_ID || (currentConfig.CustomErrorResponses?.Quantity ?? 0) !== customErrorResponses.Quantity || (currentConfig.DefaultCacheBehavior?.FunctionAssociations?.Quantity ?? 0) !== functionAssociations.Quantity || currentConfig.DefaultCacheBehavior?.FunctionAssociations?.Items?.[0]?.FunctionARN !== (urlRewriteFunctionArn ?? void 0) || (currentConfig.DefaultCacheBehavior?.LambdaFunctionAssociations?.Quantity ?? 0) !== lambdaFunctionAssociations.Quantity || currentLambdaEdgeArn !== (lambdaEdgeArn ?? void 0) || !aliasesMatch || !certMatch;
72445
+ const originsMatch = (currentConfig.Origins?.Quantity ?? 0) === originsItems.length;
72446
+ const currentBehaviorPatterns = (currentConfig.CacheBehaviors?.Items ?? []).map((b) => b.PathPattern).sort();
72447
+ const desiredBehaviorPatterns = (routePatterns ?? []).slice().sort();
72448
+ const behaviorsMatch = currentBehaviorPatterns.length === desiredBehaviorPatterns.length && desiredBehaviorPatterns.every((p3, i) => currentBehaviorPatterns[i] === p3);
72449
+ const apiOriginMatch = !hasApiRoutes || currentConfig.Origins?.Items?.some((o) => o.DomainName === apiOriginDomain);
72450
+ const needsUpdate = currentOrigin?.DomainName !== s3OriginDomain || currentOrigin?.OriginAccessControlId !== oacId || currentConfig.DefaultRootObject !== index || currentConfig.DefaultCacheBehavior?.CachePolicyId !== CACHING_OPTIMIZED_POLICY_ID || currentConfig.DefaultCacheBehavior?.ResponseHeadersPolicyId !== SECURITY_HEADERS_POLICY_ID || (currentConfig.CustomErrorResponses?.Quantity ?? 0) !== customErrorResponses.Quantity || (currentConfig.DefaultCacheBehavior?.FunctionAssociations?.Quantity ?? 0) !== functionAssociations.Quantity || currentConfig.DefaultCacheBehavior?.FunctionAssociations?.Items?.[0]?.FunctionARN !== (urlRewriteFunctionArn ?? void 0) || (currentConfig.DefaultCacheBehavior?.LambdaFunctionAssociations?.Quantity ?? 0) !== lambdaFunctionAssociations.Quantity || currentLambdaEdgeArn !== (lambdaEdgeArn ?? void 0) || !aliasesMatch || !certMatch || !originsMatch || !behaviorsMatch || !apiOriginMatch;
72377
72451
  if (needsUpdate) {
72378
72452
  yield* Effect_exports.logDebug(`CloudFront distribution ${existing.Id} config changed, updating...`);
72379
72453
  const etag = configResult.ETag;
@@ -72384,21 +72458,12 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72384
72458
  ...currentConfig,
72385
72459
  Comment: comment,
72386
72460
  Origins: {
72387
- Quantity: 1,
72388
- Items: [
72389
- {
72390
- Id: originId,
72391
- DomainName: originDomain,
72392
- OriginPath: "",
72393
- OriginAccessControlId: oacId,
72394
- S3OriginConfig: { OriginAccessIdentity: "" },
72395
- CustomHeaders: { Quantity: 0, Items: [] }
72396
- }
72397
- ]
72461
+ Quantity: originsItems.length,
72462
+ Items: originsItems
72398
72463
  },
72399
72464
  DefaultCacheBehavior: {
72400
72465
  ...currentConfig.DefaultCacheBehavior,
72401
- TargetOriginId: originId,
72466
+ TargetOriginId: s3OriginId,
72402
72467
  ViewerProtocolPolicy: "redirect-to-https",
72403
72468
  AllowedMethods: {
72404
72469
  Quantity: 2,
@@ -72407,10 +72472,12 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72407
72472
  },
72408
72473
  Compress: true,
72409
72474
  CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
72475
+ ResponseHeadersPolicyId: SECURITY_HEADERS_POLICY_ID,
72410
72476
  FunctionAssociations: functionAssociations,
72411
72477
  LambdaFunctionAssociations: lambdaFunctionAssociations,
72412
72478
  ForwardedValues: void 0
72413
72479
  },
72480
+ CacheBehaviors: cacheBehaviors,
72414
72481
  Aliases: aliasesConfig,
72415
72482
  ...viewerCertificate ? { ViewerCertificate: viewerCertificate } : {},
72416
72483
  DefaultRootObject: index,
@@ -72436,18 +72503,11 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72436
72503
  CallerReference: `${project2}-${stage}-${handlerName}-${Date.now()}`,
72437
72504
  Comment: comment,
72438
72505
  Origins: {
72439
- Quantity: 1,
72440
- Items: [
72441
- {
72442
- Id: originId,
72443
- DomainName: originDomain,
72444
- OriginAccessControlId: oacId,
72445
- S3OriginConfig: { OriginAccessIdentity: "" }
72446
- }
72447
- ]
72506
+ Quantity: originsItems.length,
72507
+ Items: originsItems
72448
72508
  },
72449
72509
  DefaultCacheBehavior: {
72450
- TargetOriginId: originId,
72510
+ TargetOriginId: s3OriginId,
72451
72511
  ViewerProtocolPolicy: "redirect-to-https",
72452
72512
  AllowedMethods: {
72453
72513
  Quantity: 2,
@@ -72456,9 +72516,11 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72456
72516
  },
72457
72517
  Compress: true,
72458
72518
  CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
72519
+ ResponseHeadersPolicyId: SECURITY_HEADERS_POLICY_ID,
72459
72520
  FunctionAssociations: functionAssociations,
72460
72521
  LambdaFunctionAssociations: lambdaFunctionAssociations
72461
72522
  },
72523
+ CacheBehaviors: cacheBehaviors,
72462
72524
  Aliases: aliasesConfig,
72463
72525
  ...viewerCertificate ? { ViewerCertificate: viewerCertificate } : {},
72464
72526
  DefaultRootObject: index,
@@ -72820,7 +72882,7 @@ var parseSource = (source) => {
72820
72882
  const project2 = new Project({ useInMemoryFileSystem: true });
72821
72883
  return project2.createSourceFile("input.ts", source);
72822
72884
  };
72823
- var RUNTIME_PROPS = ["onRequest", "onRecord", "onBatchComplete", "onBatch", "onMessage", "onObjectCreated", "onObjectRemoved", "setup", "schema", "onError", "deps", "config", "static", "middleware"];
72885
+ var RUNTIME_PROPS = ["onRequest", "onRecord", "onBatchComplete", "onBatch", "onMessage", "onObjectCreated", "onObjectRemoved", "setup", "schema", "onError", "deps", "config", "static", "middleware", "routes"];
72824
72886
  var evalConfig = (configText, exportName) => {
72825
72887
  try {
72826
72888
  return new Function(`return ${configText}`)();
@@ -72924,6 +72986,26 @@ var extractStaticGlobs = (obj) => {
72924
72986
  const arrayLiteral = init;
72925
72987
  return arrayLiteral.getElements().filter((e) => e.getKind() === SyntaxKind.StringLiteral).map((e) => e.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue());
72926
72988
  };
72989
+ var extractRoutePatterns = (obj) => {
72990
+ const routesProp = obj.getProperties().find((p3) => {
72991
+ if (p3.getKind() === SyntaxKind.PropertyAssignment) {
72992
+ return p3.getName() === "routes";
72993
+ }
72994
+ return false;
72995
+ });
72996
+ if (!routesProp || routesProp.getKind() !== SyntaxKind.PropertyAssignment) return [];
72997
+ const init = routesProp.getInitializer();
72998
+ if (!init || init.getKind() !== SyntaxKind.ObjectLiteralExpression) return [];
72999
+ const routesObj = init;
73000
+ return routesObj.getProperties().map((p3) => {
73001
+ if (p3.getKind() !== SyntaxKind.PropertyAssignment) return "";
73002
+ const nameNode = p3.getNameNode();
73003
+ if (nameNode.getKind() === SyntaxKind.StringLiteral) {
73004
+ return nameNode.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
73005
+ }
73006
+ return nameNode.getText();
73007
+ }).filter(Boolean);
73008
+ };
72927
73009
  var handlerRegistry = {
72928
73010
  http: {
72929
73011
  defineFn: "defineHttp",
@@ -72988,7 +73070,8 @@ var extractHandlerConfigs = (source, type2) => {
72988
73070
  const depsKeys = extractDepsKeys(objLiteral);
72989
73071
  const paramEntries = extractParamEntries(objLiteral);
72990
73072
  const staticGlobs = extractStaticGlobs(objLiteral);
72991
- results.push({ exportName: "default", config: config2, hasHandler, depsKeys, paramEntries, staticGlobs });
73073
+ const routePatterns = extractRoutePatterns(objLiteral);
73074
+ results.push({ exportName: "default", config: config2, hasHandler, depsKeys, paramEntries, staticGlobs, routePatterns });
72992
73075
  }
72993
73076
  }
72994
73077
  }
@@ -73011,7 +73094,8 @@ var extractHandlerConfigs = (source, type2) => {
73011
73094
  const depsKeys = extractDepsKeys(objLiteral);
73012
73095
  const paramEntries = extractParamEntries(objLiteral);
73013
73096
  const staticGlobs = extractStaticGlobs(objLiteral);
73014
- results.push({ exportName, config: config2, hasHandler, depsKeys, paramEntries, staticGlobs });
73097
+ const routePatterns = extractRoutePatterns(objLiteral);
73098
+ results.push({ exportName, config: config2, hasHandler, depsKeys, paramEntries, staticGlobs, routePatterns });
73015
73099
  }
73016
73100
  });
73017
73101
  });
@@ -73607,6 +73691,41 @@ var deployMiddlewareLambda = (input) => Effect_exports.gen(function* () {
73607
73691
  yield* Effect_exports.logDebug(`Middleware deployed: ${versionArn}`);
73608
73692
  return { versionArn };
73609
73693
  });
73694
+ var ERROR_PAGE_KEY = "_effortless/404.html";
73695
+ var generateErrorPageHtml = () => `<!DOCTYPE html>
73696
+ <html lang="en">
73697
+ <head>
73698
+ <meta charset="utf-8">
73699
+ <meta name="viewport" content="width=device-width, initial-scale=1">
73700
+ <title>404 \u2014 Page not found</title>
73701
+ <style>
73702
+ * { margin: 0; padding: 0; box-sizing: border-box; }
73703
+ body {
73704
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
73705
+ display: flex;
73706
+ align-items: center;
73707
+ justify-content: center;
73708
+ min-height: 100vh;
73709
+ background: #fff;
73710
+ color: #111;
73711
+ }
73712
+ .c { text-align: center; }
73713
+ h1 { font-size: 4rem; font-weight: 200; letter-spacing: 0.1em; }
73714
+ hr { width: 40px; border: none; border-top: 1px solid #ccc; margin: 1.5rem auto; }
73715
+ p { font-size: 1rem; color: #666; }
73716
+ a { display: inline-block; margin-top: 1.5rem; color: #666; font-size: 0.875rem; text-decoration: none; }
73717
+ a:hover { color: #111; }
73718
+ </style>
73719
+ </head>
73720
+ <body>
73721
+ <div class="c">
73722
+ <h1>404</h1>
73723
+ <hr>
73724
+ <p>This page does not exist.</p>
73725
+ <a href="javascript:history.back()">&larr; Back</a>
73726
+ </div>
73727
+ </body>
73728
+ </html>`;
73610
73729
  var deployStaticSite = (input) => Effect_exports.gen(function* () {
73611
73730
  const { projectDir, project: project2, region, fn: fn2 } = input;
73612
73731
  const { exportName, config: config2 } = fn2;
@@ -73614,6 +73733,14 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73614
73733
  const handlerName = exportName;
73615
73734
  const hasMiddleware = fn2.hasHandler;
73616
73735
  const tagCtx = { project: project2, stage, handler: handlerName };
73736
+ const routePatterns = fn2.routePatterns;
73737
+ if (routePatterns.length > 0 && !input.apiOriginDomain) {
73738
+ return yield* Effect_exports.fail(
73739
+ new Error(
73740
+ `Static site "${exportName}" has routes but no API Gateway exists. Ensure defineHttp() handlers are included in the discovery patterns.`
73741
+ )
73742
+ );
73743
+ }
73617
73744
  if (config2.build) {
73618
73745
  yield* Effect_exports.logDebug(`Building site: ${config2.build}`);
73619
73746
  yield* Effect_exports.try({
@@ -73682,6 +73809,7 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73682
73809
  urlRewriteFunctionArn = result.functionArn;
73683
73810
  }
73684
73811
  }
73812
+ const errorPagePath = isSpa ? void 0 : config2.errorPage ? `/${config2.errorPage}` : `/${ERROR_PAGE_KEY}`;
73685
73813
  const index = config2.index ?? "index.html";
73686
73814
  const { distributionId, distributionArn, domainName } = yield* ensureDistribution({
73687
73815
  project: project2,
@@ -73696,11 +73824,21 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73696
73824
  urlRewriteFunctionArn,
73697
73825
  lambdaEdgeArn,
73698
73826
  aliases,
73699
- acmCertificateArn
73827
+ acmCertificateArn,
73828
+ errorPagePath,
73829
+ ...input.apiOriginDomain && routePatterns.length > 0 ? { apiOriginDomain: input.apiOriginDomain, routePatterns } : {}
73700
73830
  });
73701
73831
  yield* putBucketPolicyForOAC(bucketName, distributionArn);
73702
73832
  const sourceDir = path8.resolve(projectDir, config2.dir);
73703
73833
  yield* syncFiles({ bucketName, sourceDir });
73834
+ if (!isSpa && !config2.errorPage) {
73835
+ yield* putObject({
73836
+ bucketName,
73837
+ key: ERROR_PAGE_KEY,
73838
+ body: generateErrorPageHtml(),
73839
+ contentType: "text/html; charset=utf-8"
73840
+ });
73841
+ }
73704
73842
  yield* invalidateDistribution(distributionId);
73705
73843
  const url2 = domain ? `https://${domain}` : `https://${domainName}`;
73706
73844
  yield* Effect_exports.logDebug(`Static site deployed: ${url2}`);
@@ -74165,9 +74303,10 @@ var buildAppTasks = (ctx, handlers, apiId, results) => {
74165
74303
  }
74166
74304
  return tasks;
74167
74305
  };
74168
- var buildStaticSiteTasks = (ctx, handlers, results) => {
74306
+ var buildStaticSiteTasks = (ctx, handlers, results, apiId) => {
74169
74307
  const tasks = [];
74170
74308
  const { region } = ctx.input;
74309
+ const apiOriginDomain = apiId ? `${apiId}.execute-api.${region}.amazonaws.com` : void 0;
74171
74310
  for (const { file: file7, exports } of handlers) {
74172
74311
  for (const fn2 of exports) {
74173
74312
  tasks.push(
@@ -74178,7 +74317,8 @@ var buildStaticSiteTasks = (ctx, handlers, results) => {
74178
74317
  stage: ctx.input.stage,
74179
74318
  region,
74180
74319
  fn: fn2,
74181
- ...fn2.hasHandler ? { file: file7 } : {}
74320
+ ...fn2.hasHandler ? { file: file7 } : {},
74321
+ ...apiOriginDomain ? { apiOriginDomain } : {}
74182
74322
  }).pipe(Effect_exports.provide(clients_exports.makeClients({
74183
74323
  s3: { region },
74184
74324
  cloudfront: { region: "us-east-1" },
@@ -74326,7 +74466,10 @@ var deployProject = (input) => Effect_exports.gen(function* () {
74326
74466
  }
74327
74467
  let apiId;
74328
74468
  let apiUrl;
74329
- if (totalHttpHandlers > 0 || totalAppHandlers > 0) {
74469
+ const staticSitesNeedApi = staticSiteHandlers.some(
74470
+ ({ exports }) => exports.some((fn2) => fn2.routePatterns.length > 0)
74471
+ );
74472
+ if (totalHttpHandlers > 0 || totalAppHandlers > 0 || staticSitesNeedApi) {
74330
74473
  const tagCtx = {
74331
74474
  project: input.project,
74332
74475
  stage,
@@ -74387,7 +74530,7 @@ var deployProject = (input) => Effect_exports.gen(function* () {
74387
74530
  ...apiId ? buildHttpTasks(ctx, httpHandlers, apiId, httpResults) : [],
74388
74531
  ...buildTableTasks(ctx, tableHandlers, tableResults),
74389
74532
  ...apiId ? buildAppTasks(ctx, appHandlers, apiId, appResults) : [],
74390
- ...buildStaticSiteTasks(ctx, staticSiteHandlers, staticSiteResults),
74533
+ ...buildStaticSiteTasks(ctx, staticSiteHandlers, staticSiteResults, apiId),
74391
74534
  ...buildFifoQueueTasks(ctx, fifoQueueHandlers, fifoQueueResults),
74392
74535
  ...buildBucketTasks(ctx, bucketHandlers, bucketResults),
74393
74536
  ...buildMailerTasks(ctx, mailerHandlers, mailerResults)