@awsless/awsless 0.0.485 → 0.0.486

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/bin.js CHANGED
@@ -202,11 +202,12 @@ var createWorkSpace = async (props) => {
202
202
  if (process.env.VERBOSE) {
203
203
  enableDebug();
204
204
  }
205
- const aws = await terraform.install("hashicorp", "aws", "5.94.1");
205
+ const aws = await terraform.install("hashicorp", "aws", "5.98.0");
206
206
  const workspace = new WorkSpace({
207
207
  providers: [
208
208
  createLambdaProvider(props),
209
209
  createCloudFrontProvider(props),
210
+ // createCloudFrontKvsProvider(props),
210
211
  aws(
211
212
  {
212
213
  profile: props.profile,
@@ -1391,7 +1392,10 @@ var SitesSchema = z31.record(
1391
1392
  ),
1392
1393
  ssr: FunctionSchema.optional().describe("Specifies the file that will render the site on the server."),
1393
1394
  // envPrefix: z.string().optional().describe('Specifies a prefix for all '),
1394
- origin: z31.enum(["ssr-first", "static-first"]).default("static-first").describe("Specifies the origin fallback ordering."),
1395
+ // origin: z
1396
+ // .enum(['ssr-first', 'static-first'])
1397
+ // .default('static-first')
1398
+ // .describe('Specifies the origin fallback ordering.'),
1395
1399
  // bind: z.object({
1396
1400
  // auth:
1397
1401
  // h
@@ -1405,13 +1409,16 @@ var SitesSchema = z31.record(
1405
1409
  // }),
1406
1410
  // ]),
1407
1411
  geoRestrictions: z31.array(z31.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
1408
- forwardHost: z31.boolean().default(false).describe(
1409
- [
1410
- "Specify if the original `host` header should be forwarded to the SSR function.",
1411
- "The original `host` header will be forwarded as `x-forwarded-host`.",
1412
- "Keep in mind that this requires an extra CloudFront Function."
1413
- ].join("\n")
1414
- ),
1412
+ // forwardHost: z
1413
+ // .boolean()
1414
+ // .default(false)
1415
+ // .describe(
1416
+ // [
1417
+ // 'Specify if the original `host` header should be forwarded to the SSR function.',
1418
+ // 'The original `host` header will be forwarded as `x-forwarded-host`.',
1419
+ // 'Keep in mind that this requires an extra CloudFront Function.',
1420
+ // ].join('\n')
1421
+ // ),
1415
1422
  errors: z31.object({
1416
1423
  400: ErrorResponseSchema.describe("Customize a `400 Bad Request` response."),
1417
1424
  403: ErrorResponseSchema.describe("Customize a `403 Forbidden` response."),
@@ -4396,20 +4403,140 @@ var getCacheControl = (file) => {
4396
4403
  var getContentType = (file) => {
4397
4404
  return contentType(extname2(file)) || "text/html; charset=utf-8";
4398
4405
  };
4399
- var getForwardHostFunctionCode = () => {
4400
- return [
4401
- "function handler(event) {",
4402
- "const request = event.request",
4403
- "const headers = request.headers",
4404
- "const host = request.headers.host.value",
4405
- 'headers["x-forwarded-host"] = { value: host }',
4406
- "return request",
4407
- "}"
4408
- ].join("\n");
4406
+ var getViewerRequestFunctionCode = (domain2, bucket, functionUrl) => {
4407
+ return $resolve([bucket?.bucketRegionalDomainName, functionUrl?.functionUrl], (bucketDomain, lambdaUrl) => {
4408
+ return CF_FUNC_WRAP([
4409
+ // --------------------------------------------------------
4410
+ // Block direct access to cloudfront.
4411
+ domain2 ? BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT : "",
4412
+ // --------------------------------------------------------
4413
+ // Define functions.
4414
+ bucketDomain ? GET_PREFIXES : "",
4415
+ bucketDomain ? SET_S3_ORIGIN : "",
4416
+ lambdaUrl ? SET_LAMBDA_ORIGIN : "",
4417
+ // --------------------------------------------------------
4418
+ // Route asset requests to the s3 bucket.
4419
+ bucketDomain ? ROUTE_TO_S3_ORIGIN_IF_STATIC_ASSET(bucketDomain) : "",
4420
+ // --------------------------------------------------------
4421
+ // Route SSR requests.
4422
+ lambdaUrl ? ROUTE_TO_LAMBDA_ORIGIN(lambdaUrl.split("/")[2]) : "",
4423
+ // --------------------------------------------------------
4424
+ // Return original response
4425
+ bucketDomain && !lambdaUrl ? ROUTE_TO_S3_ORIGIN(bucketDomain) : ""
4426
+ ]);
4427
+ });
4409
4428
  };
4429
+ var CF_FUNC_WRAP = (code) => `
4430
+ import cf from "cloudfront";
4431
+
4432
+ async function handler(event) {
4433
+ ${code.join("\n")}
4434
+
4435
+ return event.request;
4436
+ }
4437
+ `;
4438
+ var BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT = `
4439
+ if (event.request.headers.host.value.includes('cloudfront.net')) {
4440
+ return {
4441
+ statusCode: 403,
4442
+ statusDescription: 'Forbidden',
4443
+ body: {
4444
+ encoding: 'text',
4445
+ data: '<html><head><title>403 Forbidden</title></head><body><center><h1>403 Forbidden</h1></center></body></html>'
4446
+ }
4447
+ };
4448
+ }`;
4449
+ var SET_S3_ORIGIN = `
4450
+ function setS3Origin(s3Domain) {
4451
+ const origin = {
4452
+ domainName: s3Domain,
4453
+ originAccessControlConfig: {
4454
+ enabled: true,
4455
+ signingBehavior: 'always',
4456
+ signingProtocol: 'sigv4',
4457
+ originType: 's3',
4458
+ }
4459
+ };
4460
+
4461
+ console.log("s3 origin")
4462
+ console.log(origin)
4463
+ cf.updateRequestOrigin(origin);
4464
+ }`;
4465
+ var SET_LAMBDA_ORIGIN = `
4466
+ function setLambdaOrigin(urlHost) {
4467
+ cf.updateRequestOrigin({
4468
+ domainName: urlHost,
4469
+ customOriginConfig: {
4470
+ port: 443,
4471
+ protocol: 'https',
4472
+ sslProtocols: ['TLSv1.2'],
4473
+ },
4474
+ originAccessControlConfig: {
4475
+ enabled: true,
4476
+ signingBehavior: 'always',
4477
+ signingProtocol: 'sigv4',
4478
+ originType: 'lambda',
4479
+ }
4480
+ });
4481
+ }`;
4482
+ var GET_PREFIXES = `
4483
+ function getPostfixes(path) {
4484
+ if(path === '') {
4485
+ return ['/index.html'];
4486
+ }
4487
+
4488
+ if(path.endsWith('/')) {
4489
+ return ['index.html'];
4490
+ }
4491
+
4492
+ const parts = path.split('/');
4493
+ const lastPart = parts[parts.length - 1];
4494
+
4495
+ if(lastPart.includes('.')) {
4496
+ return [''];
4497
+ }
4498
+
4499
+ return ['', '.html', '/index.html'];
4500
+ }`;
4501
+ var ROUTE_TO_S3_ORIGIN_IF_STATIC_ASSET = (bucketDomain) => `
4502
+ if (event.request.method === 'GET' || event.request.method === 'HEAD') {
4503
+ const s3Domain = '${bucketDomain}';
4504
+ const path = decodeURIComponent(event.request.uri);
4505
+ const postfixes = getPostfixes(path);
4506
+
4507
+ try {
4508
+ const postfix = await Promise.any(
4509
+ postfixes.map(p => {
4510
+ return cf
4511
+ .kvs()
4512
+ .get(path + p)
4513
+ .then(v => p);
4514
+ })
4515
+ );
4516
+
4517
+ event.request.uri = event.request.uri + postfix;
4518
+ setS3Origin(s3Domain);
4519
+ return event.request;
4520
+ } catch (e) {}
4521
+ }`;
4522
+ var ROUTE_TO_S3_ORIGIN = (bucketDomain) => `
4523
+ setS3Origin('${bucketDomain}');`;
4524
+ var ROUTE_TO_LAMBDA_ORIGIN = (url) => `
4525
+ for (var key in event.request.querystring) {
4526
+ if (key.includes('/')) {
4527
+ event.request.querystring[encodeURIComponent(key)] = event.request.querystring[key];
4528
+ delete event.request.querystring[key];
4529
+ }
4530
+ }
4531
+
4532
+ if (event.request.headers.host) {
4533
+ event.request.headers['x-forwarded-host'] = event.request.headers.host;
4534
+ }
4535
+
4536
+ setLambdaOrigin('${url}');`;
4410
4537
 
4411
4538
  // src/feature/site/index.ts
4412
- import { camelCase as camelCase6, constantCase as constantCase10 } from "change-case";
4539
+ import { camelCase as camelCase6 } from "change-case";
4413
4540
 
4414
4541
  // src/util/exec.ts
4415
4542
  import { exec } from "promisify-child-process";
@@ -4448,10 +4575,19 @@ var siteFeature = defineFeature({
4448
4575
  });
4449
4576
  });
4450
4577
  }
4451
- const origins = [];
4452
- const originGroups = [];
4453
- let bucket;
4578
+ const kvs = new $15.aws.cloudfront.KeyValueStore(group, "kvs", {
4579
+ name,
4580
+ comment: "Store for static assets"
4581
+ });
4582
+ const keys = [];
4583
+ new $15.aws.cloudfrontkeyvaluestore.KeysExclusive(group, "keys", {
4584
+ keyValueStoreArn: kvs.arn,
4585
+ resourceKeyValuePair: new Future3((resolve) => {
4586
+ resolve(keys);
4587
+ })
4588
+ });
4454
4589
  const versions = [];
4590
+ let functionUrl;
4455
4591
  if (props.ssr) {
4456
4592
  const result = createLambdaFunction(group, ctx, `site`, id, props.ssr);
4457
4593
  versions.push(result.code.sourceHash);
@@ -4465,28 +4601,12 @@ var siteFeature = defineFeature({
4465
4601
  functionUrlAuthType: "AWS_IAM",
4466
4602
  sourceArn: `arn:aws:cloudfront::${ctx.accountId}:distribution/*`
4467
4603
  });
4468
- const url = new $15.aws.lambda.FunctionUrl(group, "url", {
4604
+ functionUrl = new $15.aws.lambda.FunctionUrl(group, "url", {
4469
4605
  functionName: result.lambda.functionName,
4470
4606
  authorizationType: "AWS_IAM"
4471
4607
  });
4472
- const ssrAccessControl = new $15.aws.cloudfront.OriginAccessControl(group, "ssr-access", {
4473
- name: `${name}-ssr`,
4474
- originAccessControlOriginType: "lambda",
4475
- signingBehavior: "always",
4476
- signingProtocol: "sigv4"
4477
- });
4478
- origins.push({
4479
- originId: "ssr",
4480
- domainName: url.functionUrl.pipe((url2) => url2.split("/")[2]),
4481
- originAccessControlId: ssrAccessControl.id,
4482
- customOriginConfig: {
4483
- originProtocolPolicy: "https-only",
4484
- httpPort: 80,
4485
- httpsPort: 443,
4486
- originSslProtocols: ["TLSv1.2"]
4487
- }
4488
- });
4489
4608
  }
4609
+ let bucket;
4490
4610
  if (props.static) {
4491
4611
  bucket = new $15.aws.s3.Bucket(group, "bucket", {
4492
4612
  bucket: formatLocalResourceName({
@@ -4527,14 +4647,8 @@ var siteFeature = defineFeature({
4527
4647
  bucket.arn.pipe((arn) => `${arn}/*`)
4528
4648
  ]
4529
4649
  });
4530
- const accessControl = new $15.aws.cloudfront.OriginAccessControl(group, `access`, {
4531
- name,
4532
- originAccessControlOriginType: "s3",
4533
- signingBehavior: "always",
4534
- signingProtocol: "sigv4"
4535
- });
4536
4650
  ctx.onReady(() => {
4537
- if (typeof props.static === "string") {
4651
+ if (typeof props.static === "string" && bucket) {
4538
4652
  const files = glob2.sync("**", {
4539
4653
  // cwd: join(directories.root, props.static),
4540
4654
  cwd: props.static,
@@ -4549,29 +4663,12 @@ var siteFeature = defineFeature({
4549
4663
  source: join11(props.static, file),
4550
4664
  sourceHash: $hash(join11(props.static, file))
4551
4665
  });
4666
+ keys.push({ key: `/${file}`, value: "s3" });
4552
4667
  versions.push(object.key);
4553
4668
  versions.push(object.sourceHash);
4554
4669
  }
4555
4670
  }
4556
4671
  });
4557
- origins.push({
4558
- originId: "static",
4559
- domainName: bucket.bucketRegionalDomainName,
4560
- originAccessControlId: accessControl.id,
4561
- s3OriginConfig: {
4562
- // is required to have an value for s3 origins when using origin access control
4563
- originAccessIdentity: ""
4564
- }
4565
- });
4566
- }
4567
- if (props.ssr && props.static) {
4568
- originGroups.push({
4569
- originId: "group",
4570
- member: props.origin === "ssr-first" ? [{ originId: "ssr" }, { originId: "static" }] : [{ originId: "static" }, { originId: "ssr" }],
4571
- failoverCriteria: {
4572
- statusCodes: [403, 404]
4573
- }
4574
- });
4575
4672
  }
4576
4673
  const cache = new $15.aws.cloudfront.CachePolicy(group, "cache", {
4577
4674
  name,
@@ -4655,30 +4752,25 @@ var siteFeature = defineFeature({
4655
4752
  });
4656
4753
  const domainName = props.domain ? formatFullDomainName(ctx.appConfig, props.domain, props.subDomain) : void 0;
4657
4754
  const certificateArn = props.domain ? ctx.shared.entry("domain", `global-certificate-arn`, props.domain) : void 0;
4658
- const associations = [];
4659
- if (props.forwardHost) {
4660
- const viewerRequest = new $15.aws.cloudfront.Function(group, "forward-host", {
4661
- name: formatLocalResourceName({
4662
- appName: ctx.app.name,
4663
- stackName: ctx.stack.name,
4664
- resourceType: "site",
4665
- resourceName: "forward-host"
4666
- }),
4667
- runtime: `cloudfront-js-2.0`,
4668
- comment: "Forward the host header to the origin",
4669
- publish: true,
4670
- code: getForwardHostFunctionCode()
4671
- });
4672
- associations.push({
4673
- eventType: "viewer-request",
4674
- functionArn: viewerRequest.arn
4675
- });
4676
- }
4755
+ const viewerRequest = new $15.aws.cloudfront.Function(group, "viewer-request", {
4756
+ name: formatLocalResourceName({
4757
+ appName: ctx.app.name,
4758
+ stackName: ctx.stack.name,
4759
+ resourceType: "site",
4760
+ resourceName: `request-${id}`
4761
+ }),
4762
+ runtime: `cloudfront-js-2.0`,
4763
+ comment: `Viewer Request - ${name}`,
4764
+ publish: true,
4765
+ code: getViewerRequestFunctionCode(domainName, bucket, functionUrl),
4766
+ keyValueStoreAssociations: [kvs.arn]
4767
+ });
4677
4768
  const distribution = new $15.aws.cloudfront.Distribution(group, "distribution", {
4678
4769
  // name,
4679
- tags: {
4680
- Name: name
4681
- },
4770
+ // tags: {
4771
+ // Name: name,
4772
+ // },
4773
+ comment: name,
4682
4774
  enabled: true,
4683
4775
  aliases: domainName ? [domainName] : void 0,
4684
4776
  priceClass: "PriceClass_All",
@@ -4690,8 +4782,19 @@ var siteFeature = defineFeature({
4690
4782
  } : {
4691
4783
  cloudfrontDefaultCertificate: true
4692
4784
  },
4693
- origin: origins,
4694
- originGroup: originGroups,
4785
+ origin: [
4786
+ {
4787
+ originId: "default",
4788
+ domainName: "placeholder.awsless.dev",
4789
+ customOriginConfig: {
4790
+ httpPort: 80,
4791
+ httpsPort: 443,
4792
+ originProtocolPolicy: "http-only",
4793
+ originReadTimeout: 20,
4794
+ originSslProtocols: ["TLSv1.2"]
4795
+ }
4796
+ }
4797
+ ],
4695
4798
  customErrorResponse: Object.entries(props.errors ?? {}).map(([errorCode, item]) => {
4696
4799
  if (typeof item === "string") {
4697
4800
  return {
@@ -4715,14 +4818,21 @@ var siteFeature = defineFeature({
4715
4818
  },
4716
4819
  defaultCacheBehavior: {
4717
4820
  compress: true,
4718
- targetOriginId: props.ssr && props.static ? "group" : props.ssr ? "ssr" : "static",
4719
- functionAssociation: associations,
4821
+ targetOriginId: "default",
4822
+ functionAssociation: [
4823
+ {
4824
+ eventType: "viewer-request",
4825
+ functionArn: viewerRequest.arn
4826
+ }
4827
+ ],
4720
4828
  originRequestPolicyId: originRequest.id,
4721
4829
  cachePolicyId: cache.id,
4722
4830
  responseHeadersPolicyId: responseHeaders.id,
4723
4831
  viewerProtocolPolicy: "redirect-to-https",
4724
4832
  allowedMethods: ["GET", "HEAD", "POST", "PUT", "PATCH", "OPTIONS", "DELETE"],
4725
4833
  cachedMethods: ["GET", "HEAD"]
4834
+ // cachedMethods: ['GET', 'HEAD', 'OPTIONS'],
4835
+ // cachedMethods: [],
4726
4836
  }
4727
4837
  });
4728
4838
  new Invalidation(group, "invalidate", {
@@ -4736,7 +4846,7 @@ var siteFeature = defineFeature({
4736
4846
  });
4737
4847
  })
4738
4848
  });
4739
- if (props.static) {
4849
+ if (bucket) {
4740
4850
  new $15.aws.s3.BucketPolicy(
4741
4851
  group,
4742
4852
  `policy`,
@@ -4780,9 +4890,6 @@ var siteFeature = defineFeature({
4780
4890
  }
4781
4891
  });
4782
4892
  }
4783
- if (domainName) {
4784
- ctx.bind(`SITE_${constantCase10(ctx.stack.name)}_${constantCase10(id)}_ENDPOINT`, domainName);
4785
- }
4786
4893
  }
4787
4894
  }
4788
4895
  });
@@ -4939,7 +5046,7 @@ var storeFeature = defineFeature({
4939
5046
 
4940
5047
  // src/feature/table/index.ts
4941
5048
  import { $ as $17, Group as Group17 } from "@awsless/formation";
4942
- import { constantCase as constantCase11 } from "change-case";
5049
+ import { constantCase as constantCase10 } from "change-case";
4943
5050
  import { toSeconds as toSeconds7 } from "@awsless/duration";
4944
5051
  var tableFeature = defineFeature({
4945
5052
  name: "table",
@@ -5021,8 +5128,8 @@ var tableFeature = defineFeature({
5021
5128
  name,
5022
5129
  billingMode: "PAY_PER_REQUEST",
5023
5130
  streamEnabled: !!props.stream,
5024
- streamViewType: props.stream && constantCase11(props.stream?.type),
5025
- tableClass: constantCase11(props.class),
5131
+ streamViewType: props.stream && constantCase10(props.stream?.type),
5132
+ tableClass: constantCase10(props.class),
5026
5133
  hashKey: props.hash,
5027
5134
  rangeKey: props.sort,
5028
5135
  attribute: attributeDefinitions(),
@@ -5037,7 +5144,7 @@ var tableFeature = defineFeature({
5037
5144
  name: name2,
5038
5145
  hashKey: index.hash,
5039
5146
  rangeKey: index.sort,
5040
- projectionType: constantCase11(index.projection)
5147
+ projectionType: constantCase10(index.projection)
5041
5148
  })),
5042
5149
  deletionProtectionEnabled: ctx.appConfig.removal === "retain"
5043
5150
  },
@@ -6923,7 +7030,7 @@ var auth = (program2) => {
6923
7030
 
6924
7031
  // src/cli/command/bind.ts
6925
7032
  import { log as log10, note as note3 } from "@clack/prompts";
6926
- import { constantCase as constantCase12 } from "change-case";
7033
+ import { constantCase as constantCase11 } from "change-case";
6927
7034
  import { spawn } from "child_process";
6928
7035
  var bind = (program2) => {
6929
7036
  program2.command("bind").argument("[command...]", "The command to execute").option("--config <string...>", "List of config values that will be accessable", (v) => v.split(",")).description(`Bind your site environment variables to a command`).action(async (commands7 = [], opts) => {
@@ -6952,10 +7059,10 @@ var bind = (program2) => {
6952
7059
  const configList = opts.config ?? [];
6953
7060
  const configs = {};
6954
7061
  for (const name of configList) {
6955
- configs[`CONFIG_${constantCase12(name)}`] = name;
7062
+ configs[`CONFIG_${constantCase11(name)}`] = name;
6956
7063
  }
6957
7064
  if (configList.length ?? 0 > 0) {
6958
- note3(wrap(configList.map((v) => color.label(constantCase12(v)))), "Bind Config");
7065
+ note3(wrap(configList.map((v) => color.label(constantCase11(v)))), "Bind Config");
6959
7066
  }
6960
7067
  if (commands7.length === 0) {
6961
7068
  return "No command to execute.";
@@ -901,7 +901,10 @@ var SitesSchema = z29.record(
901
901
  ),
902
902
  ssr: FunctionSchema.optional().describe("Specifies the file that will render the site on the server."),
903
903
  // envPrefix: z.string().optional().describe('Specifies a prefix for all '),
904
- origin: z29.enum(["ssr-first", "static-first"]).default("static-first").describe("Specifies the origin fallback ordering."),
904
+ // origin: z
905
+ // .enum(['ssr-first', 'static-first'])
906
+ // .default('static-first')
907
+ // .describe('Specifies the origin fallback ordering.'),
905
908
  // bind: z.object({
906
909
  // auth:
907
910
  // h
@@ -915,13 +918,16 @@ var SitesSchema = z29.record(
915
918
  // }),
916
919
  // ]),
917
920
  geoRestrictions: z29.array(z29.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
918
- forwardHost: z29.boolean().default(false).describe(
919
- [
920
- "Specify if the original `host` header should be forwarded to the SSR function.",
921
- "The original `host` header will be forwarded as `x-forwarded-host`.",
922
- "Keep in mind that this requires an extra CloudFront Function."
923
- ].join("\n")
924
- ),
921
+ // forwardHost: z
922
+ // .boolean()
923
+ // .default(false)
924
+ // .describe(
925
+ // [
926
+ // 'Specify if the original `host` header should be forwarded to the SSR function.',
927
+ // 'The original `host` header will be forwarded as `x-forwarded-host`.',
928
+ // 'Keep in mind that this requires an extra CloudFront Function.',
929
+ // ].join('\n')
930
+ // ),
925
931
  errors: z29.object({
926
932
  400: ErrorResponseSchema.describe("Customize a `400 Bad Request` response."),
927
933
  403: ErrorResponseSchema.describe("Customize a `403 Forbidden` response."),
Binary file