effortless-aws 0.15.0 → 0.16.1

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,53 @@ 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
+ OriginReadTimeout: 30,
72376
+ OriginKeepaliveTimeout: 5
72377
+ },
72378
+ CustomHeaders: { Quantity: 0, Items: [] }
72379
+ }] : []
72380
+ ];
72381
+ const API_METHODS = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"];
72382
+ const CACHED_METHODS = ["GET", "HEAD"];
72383
+ const cacheBehaviors = hasApiRoutes ? {
72384
+ Quantity: routePatterns.length,
72385
+ Items: routePatterns.map((pattern2) => ({
72386
+ PathPattern: pattern2,
72387
+ TargetOriginId: apiOriginId,
72388
+ ViewerProtocolPolicy: "redirect-to-https",
72389
+ AllowedMethods: {
72390
+ Quantity: 7,
72391
+ Items: [...API_METHODS],
72392
+ CachedMethods: { Quantity: 2, Items: [...CACHED_METHODS] }
72393
+ },
72394
+ Compress: true,
72395
+ CachePolicyId: CACHING_DISABLED_POLICY_ID,
72396
+ OriginRequestPolicyId: ALL_VIEWER_EXCEPT_HOST_HEADER_POLICY_ID
72397
+ }))
72398
+ } : { Quantity: 0, Items: [] };
72399
+ const { errorPagePath } = input;
72345
72400
  const customErrorResponses = spa ? {
72346
72401
  Quantity: 2,
72347
72402
  Items: [
@@ -72358,6 +72413,22 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72358
72413
  ErrorCachingMinTTL: 0
72359
72414
  }
72360
72415
  ]
72416
+ } : errorPagePath ? {
72417
+ Quantity: 2,
72418
+ Items: [
72419
+ {
72420
+ ErrorCode: 403,
72421
+ ResponseCode: "404",
72422
+ ResponsePagePath: errorPagePath,
72423
+ ErrorCachingMinTTL: 0
72424
+ },
72425
+ {
72426
+ ErrorCode: 404,
72427
+ ResponseCode: "404",
72428
+ ResponsePagePath: errorPagePath,
72429
+ ErrorCachingMinTTL: 0
72430
+ }
72431
+ ]
72361
72432
  } : { Quantity: 0, Items: [] };
72362
72433
  const existing = yield* findDistributionByTags(project2, stage, handlerName);
72363
72434
  if (existing) {
@@ -72373,7 +72444,12 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72373
72444
  const aliasesMatch = currentAliases.length === desiredAliases.length && desiredAliases.every((a) => currentAliases.includes(a));
72374
72445
  const certMatch = currentConfig.ViewerCertificate?.ACMCertificateArn === (acmCertificateArn ?? void 0);
72375
72446
  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;
72447
+ const originsMatch = (currentConfig.Origins?.Quantity ?? 0) === originsItems.length;
72448
+ const currentBehaviorPatterns = (currentConfig.CacheBehaviors?.Items ?? []).map((b) => b.PathPattern).sort();
72449
+ const desiredBehaviorPatterns = (routePatterns ?? []).slice().sort();
72450
+ const behaviorsMatch = currentBehaviorPatterns.length === desiredBehaviorPatterns.length && desiredBehaviorPatterns.every((p3, i) => currentBehaviorPatterns[i] === p3);
72451
+ const apiOriginMatch = !hasApiRoutes || currentConfig.Origins?.Items?.some((o) => o.DomainName === apiOriginDomain);
72452
+ 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
72453
  if (needsUpdate) {
72378
72454
  yield* Effect_exports.logDebug(`CloudFront distribution ${existing.Id} config changed, updating...`);
72379
72455
  const etag = configResult.ETag;
@@ -72384,21 +72460,12 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72384
72460
  ...currentConfig,
72385
72461
  Comment: comment,
72386
72462
  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
- ]
72463
+ Quantity: originsItems.length,
72464
+ Items: originsItems
72398
72465
  },
72399
72466
  DefaultCacheBehavior: {
72400
72467
  ...currentConfig.DefaultCacheBehavior,
72401
- TargetOriginId: originId,
72468
+ TargetOriginId: s3OriginId,
72402
72469
  ViewerProtocolPolicy: "redirect-to-https",
72403
72470
  AllowedMethods: {
72404
72471
  Quantity: 2,
@@ -72407,10 +72474,12 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72407
72474
  },
72408
72475
  Compress: true,
72409
72476
  CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
72477
+ ResponseHeadersPolicyId: SECURITY_HEADERS_POLICY_ID,
72410
72478
  FunctionAssociations: functionAssociations,
72411
72479
  LambdaFunctionAssociations: lambdaFunctionAssociations,
72412
72480
  ForwardedValues: void 0
72413
72481
  },
72482
+ CacheBehaviors: cacheBehaviors,
72414
72483
  Aliases: aliasesConfig,
72415
72484
  ...viewerCertificate ? { ViewerCertificate: viewerCertificate } : {},
72416
72485
  DefaultRootObject: index,
@@ -72436,18 +72505,11 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72436
72505
  CallerReference: `${project2}-${stage}-${handlerName}-${Date.now()}`,
72437
72506
  Comment: comment,
72438
72507
  Origins: {
72439
- Quantity: 1,
72440
- Items: [
72441
- {
72442
- Id: originId,
72443
- DomainName: originDomain,
72444
- OriginAccessControlId: oacId,
72445
- S3OriginConfig: { OriginAccessIdentity: "" }
72446
- }
72447
- ]
72508
+ Quantity: originsItems.length,
72509
+ Items: originsItems
72448
72510
  },
72449
72511
  DefaultCacheBehavior: {
72450
- TargetOriginId: originId,
72512
+ TargetOriginId: s3OriginId,
72451
72513
  ViewerProtocolPolicy: "redirect-to-https",
72452
72514
  AllowedMethods: {
72453
72515
  Quantity: 2,
@@ -72456,9 +72518,11 @@ var ensureDistribution = (input) => Effect_exports.gen(function* () {
72456
72518
  },
72457
72519
  Compress: true,
72458
72520
  CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
72521
+ ResponseHeadersPolicyId: SECURITY_HEADERS_POLICY_ID,
72459
72522
  FunctionAssociations: functionAssociations,
72460
72523
  LambdaFunctionAssociations: lambdaFunctionAssociations
72461
72524
  },
72525
+ CacheBehaviors: cacheBehaviors,
72462
72526
  Aliases: aliasesConfig,
72463
72527
  ...viewerCertificate ? { ViewerCertificate: viewerCertificate } : {},
72464
72528
  DefaultRootObject: index,
@@ -72820,7 +72884,7 @@ var parseSource = (source) => {
72820
72884
  const project2 = new Project({ useInMemoryFileSystem: true });
72821
72885
  return project2.createSourceFile("input.ts", source);
72822
72886
  };
72823
- var RUNTIME_PROPS = ["onRequest", "onRecord", "onBatchComplete", "onBatch", "onMessage", "onObjectCreated", "onObjectRemoved", "setup", "schema", "onError", "deps", "config", "static", "middleware"];
72887
+ var RUNTIME_PROPS = ["onRequest", "onRecord", "onBatchComplete", "onBatch", "onMessage", "onObjectCreated", "onObjectRemoved", "setup", "schema", "onError", "deps", "config", "static", "middleware", "routes"];
72824
72888
  var evalConfig = (configText, exportName) => {
72825
72889
  try {
72826
72890
  return new Function(`return ${configText}`)();
@@ -72924,6 +72988,26 @@ var extractStaticGlobs = (obj) => {
72924
72988
  const arrayLiteral = init;
72925
72989
  return arrayLiteral.getElements().filter((e) => e.getKind() === SyntaxKind.StringLiteral).map((e) => e.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue());
72926
72990
  };
72991
+ var extractRoutePatterns = (obj) => {
72992
+ const routesProp = obj.getProperties().find((p3) => {
72993
+ if (p3.getKind() === SyntaxKind.PropertyAssignment) {
72994
+ return p3.getName() === "routes";
72995
+ }
72996
+ return false;
72997
+ });
72998
+ if (!routesProp || routesProp.getKind() !== SyntaxKind.PropertyAssignment) return [];
72999
+ const init = routesProp.getInitializer();
73000
+ if (!init || init.getKind() !== SyntaxKind.ObjectLiteralExpression) return [];
73001
+ const routesObj = init;
73002
+ return routesObj.getProperties().map((p3) => {
73003
+ if (p3.getKind() !== SyntaxKind.PropertyAssignment) return "";
73004
+ const nameNode = p3.getNameNode();
73005
+ if (nameNode.getKind() === SyntaxKind.StringLiteral) {
73006
+ return nameNode.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
73007
+ }
73008
+ return nameNode.getText();
73009
+ }).filter(Boolean);
73010
+ };
72927
73011
  var handlerRegistry = {
72928
73012
  http: {
72929
73013
  defineFn: "defineHttp",
@@ -72988,7 +73072,8 @@ var extractHandlerConfigs = (source, type2) => {
72988
73072
  const depsKeys = extractDepsKeys(objLiteral);
72989
73073
  const paramEntries = extractParamEntries(objLiteral);
72990
73074
  const staticGlobs = extractStaticGlobs(objLiteral);
72991
- results.push({ exportName: "default", config: config2, hasHandler, depsKeys, paramEntries, staticGlobs });
73075
+ const routePatterns = extractRoutePatterns(objLiteral);
73076
+ results.push({ exportName: "default", config: config2, hasHandler, depsKeys, paramEntries, staticGlobs, routePatterns });
72992
73077
  }
72993
73078
  }
72994
73079
  }
@@ -73011,7 +73096,8 @@ var extractHandlerConfigs = (source, type2) => {
73011
73096
  const depsKeys = extractDepsKeys(objLiteral);
73012
73097
  const paramEntries = extractParamEntries(objLiteral);
73013
73098
  const staticGlobs = extractStaticGlobs(objLiteral);
73014
- results.push({ exportName, config: config2, hasHandler, depsKeys, paramEntries, staticGlobs });
73099
+ const routePatterns = extractRoutePatterns(objLiteral);
73100
+ results.push({ exportName, config: config2, hasHandler, depsKeys, paramEntries, staticGlobs, routePatterns });
73015
73101
  }
73016
73102
  });
73017
73103
  });
@@ -73607,6 +73693,41 @@ var deployMiddlewareLambda = (input) => Effect_exports.gen(function* () {
73607
73693
  yield* Effect_exports.logDebug(`Middleware deployed: ${versionArn}`);
73608
73694
  return { versionArn };
73609
73695
  });
73696
+ var ERROR_PAGE_KEY = "_effortless/404.html";
73697
+ var generateErrorPageHtml = () => `<!DOCTYPE html>
73698
+ <html lang="en">
73699
+ <head>
73700
+ <meta charset="utf-8">
73701
+ <meta name="viewport" content="width=device-width, initial-scale=1">
73702
+ <title>404 \u2014 Page not found</title>
73703
+ <style>
73704
+ * { margin: 0; padding: 0; box-sizing: border-box; }
73705
+ body {
73706
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
73707
+ display: flex;
73708
+ align-items: center;
73709
+ justify-content: center;
73710
+ min-height: 100vh;
73711
+ background: #fff;
73712
+ color: #111;
73713
+ }
73714
+ .c { text-align: center; }
73715
+ h1 { font-size: 4rem; font-weight: 200; letter-spacing: 0.1em; }
73716
+ hr { width: 40px; border: none; border-top: 1px solid #ccc; margin: 1.5rem auto; }
73717
+ p { font-size: 1rem; color: #666; }
73718
+ a { display: inline-block; margin-top: 1.5rem; color: #666; font-size: 0.875rem; text-decoration: none; }
73719
+ a:hover { color: #111; }
73720
+ </style>
73721
+ </head>
73722
+ <body>
73723
+ <div class="c">
73724
+ <h1>404</h1>
73725
+ <hr>
73726
+ <p>This page does not exist.</p>
73727
+ <a href="javascript:history.back()">&larr; Back</a>
73728
+ </div>
73729
+ </body>
73730
+ </html>`;
73610
73731
  var deployStaticSite = (input) => Effect_exports.gen(function* () {
73611
73732
  const { projectDir, project: project2, region, fn: fn2 } = input;
73612
73733
  const { exportName, config: config2 } = fn2;
@@ -73614,6 +73735,14 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73614
73735
  const handlerName = exportName;
73615
73736
  const hasMiddleware = fn2.hasHandler;
73616
73737
  const tagCtx = { project: project2, stage, handler: handlerName };
73738
+ const routePatterns = fn2.routePatterns;
73739
+ if (routePatterns.length > 0 && !input.apiOriginDomain) {
73740
+ return yield* Effect_exports.fail(
73741
+ new Error(
73742
+ `Static site "${exportName}" has routes but no API Gateway exists. Ensure defineHttp() handlers are included in the discovery patterns.`
73743
+ )
73744
+ );
73745
+ }
73617
73746
  if (config2.build) {
73618
73747
  yield* Effect_exports.logDebug(`Building site: ${config2.build}`);
73619
73748
  yield* Effect_exports.try({
@@ -73682,6 +73811,7 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73682
73811
  urlRewriteFunctionArn = result.functionArn;
73683
73812
  }
73684
73813
  }
73814
+ const errorPagePath = isSpa ? void 0 : config2.errorPage ? `/${config2.errorPage}` : `/${ERROR_PAGE_KEY}`;
73685
73815
  const index = config2.index ?? "index.html";
73686
73816
  const { distributionId, distributionArn, domainName } = yield* ensureDistribution({
73687
73817
  project: project2,
@@ -73696,11 +73826,21 @@ var deployStaticSite = (input) => Effect_exports.gen(function* () {
73696
73826
  urlRewriteFunctionArn,
73697
73827
  lambdaEdgeArn,
73698
73828
  aliases,
73699
- acmCertificateArn
73829
+ acmCertificateArn,
73830
+ errorPagePath,
73831
+ ...input.apiOriginDomain && routePatterns.length > 0 ? { apiOriginDomain: input.apiOriginDomain, routePatterns } : {}
73700
73832
  });
73701
73833
  yield* putBucketPolicyForOAC(bucketName, distributionArn);
73702
73834
  const sourceDir = path8.resolve(projectDir, config2.dir);
73703
73835
  yield* syncFiles({ bucketName, sourceDir });
73836
+ if (!isSpa && !config2.errorPage) {
73837
+ yield* putObject({
73838
+ bucketName,
73839
+ key: ERROR_PAGE_KEY,
73840
+ body: generateErrorPageHtml(),
73841
+ contentType: "text/html; charset=utf-8"
73842
+ });
73843
+ }
73704
73844
  yield* invalidateDistribution(distributionId);
73705
73845
  const url2 = domain ? `https://${domain}` : `https://${domainName}`;
73706
73846
  yield* Effect_exports.logDebug(`Static site deployed: ${url2}`);
@@ -74165,9 +74305,10 @@ var buildAppTasks = (ctx, handlers, apiId, results) => {
74165
74305
  }
74166
74306
  return tasks;
74167
74307
  };
74168
- var buildStaticSiteTasks = (ctx, handlers, results) => {
74308
+ var buildStaticSiteTasks = (ctx, handlers, results, apiId) => {
74169
74309
  const tasks = [];
74170
74310
  const { region } = ctx.input;
74311
+ const apiOriginDomain = apiId ? `${apiId}.execute-api.${region}.amazonaws.com` : void 0;
74171
74312
  for (const { file: file7, exports } of handlers) {
74172
74313
  for (const fn2 of exports) {
74173
74314
  tasks.push(
@@ -74178,7 +74319,8 @@ var buildStaticSiteTasks = (ctx, handlers, results) => {
74178
74319
  stage: ctx.input.stage,
74179
74320
  region,
74180
74321
  fn: fn2,
74181
- ...fn2.hasHandler ? { file: file7 } : {}
74322
+ ...fn2.hasHandler ? { file: file7 } : {},
74323
+ ...apiOriginDomain ? { apiOriginDomain } : {}
74182
74324
  }).pipe(Effect_exports.provide(clients_exports.makeClients({
74183
74325
  s3: { region },
74184
74326
  cloudfront: { region: "us-east-1" },
@@ -74326,7 +74468,10 @@ var deployProject = (input) => Effect_exports.gen(function* () {
74326
74468
  }
74327
74469
  let apiId;
74328
74470
  let apiUrl;
74329
- if (totalHttpHandlers > 0 || totalAppHandlers > 0) {
74471
+ const staticSitesNeedApi = staticSiteHandlers.some(
74472
+ ({ exports }) => exports.some((fn2) => fn2.routePatterns.length > 0)
74473
+ );
74474
+ if (totalHttpHandlers > 0 || totalAppHandlers > 0 || staticSitesNeedApi) {
74330
74475
  const tagCtx = {
74331
74476
  project: input.project,
74332
74477
  stage,
@@ -74387,7 +74532,7 @@ var deployProject = (input) => Effect_exports.gen(function* () {
74387
74532
  ...apiId ? buildHttpTasks(ctx, httpHandlers, apiId, httpResults) : [],
74388
74533
  ...buildTableTasks(ctx, tableHandlers, tableResults),
74389
74534
  ...apiId ? buildAppTasks(ctx, appHandlers, apiId, appResults) : [],
74390
- ...buildStaticSiteTasks(ctx, staticSiteHandlers, staticSiteResults),
74535
+ ...buildStaticSiteTasks(ctx, staticSiteHandlers, staticSiteResults, apiId),
74391
74536
  ...buildFifoQueueTasks(ctx, fifoQueueHandlers, fifoQueueResults),
74392
74537
  ...buildBucketTasks(ctx, bucketHandlers, bucketResults),
74393
74538
  ...buildMailerTasks(ctx, mailerHandlers, mailerResults)