@awsless/cli 0.0.46-next.19 → 0.0.46-next.20

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
@@ -53724,9 +53724,9 @@ var require_nodefs_handler = __commonJS((exports, module) => {
53724
53724
  if (this.fsw.closed) {
53725
53725
  return;
53726
53726
  }
53727
- const dirname16 = sysPath.dirname(file2);
53727
+ const dirname17 = sysPath.dirname(file2);
53728
53728
  const basename4 = sysPath.basename(file2);
53729
- const parent = this.fsw._getWatchedDir(dirname16);
53729
+ const parent = this.fsw._getWatchedDir(dirname17);
53730
53730
  let prevStats = stats2;
53731
53731
  if (parent.has(basename4))
53732
53732
  return;
@@ -53751,7 +53751,7 @@ var require_nodefs_handler = __commonJS((exports, module) => {
53751
53751
  prevStats = newStats2;
53752
53752
  }
53753
53753
  } catch (error3) {
53754
- this.fsw._remove(dirname16, basename4);
53754
+ this.fsw._remove(dirname17, basename4);
53755
53755
  }
53756
53756
  } else if (parent.has(basename4)) {
53757
53757
  const at = newStats.atimeMs;
@@ -56328,7 +56328,7 @@ var require_client2 = __commonJS((exports) => {
56328
56328
  var require_config = __commonJS((exports) => {
56329
56329
  var { homedir: homedir2 } = __require("os");
56330
56330
  var { sep: sep2, join: join29 } = __require("path");
56331
- var { createHash: createHash16 } = __require("crypto");
56331
+ var { createHash: createHash17 } = __require("crypto");
56332
56332
  var { readFile: readFile$1 } = __require("fs/promises");
56333
56333
  var { IniSectionType: IniSectionType2 } = require_dist_cjs();
56334
56334
  var { normalizeProvider } = require_client2();
@@ -56483,7 +56483,7 @@ var require_config = __commonJS((exports) => {
56483
56483
  var DEFAULT_PROFILE = "default";
56484
56484
  var getProfileName = (init) => init.profile || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
56485
56485
  var getSSOTokenFilepath = (id) => {
56486
- const hasher = createHash16("sha1");
56486
+ const hasher = createHash17("sha1");
56487
56487
  const cacheName = hasher.update(id).digest("hex");
56488
56488
  return join29(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
56489
56489
  };
@@ -57833,7 +57833,7 @@ var require_endpoints = __commonJS((exports) => {
57833
57833
 
57834
57834
  // ../../node_modules/.pnpm/@smithy+core@3.29.7/node_modules/@smithy/core/dist-cjs/submodules/serde/index.js
57835
57835
  var require_serde = __commonJS((exports) => {
57836
- var { createHmac: createHmac3, createHash: createHash16, getRandomValues } = __require("crypto");
57836
+ var { createHmac: createHmac3, createHash: createHash17, getRandomValues } = __require("crypto");
57837
57837
  var { ReadStream, lstatSync: lstatSync2, fstatSync } = __require("fs");
57838
57838
  var { HttpResponse: HttpResponse2 } = require_transport2();
57839
57839
  var { toEndpointV1 } = require_endpoints();
@@ -58735,7 +58735,7 @@ var require_serde = __commonJS((exports) => {
58735
58735
  return Promise.resolve(this.hash.digest());
58736
58736
  }
58737
58737
  reset() {
58738
- this.hash = this.secret ? createHmac3(this.algorithmIdentifier, castSourceData(this.secret)) : createHash16(this.algorithmIdentifier);
58738
+ this.hash = this.secret ? createHmac3(this.algorithmIdentifier, castSourceData(this.secret)) : createHash17(this.algorithmIdentifier);
58739
58739
  }
58740
58740
  }
58741
58741
  function castSourceData(toCast, encoding) {
@@ -59474,7 +59474,7 @@ var require_checksum = __commonJS((exports) => {
59474
59474
  var { createReadStream: createReadStream2 } = __require("fs");
59475
59475
  var { Writable } = __require("stream");
59476
59476
  var { toUint8Array, concatBytes } = require_serde();
59477
- var { createHash: createHash16, createHmac: createHmac3 } = __require("crypto");
59477
+ var { createHash: createHash17, createHmac: createHmac3 } = __require("crypto");
59478
59478
  var zlib = __require("zlib");
59479
59479
  async function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
59480
59480
  const size = blob.size;
@@ -59639,7 +59639,7 @@ var require_checksum = __commonJS((exports) => {
59639
59639
  }
59640
59640
  var hasNativeCrypto$1 = (() => {
59641
59641
  try {
59642
- createHash16("md5");
59642
+ createHash17("md5");
59643
59643
  return true;
59644
59644
  } catch {
59645
59645
  return false;
@@ -59649,7 +59649,7 @@ var require_checksum = __commonJS((exports) => {
59649
59649
  function buildNativeClass$2() {
59650
59650
  return class Md5Node2 {
59651
59651
  digestLength = 16;
59652
- hash = createHash16("md5");
59652
+ hash = createHash17("md5");
59653
59653
  update(data) {
59654
59654
  this.hash.update(toUint8Array(data));
59655
59655
  }
@@ -59658,7 +59658,7 @@ var require_checksum = __commonJS((exports) => {
59658
59658
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
59659
59659
  }
59660
59660
  reset() {
59661
- this.hash = createHash16("md5");
59661
+ this.hash = createHash17("md5");
59662
59662
  }
59663
59663
  };
59664
59664
  }
@@ -59948,7 +59948,7 @@ var require_checksum = __commonJS((exports) => {
59948
59948
  ]);
59949
59949
  var hasNativeCrypto = (() => {
59950
59950
  try {
59951
- createHash16("sha256");
59951
+ createHash17("sha256");
59952
59952
  return true;
59953
59953
  } catch {
59954
59954
  return false;
@@ -59988,7 +59988,7 @@ var require_checksum = __commonJS((exports) => {
59988
59988
  this.finished = false;
59989
59989
  }
59990
59990
  createHash() {
59991
- return this.secret ? createHmac3("sha256", toBuffer(this.secret)) : createHash16("sha256");
59991
+ return this.secret ? createHmac3("sha256", toBuffer(this.secret)) : createHash17("sha256");
59992
59992
  }
59993
59993
  };
59994
59994
  }
@@ -74174,10 +74174,10 @@ var require_signin = __commonJS((exports) => {
74174
74174
  });
74175
74175
 
74176
74176
  // ../../node_modules/.pnpm/@aws-sdk+credential-provider-login@3.972.66/node_modules/@aws-sdk/credential-provider-login/dist-es/LoginCredentialsFetcher.js
74177
- import { createHash as createHash16, createPrivateKey, createPublicKey, sign } from "crypto";
74177
+ import { createHash as createHash17, createPrivateKey, createPublicKey, sign } from "crypto";
74178
74178
  import { promises as fs3 } from "fs";
74179
74179
  import { homedir as homedir3 } from "os";
74180
- import { dirname as dirname17, join as join32 } from "path";
74180
+ import { dirname as dirname18, join as join32 } from "path";
74181
74181
  var import_config24, import_protocols3, LoginCredentialsFetcher;
74182
74182
  var init_LoginCredentialsFetcher = __esm(() => {
74183
74183
  import_config24 = __toESM(require_config(), 1);
@@ -74329,7 +74329,7 @@ var init_LoginCredentialsFetcher = __esm(() => {
74329
74329
  }
74330
74330
  async saveToken(token) {
74331
74331
  const tokenFilePath = this.getTokenFilePath();
74332
- const directory = dirname17(tokenFilePath);
74332
+ const directory = dirname18(tokenFilePath);
74333
74333
  try {
74334
74334
  await fs3.mkdir(directory, { recursive: true });
74335
74335
  } catch (error3) {}
@@ -74338,7 +74338,7 @@ var init_LoginCredentialsFetcher = __esm(() => {
74338
74338
  getTokenFilePath() {
74339
74339
  const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join32(homedir3(), ".aws", "login", "cache");
74340
74340
  const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
74341
- const loginSessionSha256 = createHash16("sha256").update(loginSessionBytes).digest("hex");
74341
+ const loginSessionSha256 = createHash17("sha256").update(loginSessionBytes).digest("hex");
74342
74342
  return join32(directory, `${loginSessionSha256}.json`);
74343
74343
  }
74344
74344
  derToRawSignature(derSignature) {
@@ -100603,6 +100603,10 @@ var AuthDefaultSchema = exports_external.record(ResourceIdSchema, exports_extern
100603
100603
  }).default({}).describe("Specifies the validity duration for every JWT token.")
100604
100604
  })).default({}).describe("Define the authenticatable users in your app.");
100605
100605
 
100606
+ // src/feature/config/schema.ts
100607
+ var ConfigNameSchema = exports_external.string().regex(/^[a-z0-9-]+$/, "Invalid config name");
100608
+ var ConfigsSchema = exports_external.array(ConfigNameSchema).optional().describe("Define the config values for your app.");
100609
+
100606
100610
  // src/feature/domain/schema.ts
100607
100611
  var DomainNameSchema = exports_external.string().regex(/[a-z\-\_\.]/g, "Invalid domain name").describe("Enter a fully qualified domain name, for example, www.example.com. You can optionally include a trailing dot. If you omit the trailing dot, Amazon Route 53 assumes that the domain name that you specify is fully qualified. This means that Route 53 treats www.example.com (without a trailing dot) and www.example.com. (with a trailing dot) as identical.");
100608
100612
  var DNSTypeSchema = exports_external.enum(["A", "AAAA", "CAA", "CNAME", "DS", "MX", "NAPTR", "NS", "PTR", "SOA", "SPF", "SRV", "TXT"]).describe("The DNS record type.");
@@ -100744,6 +100748,11 @@ var sizeMax = (max) => {
100744
100748
  // src/feature/function/schema.ts
100745
100749
  var MemorySizeSchema = SizeSchema.refine(sizeMin(mebibytes(128)), "Minimum memory size is 128 MB").refine(sizeMax(gibibytes(10)), "Maximum memory size is 10 GB").describe("The amount of memory available to the function at runtime. Increasing the function memory also increases its CPU allocation. The value can be any multiple of 1 MB. You can specify a size value from 128 MB to 10 GB.");
100746
100750
  var TimeoutSchema = DurationSchema.refine(durationMin(seconds(10)), "Minimum timeout duration is 10 seconds").refine(durationMax(minutes(15)), "Maximum timeout duration is 15 minutes").describe("The amount of time that Lambda allows a function to run before stopping it. You can specify a size value from 1 second to 15 minutes.");
100751
+ var EphemeralStorageSizeSchema = SizeSchema.refine(sizeMin(mebibytes(512)), "Minimum ephemeral storage size is 512 MB").refine(sizeMax(gibibytes(10)), "Minimum ephemeral storage size is 10 GB").describe("The size of the function's /tmp directory. You can specify a size value from 512 MB to 10 GB.");
100752
+ var ReservedConcurrentExecutionsSchema = exports_external.number().int().min(0).describe("The number of simultaneous executions to reserve for the function. You can specify a number from 0.");
100753
+ var VPCSchema = exports_external.boolean().describe("Put the function inside your global VPC.");
100754
+ var DescriptionSchema = exports_external.string().describe("A description of the function.");
100755
+ var LayersSchema = exports_external.string().array().describe(`A list of function layers to add to the function's execution environment. Specify each layer by its name.`);
100747
100756
  var EnvironmentSchema = exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Environment variable key-value pairs.");
100748
100757
  var ArchitectureSchema = exports_external.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the function supports.");
100749
100758
  var RuntimeSchema = exports_external.enum(["nodejs18.x", "nodejs20.x", "nodejs22.x", "nodejs24.x"]).or(exports_external.literal("container")).or(exports_external.string()).describe("The identifier of the function's runtime.");
@@ -100782,6 +100791,7 @@ var LogSchema = exports_external.union([
100782
100791
  var FileCodeSchema = exports_external.object({
100783
100792
  file: LocalFileSchema.describe("The file path of the function code."),
100784
100793
  minify: MinifySchema.optional().default(true),
100794
+ moduleSideEffects: RelativePathSchema.array().default([]).describe(`A list of glob patterns for modules that should be flagged as having potential side effects. For example "./.svelte-kit/**" will flag every file inside the .svelte-kit folder.`),
100785
100795
  external: exports_external.string().array().optional().describe(`A list of external packages that won't be included in the bundle.`),
100786
100796
  importAsString: exports_external.string().array().optional().describe(`A list of glob patterns, which specifies the files that should be imported as string.`)
100787
100797
  });
@@ -100801,7 +100811,29 @@ var FunctionSchema = exports_external.union([
100801
100811
  })).pipe(FnSchema),
100802
100812
  FnSchema
100803
100813
  ]);
100804
- var FunctionsSchema = exports_external.record(ResourceIdSchema, FunctionSchema).optional().describe("Define the functions in your stack.");
100814
+ var StackFnSchema = exports_external.object({
100815
+ code: CodeSchema,
100816
+ handler: HandlerSchema.optional(),
100817
+ runtime: RuntimeSchema.optional(),
100818
+ description: DescriptionSchema.optional(),
100819
+ vpc: VPCSchema.optional(),
100820
+ log: LogSchema.optional(),
100821
+ timeout: TimeoutSchema.optional(),
100822
+ memorySize: MemorySizeSchema.optional(),
100823
+ architecture: ArchitectureSchema.optional(),
100824
+ ephemeralStorageSize: EphemeralStorageSizeSchema.optional(),
100825
+ reserved: ReservedConcurrentExecutionsSchema.optional(),
100826
+ layers: LayersSchema.optional(),
100827
+ environment: EnvironmentSchema.optional(),
100828
+ permissions: PermissionsSchema.optional()
100829
+ }).strict();
100830
+ var StackFunctionSchema = exports_external.union([
100831
+ LocalFileSchema.transform((code) => ({
100832
+ code
100833
+ })).pipe(StackFnSchema),
100834
+ StackFnSchema
100835
+ ]);
100836
+ var FunctionsSchema = exports_external.record(ResourceIdSchema, StackFunctionSchema).optional().describe("Define the functions in your stack.");
100805
100837
  var FunctionDefaultSchema = exports_external.object({
100806
100838
  runtime: RuntimeSchema.default("nodejs24.x"),
100807
100839
  handler: HandlerSchema.default("index.default"),
@@ -100816,6 +100848,10 @@ var FunctionDefaultSchema = exports_external.object({
100816
100848
  timeout: TimeoutSchema.default("15 minutes"),
100817
100849
  memorySize: MemorySizeSchema.default("1024 MB"),
100818
100850
  architecture: ArchitectureSchema.default("arm64"),
100851
+ vpc: VPCSchema.default(true),
100852
+ ephemeralStorageSize: EphemeralStorageSizeSchema.default("512 MB"),
100853
+ reserved: ReservedConcurrentExecutionsSchema.optional(),
100854
+ layers: LayersSchema.optional(),
100819
100855
  environment: EnvironmentSchema.optional(),
100820
100856
  permissions: PermissionsSchema.optional()
100821
100857
  }).default({});
@@ -100935,7 +100971,7 @@ var PermissionSchema2 = exports_external.object({
100935
100971
  resources: ResourcesSchema2
100936
100972
  });
100937
100973
  var PermissionsSchema2 = exports_external.union([PermissionSchema2.transform((v3) => [v3]), PermissionSchema2.array()]).describe("Add IAM permissions to your instance.");
100938
- var DescriptionSchema = exports_external.string().describe("A description of the instance.");
100974
+ var DescriptionSchema2 = exports_external.string().describe("A description of the instance.");
100939
100975
  var ImageSchema = exports_external.string().optional().describe("The URL of the container image to use. Default: public.ecr.aws/aws-cli/aws-cli:{architecture}");
100940
100976
  var validLogRetentionDays2 = [
100941
100977
  ...[1, 3, 5, 7, 14, 30, 60, 90, 120, 150],
@@ -100964,7 +101000,7 @@ var CodeSchema2 = exports_external.union([
100964
101000
  var StartupCommandSchema = exports_external.union([exports_external.string().transform((v3) => [v3]), exports_external.string().array()]).describe("Optional shell commands to run before the instance program starts.");
100965
101001
  var ISchema = exports_external.object({
100966
101002
  code: CodeSchema2,
100967
- description: DescriptionSchema.optional(),
101003
+ description: DescriptionSchema2.optional(),
100968
101004
  image: ImageSchema.optional(),
100969
101005
  startupCommand: StartupCommandSchema.optional(),
100970
101006
  log: LogSchema2.optional(),
@@ -101420,6 +101456,7 @@ var AppSchema = exports_external.object({
101420
101456
  region: RegionSchema.describe("The AWS region to deploy to."),
101421
101457
  profile: exports_external.string().describe("The AWS profile to deploy to."),
101422
101458
  protect: exports_external.boolean().default(false).describe("Protect your app & stacks from being deleted."),
101459
+ configs: ConfigsSchema,
101423
101460
  removal: exports_external.enum(["remove", "retain"]).default("remove").describe([
101424
101461
  "Configure how your resources are handled when they have to be removed.",
101425
101462
  "",
@@ -101476,10 +101513,6 @@ var CommandSchema = exports_external.union([
101476
101513
  ]);
101477
101514
  var CommandsSchema = exports_external.record(ResourceIdSchema, CommandSchema).optional().describe("Define the custom commands for your stack.");
101478
101515
 
101479
- // src/feature/config/schema.ts
101480
- var ConfigNameSchema = exports_external.string().regex(/^[a-z0-9-]+$/, "Invalid config name");
101481
- var ConfigsSchema = exports_external.array(ConfigNameSchema).optional().describe("Define the config values for your stack.");
101482
-
101483
101516
  // src/feature/cron/schema/schedule.ts
101484
101517
  var import_aws_cron_expression_validator = __toESM(require_src5(), 1);
101485
101518
  var RateExpressionSchema = exports_external.custom((value) => {
@@ -101885,7 +101918,6 @@ var StackSchema = exports_external.object({
101885
101918
  commands: CommandsSchema,
101886
101919
  rest: RestSchema,
101887
101920
  rpc: RpcSchema,
101888
- configs: ConfigsSchema,
101889
101921
  crons: CronsSchema,
101890
101922
  caches: CachesSchema,
101891
101923
  subscribers: SubscribersSchema,
@@ -102668,6 +102700,7 @@ var loadAppConfig = async (options) => {
102668
102700
  const appConfig = await readConfigWithStage(appFileName, options.stage);
102669
102701
  debug3("Validate app config file");
102670
102702
  const app = await validateConfig(AppSchema, appConfig.file, appConfig.data);
102703
+ app.stage = options.stage;
102671
102704
  return app;
102672
102705
  };
102673
102706
  var loadStackConfigs = async (options) => {
@@ -103465,8 +103498,18 @@ var ROUTE_MODULE_QUERY = "?awsless-route=";
103465
103498
  var formatRouteModuleId = (file2, routeKey) => {
103466
103499
  return `${file2}${ROUTE_MODULE_QUERY}${encodeURIComponent(routeKey)}`;
103467
103500
  };
103501
+ var createModuleMatcher = (patterns = []) => {
103502
+ const globs = patterns.map((pattern) => {
103503
+ return new Minimatch(pattern.replaceAll("\\", "/"), { dot: true });
103504
+ });
103505
+ return (id) => {
103506
+ const path2 = id.replaceAll("\\", "/");
103507
+ return globs.some((glob2) => glob2.match(path2));
103508
+ };
103509
+ };
103468
103510
  var bundleTypeScriptWithRolldown = async (props) => {
103469
103511
  const { format: format2 = "esm", minify = true } = props;
103512
+ const hasModuleSideEffects = createModuleMatcher(props.moduleSideEffects);
103470
103513
  const bundle = await rolldown({
103471
103514
  input: props.file,
103472
103515
  platform: "node",
@@ -103474,7 +103517,7 @@ var bundleTypeScriptWithRolldown = async (props) => {
103474
103517
  return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk") || props.external?.includes(importee);
103475
103518
  },
103476
103519
  treeshake: {
103477
- moduleSideEffects: (id, isExternal) => isExternal ? props.external?.includes(id) === true : id.startsWith(`${directories.root}/`) && !id.includes("/node_modules/")
103520
+ moduleSideEffects: (id, isExternal) => isExternal ? props.external?.includes(id) === true : hasModuleSideEffects(id) || id.startsWith(`${directories.root}/`) && !id.includes("/node_modules/")
103478
103521
  },
103479
103522
  onwarn: (error3) => {
103480
103523
  if (error3.code === "UNRESOLVED_IMPORT") {
@@ -103567,7 +103610,8 @@ var registerBundleFunction = (ctx, routeKey, props) => {
103567
103610
  file: props.code.file,
103568
103611
  exportName: parseExportName(props.handler ?? ctx.appConfig.defaults.function.handler),
103569
103612
  external: props.code.external,
103570
- importAsString: props.code.importAsString
103613
+ importAsString: props.code.importAsString,
103614
+ moduleSideEffects: props.code.moduleSideEffects
103571
103615
  });
103572
103616
  return bundle;
103573
103617
  };
@@ -103599,7 +103643,11 @@ ${entries2.join(`
103599
103643
  readFile7(runtime),
103600
103644
  ...handlers.map((handler) => dirname6(handler.file) === dirname6(runtime) ? readFile7(handler.file) : generateFileHash(workspace, handler.file))
103601
103645
  ]);
103602
- const hash2 = createHash8("sha1").update(entry).update(JSON.stringify([props.external, props.minify, handlers.map((h2) => [h2.external, h2.importAsString])]));
103646
+ const hash2 = createHash8("sha1").update(entry).update(JSON.stringify([
103647
+ props.external,
103648
+ props.minify,
103649
+ handlers.map((h2) => [h2.external, h2.importAsString, h2.moduleSideEffects])
103650
+ ]));
103603
103651
  for (const item of hashes) {
103604
103652
  hash2.update(item);
103605
103653
  }
@@ -103609,6 +103657,7 @@ ${entries2.join(`
103609
103657
  const entryFile = join10(temp.path, "entry.ts");
103610
103658
  await writeFile5(entryFile, entry);
103611
103659
  const importAsString2 = handlers.flatMap((handler) => handler.importAsString ?? []);
103660
+ const moduleSideEffects = handlers.flatMap((handler) => handler.moduleSideEffects ?? []);
103612
103661
  const bundle = await bundleTypeScriptWithRolldown({
103613
103662
  file: entryFile,
103614
103663
  minify: props.minify,
@@ -103617,7 +103666,8 @@ ${entries2.join(`
103617
103666
  ...props.external ?? [],
103618
103667
  ...handlers.flatMap((handler) => handler.external ?? [])
103619
103668
  ],
103620
- importAsString: importAsString2.length > 0 ? importAsString2 : undefined
103669
+ importAsString: importAsString2.length > 0 ? importAsString2 : undefined,
103670
+ moduleSideEffects: moduleSideEffects.length > 0 ? moduleSideEffects : undefined
103621
103671
  });
103622
103672
  await temp.delete();
103623
103673
  await rm6(getBuildPath("bundle", props.name, "files"), { recursive: true, force: true });
@@ -103796,7 +103846,15 @@ var bundleFeature = defineFeature({
103796
103846
  }),
103797
103847
  sourceCodeHash: sourceHash,
103798
103848
  environment: {
103799
- variables: {}
103849
+ variables: {
103850
+ APP: ctx.appConfig.name,
103851
+ APP_ID: ctx.appId,
103852
+ AWS_ACCOUNT_ID: ctx.accountId,
103853
+ REGION: ctx.appConfig.region,
103854
+ STAGE: ctx.appConfig.stage ?? "default",
103855
+ STANDALONE: "false",
103856
+ AWS_USE_DUALSTACK_ENDPOINT: "true"
103857
+ }
103800
103858
  },
103801
103859
  vpcConfig: {
103802
103860
  securityGroupIds: [ctx.shared.get("vpc", "security-group-id")],
@@ -103863,10 +103921,6 @@ var bundleFeature = defineFeature({
103863
103921
  resources: [logGroup.arn.pipe((arn) => `${arn}:*`)]
103864
103922
  });
103865
103923
  }
103866
- addEnv("APP", ctx.appConfig.name);
103867
- addEnv("APP_ID", ctx.appId);
103868
- addEnv("AWS_ACCOUNT_ID", ctx.accountId);
103869
- addEnv("AWS_USE_DUALSTACK_ENDPOINT", "true");
103870
103924
  for (const [name2, value] of Object.entries(defaults2.environment ?? {})) {
103871
103925
  addEnv(name2, value);
103872
103926
  }
@@ -104134,10 +104188,10 @@ var configFeature = defineFeature({
104134
104188
  async onTypeGen(ctx) {
104135
104189
  const gen = new TypeFile("awsless");
104136
104190
  const resources = new TypeObject(0, false);
104191
+ for (const name of ctx.appConfig.configs ?? []) {
104192
+ resources.addConst(name, "string");
104193
+ }
104137
104194
  for (const stack of ctx.stackConfigs) {
104138
- for (const name of stack.configs ?? []) {
104139
- resources.addConst(name, "string");
104140
- }
104141
104195
  for (const site of Object.values(stack.sites ?? {})) {
104142
104196
  for (const name of site.build?.configs ?? []) {
104143
104197
  resources.addConst(name, "string");
@@ -104159,10 +104213,7 @@ var configFeature = defineFeature({
104159
104213
  `arn:aws:ssm:${ctx.appConfig.region}:${ctx.accountId}:parameter${configParameterPrefix(ctx.app.name)}/*`
104160
104214
  ]
104161
104215
  });
104162
- },
104163
- onStack(ctx) {
104164
- const configs = ctx.stackConfig.configs ?? [];
104165
- for (const name of configs) {
104216
+ for (const name of ctx.appConfig.configs ?? []) {
104166
104217
  ctx.registerConfig(name);
104167
104218
  ctx.addEnv(`CONFIG_${constantCase(name)}`, name);
104168
104219
  }
@@ -104476,8 +104527,471 @@ var domainFeature = defineFeature({
104476
104527
  });
104477
104528
 
104478
104529
  // src/feature/function/index.ts
104530
+ import { formatRouteEnvName } from "awsless";
104479
104531
  import { relative as relative3 } from "path";
104532
+
104533
+ // src/feature/function/util.ts
104534
+ import { seconds as seconds4, toDays as toDays6, toSeconds as toSeconds4 } from "@awsless/duration";
104535
+ import { generateFileHash as generateFileHash2 } from "@awsless/ts-file-cache";
104480
104536
  var import_deepmerge = __toESM(require_cjs2(), 1);
104537
+ import { createHash as createHash10 } from "crypto";
104538
+
104539
+ // src/feature/on-error-log/util.ts
104540
+ var filterPattern = `{${[
104541
+ `$.level = "WARN"`,
104542
+ `$.level = "ERROR"`,
104543
+ `$.level = "FATAL"`,
104544
+ `($.type = "platform.report" && $.record.status = "timeout")`,
104545
+ `($.type = "platform.report" && $.record.status = "error")`,
104546
+ `($.type = "platform.report" && $.record.status = "failure")`
104547
+ ].join(" || ")}}`;
104548
+
104549
+ // src/feature/function/util.ts
104550
+ var standaloneFields = [
104551
+ "runtime",
104552
+ "description",
104553
+ "vpc",
104554
+ "log",
104555
+ "timeout",
104556
+ "memorySize",
104557
+ "architecture",
104558
+ "ephemeralStorageSize",
104559
+ "reserved",
104560
+ "layers",
104561
+ "environment",
104562
+ "permissions"
104563
+ ];
104564
+ var isStandaloneFunction = (props) => {
104565
+ return standaloneFields.some((field) => typeof props[field] !== "undefined");
104566
+ };
104567
+ var createLambdaFunction = (ctx, id, local) => {
104568
+ const group = new Group(ctx.stack, "function", id);
104569
+ const props = import_deepmerge.default(ctx.appConfig.defaults.function, local);
104570
+ if (props.runtime === "container") {
104571
+ throw new FileError(ctx.stackConfig.file, `The "container" runtime isn't supported for stack functions.`);
104572
+ }
104573
+ for (const layerId of props.layers ?? []) {
104574
+ if (!(layerId in (ctx.appConfig.defaults.layers ?? {}))) {
104575
+ throw new FileError(ctx.stackConfig.file, `Layer "${layerId}" is not defined in app.json`);
104576
+ }
104577
+ }
104578
+ const name = formatLocalResourceName({
104579
+ appName: ctx.app.name,
104580
+ stackName: ctx.stack.name,
104581
+ resourceType: "function",
104582
+ resourceName: id
104583
+ });
104584
+ const roleName = shortId(`${ctx.app.name}:${ctx.stack.name}:function:${id}:${ctx.appId}`);
104585
+ const fileCode = local.code;
104586
+ ctx.registerBuild("function", name, async (build2, { workspace }) => {
104587
+ const fingerprint = createHash10("sha1").update(await generateFileHash2(workspace, fileCode.file)).update(JSON.stringify([
104588
+ fileCode.minify,
104589
+ fileCode.external,
104590
+ fileCode.importAsString,
104591
+ fileCode.moduleSideEffects
104592
+ ])).digest("hex");
104593
+ return build2(fingerprint, async (write) => {
104594
+ const bundle = await bundleTypeScriptWithRolldown({
104595
+ file: fileCode.file,
104596
+ minify: fileCode.minify,
104597
+ external: [
104598
+ ...fileCode.external ?? [],
104599
+ ...(props.layers ?? []).flatMap((layerId) => ctx.shared.entry("layer", "packages", layerId))
104600
+ ],
104601
+ moduleSideEffects: fileCode.moduleSideEffects,
104602
+ importAsString: fileCode.importAsString
104603
+ });
104604
+ const archive = await zipFiles(bundle.files);
104605
+ await Promise.all([
104606
+ write("HASH", bundle.hash),
104607
+ write("bundle.zip", archive),
104608
+ ...bundle.files.map((file2) => write(`files/${file2.name}`, file2.code)),
104609
+ ...bundle.files.map((file2) => file2.map && write(`files/${file2.name}.map`, file2.map))
104610
+ ]);
104611
+ return {
104612
+ size: formatByteSize(archive.byteLength)
104613
+ };
104614
+ });
104615
+ });
104616
+ const sourceHash = $file(getBuildPath("function", name, "HASH"));
104617
+ const code = new aws.s3.BucketObject(group, "code", {
104618
+ bucket: ctx.shared.get("asset", "bucket").name,
104619
+ key: `lambda/${name}.zip`,
104620
+ source: relativePath(getBuildPath("function", name, "bundle.zip")),
104621
+ sourceHash
104622
+ }, {
104623
+ replaceOnChanges: ["bucket", "key"]
104624
+ });
104625
+ const role = new aws.iam.Role(group, "role", {
104626
+ name: roleName,
104627
+ description: name,
104628
+ assumeRolePolicy: JSON.stringify({
104629
+ Version: "2012-10-17",
104630
+ Statement: [
104631
+ {
104632
+ Effect: "Allow",
104633
+ Action: "sts:AssumeRole",
104634
+ Principal: {
104635
+ Service: ["lambda.amazonaws.com"]
104636
+ }
104637
+ }
104638
+ ]
104639
+ })
104640
+ });
104641
+ const statements = [];
104642
+ const statementDeps = new Set;
104643
+ const addPermission = (...permissions) => {
104644
+ statements.push(...permissions);
104645
+ for (const dep of findInputDeps(permissions)) {
104646
+ statementDeps.add(dep);
104647
+ }
104648
+ };
104649
+ addPermission(...props.permissions ?? []);
104650
+ ctx.onPermission((statement) => {
104651
+ addPermission(statement);
104652
+ });
104653
+ const policy = new aws.iam.RolePolicy(group, "policy", {
104654
+ role: role.name,
104655
+ name: "lambda-policy",
104656
+ policy: new Output(statementDeps, async (resolve3) => {
104657
+ const list2 = await resolveInputs(statements);
104658
+ resolve3(JSON.stringify({
104659
+ Version: "2012-10-17",
104660
+ Statement: compactPolicyStatements(list2).map((statement) => ({
104661
+ Effect: pascalCase(statement.effect ?? "allow"),
104662
+ Action: statement.actions,
104663
+ Resource: statement.resources,
104664
+ Condition: statement.conditions
104665
+ }))
104666
+ }));
104667
+ })
104668
+ });
104669
+ const dependsOn = [policy];
104670
+ if (props.vpc) {
104671
+ dependsOn.push(new aws.iam.RolePolicy(group, "vpc-policy", {
104672
+ role: role.name,
104673
+ name: "lambda-vpc-policy",
104674
+ policy: JSON.stringify({
104675
+ Version: "2012-10-17",
104676
+ Statement: [
104677
+ {
104678
+ Effect: "Allow",
104679
+ Action: [
104680
+ "ec2:CreateNetworkInterface",
104681
+ "ec2:DescribeNetworkInterfaces",
104682
+ "ec2:DescribeSubnets",
104683
+ "ec2:DeleteNetworkInterface",
104684
+ "ec2:AssignPrivateIpAddresses",
104685
+ "ec2:UnassignPrivateIpAddresses"
104686
+ ],
104687
+ Resource: ["*"]
104688
+ }
104689
+ ]
104690
+ })
104691
+ }));
104692
+ }
104693
+ const variables = {};
104694
+ const logFormats = {
104695
+ text: "Text",
104696
+ json: "JSON"
104697
+ };
104698
+ const lambda = new aws.lambda.Function(group, "function", {
104699
+ functionName: name,
104700
+ description: props.description ?? name,
104701
+ role: role.arn,
104702
+ runtime: props.runtime,
104703
+ handler: props.handler,
104704
+ timeout: toSeconds4(props.timeout),
104705
+ memorySize: toMebibytes(props.memorySize),
104706
+ architectures: [props.architecture],
104707
+ reservedConcurrentExecutions: props.reserved,
104708
+ ephemeralStorage: {
104709
+ size: toMebibytes(props.ephemeralStorageSize)
104710
+ },
104711
+ layers: props.layers?.map((layerId) => ctx.shared.entry("layer", "arn", layerId)),
104712
+ timeouts: {
104713
+ create: "30s",
104714
+ update: "30s",
104715
+ delete: "30s"
104716
+ },
104717
+ s3Bucket: code.bucket,
104718
+ s3ObjectVersion: code.versionId,
104719
+ s3Key: code.key.pipe((name2) => {
104720
+ if (name2.startsWith("/")) {
104721
+ return name2.substring(1);
104722
+ }
104723
+ return name2;
104724
+ }),
104725
+ sourceCodeHash: sourceHash,
104726
+ environment: {
104727
+ variables
104728
+ },
104729
+ vpcConfig: props.vpc ? {
104730
+ securityGroupIds: [ctx.shared.get("vpc", "security-group-id")],
104731
+ subnetIds: ctx.shared.get("vpc", "private-subnets"),
104732
+ ipv6AllowedForDualStack: true
104733
+ } : undefined,
104734
+ loggingConfig: {
104735
+ logGroup: `/aws/lambda/${name}`,
104736
+ logFormat: logFormats[props.log.format],
104737
+ applicationLogLevel: props.log.format === "json" ? props.log.level?.toUpperCase() : undefined,
104738
+ systemLogLevel: props.log.format === "json" ? props.log.system?.toUpperCase() : undefined
104739
+ }
104740
+ }, {
104741
+ dependsOn
104742
+ });
104743
+ ctx.addFunction(lambda);
104744
+ variables.APP = ctx.appConfig.name;
104745
+ variables.APP_ID = ctx.appId;
104746
+ variables.AWS_ACCOUNT_ID = ctx.accountId;
104747
+ variables.REGION = ctx.appConfig.region;
104748
+ variables.STAGE = ctx.appConfig.stage ?? "default";
104749
+ variables.STACK = ctx.stackConfig.name;
104750
+ variables.STANDALONE = "true";
104751
+ if (props.vpc) {
104752
+ variables.AWS_USE_DUALSTACK_ENDPOINT = "true";
104753
+ }
104754
+ for (const [key, value] of Object.entries(props.environment ?? {})) {
104755
+ variables[key] = value;
104756
+ }
104757
+ ctx.onEnv((name2, value) => {
104758
+ variables[name2] = value;
104759
+ });
104760
+ ctx.onBind((name2, value) => {
104761
+ variables[name2] = value;
104762
+ });
104763
+ if (props.log.retention.value > 0n) {
104764
+ const logGroup = new aws.cloudwatch.LogGroup(group, "log", {
104765
+ name: `/aws/lambda/${name}`,
104766
+ retentionInDays: toDays6(props.log.retention)
104767
+ });
104768
+ addPermission({
104769
+ actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
104770
+ resources: [logGroup.arn.pipe((arn) => `${arn}:*`)]
104771
+ });
104772
+ if (ctx.shared.has("on-error-log", "subscriber-arn")) {
104773
+ new aws.cloudwatch.LogSubscriptionFilter(group, "on-error-log", {
104774
+ name: "error-log-subscription",
104775
+ destinationArn: ctx.shared.get("on-error-log", "subscriber-arn"),
104776
+ logGroupName: logGroup.name,
104777
+ filterPattern
104778
+ }, {
104779
+ dependsOn: [ctx.shared.get("on-error-log", "permission")]
104780
+ });
104781
+ }
104782
+ }
104783
+ return {
104784
+ name,
104785
+ group,
104786
+ lambda,
104787
+ policy,
104788
+ code,
104789
+ setEnvironment(name2, value) {
104790
+ variables[name2] = value;
104791
+ },
104792
+ addPermission(...permissions) {
104793
+ addPermission(...permissions);
104794
+ }
104795
+ };
104796
+ };
104797
+ var createPrebuildLambdaFunction = (parentGroup, ctx, ns, id, props) => {
104798
+ let name;
104799
+ let roleName;
104800
+ const group = new Group(parentGroup, "function", id);
104801
+ if ("stack" in ctx) {
104802
+ name = formatLocalResourceName({
104803
+ appName: ctx.app.name,
104804
+ stackName: ctx.stack.name,
104805
+ resourceType: ns,
104806
+ resourceName: id
104807
+ });
104808
+ roleName = formatLocalResourceName({
104809
+ appName: ctx.app.name,
104810
+ stackName: ctx.stack.name,
104811
+ resourceType: ns,
104812
+ resourceName: id,
104813
+ postfix: ctx.appId
104814
+ });
104815
+ } else {
104816
+ name = formatGlobalResourceName({
104817
+ appName: ctx.app.name,
104818
+ resourceType: ns,
104819
+ resourceName: id
104820
+ });
104821
+ roleName = formatGlobalResourceName({
104822
+ appName: ctx.app.name,
104823
+ resourceType: ns,
104824
+ resourceName: id,
104825
+ postfix: ctx.appId
104826
+ });
104827
+ }
104828
+ const sourceHash = $file(props.bundleHash);
104829
+ const code = new aws.s3.BucketObject(group, "code", {
104830
+ bucket: ctx.shared.get("asset", "bucket").name,
104831
+ key: `lambda/${name}.zip`,
104832
+ source: relativePath(props.bundleFile),
104833
+ sourceHash
104834
+ }, {
104835
+ replaceOnChanges: ["bucket", "key"]
104836
+ });
104837
+ const role = new aws.iam.Role(group, "role", {
104838
+ name: roleName,
104839
+ description: name,
104840
+ assumeRolePolicy: JSON.stringify({
104841
+ Version: "2012-10-17",
104842
+ Statement: [
104843
+ {
104844
+ Effect: "Allow",
104845
+ Action: "sts:AssumeRole",
104846
+ Principal: {
104847
+ Service: ["lambda.amazonaws.com"]
104848
+ }
104849
+ }
104850
+ ]
104851
+ })
104852
+ });
104853
+ const statements = [];
104854
+ const statementDeps = new Set;
104855
+ const addPermission = (...permissions) => {
104856
+ statements.push(...permissions);
104857
+ for (const dep of findInputDeps(permissions)) {
104858
+ statementDeps.add(dep);
104859
+ }
104860
+ };
104861
+ const policy = new aws.iam.RolePolicy(group, "policy", {
104862
+ role: role.name,
104863
+ name: "lambda-policy",
104864
+ policy: new Output(statementDeps, async (resolve3) => {
104865
+ const list2 = await resolveInputs(statements);
104866
+ resolve3(JSON.stringify({
104867
+ Version: "2012-10-17",
104868
+ Statement: compactPolicyStatements(list2).map((statement) => ({
104869
+ Effect: pascalCase(statement.effect ?? "allow"),
104870
+ Action: statement.actions,
104871
+ Resource: statement.resources,
104872
+ Condition: statement.conditions
104873
+ }))
104874
+ }));
104875
+ })
104876
+ });
104877
+ const dependsOn = [policy];
104878
+ if (props.vpc) {
104879
+ dependsOn.push(new aws.iam.RolePolicy(group, "vpc-policy", {
104880
+ role: role.name,
104881
+ name: "lambda-vpc-policy",
104882
+ policy: JSON.stringify({
104883
+ Version: "2012-10-17",
104884
+ Statement: [
104885
+ {
104886
+ Effect: "Allow",
104887
+ Action: [
104888
+ "ec2:CreateNetworkInterface",
104889
+ "ec2:DescribeNetworkInterfaces",
104890
+ "ec2:DescribeSubnets",
104891
+ "ec2:DeleteNetworkInterface",
104892
+ "ec2:AssignPrivateIpAddresses",
104893
+ "ec2:UnassignPrivateIpAddresses"
104894
+ ],
104895
+ Resource: ["*"]
104896
+ }
104897
+ ]
104898
+ })
104899
+ }));
104900
+ }
104901
+ const variables = {};
104902
+ const logFormats = {
104903
+ text: "Text",
104904
+ json: "JSON"
104905
+ };
104906
+ const lambda = new aws.lambda.Function(group, "function", {
104907
+ functionName: name,
104908
+ description: name,
104909
+ role: role.arn,
104910
+ runtime: props.runtime,
104911
+ handler: props.handler,
104912
+ timeout: toSeconds4(props.timeout ?? seconds4(10)),
104913
+ memorySize: toMebibytes(props.memorySize ?? mebibytes(128)),
104914
+ architectures: [props.architecture ?? "arm64"],
104915
+ timeouts: {
104916
+ create: "30s",
104917
+ update: "30s",
104918
+ delete: "30s"
104919
+ },
104920
+ s3Bucket: code.bucket,
104921
+ s3ObjectVersion: code.versionId,
104922
+ s3Key: code.key.pipe((name2) => {
104923
+ if (name2.startsWith("/")) {
104924
+ return name2.substring(1);
104925
+ }
104926
+ return name2;
104927
+ }),
104928
+ sourceCodeHash: sourceHash,
104929
+ environment: {
104930
+ variables
104931
+ },
104932
+ vpcConfig: props.vpc ? {
104933
+ securityGroupIds: [ctx.shared.get("vpc", "security-group-id")],
104934
+ subnetIds: ctx.shared.get("vpc", "private-subnets"),
104935
+ ipv6AllowedForDualStack: true
104936
+ } : undefined,
104937
+ loggingConfig: {
104938
+ logGroup: `/aws/lambda/${name}`,
104939
+ logFormat: logFormats[props.log?.format ?? "json"],
104940
+ applicationLogLevel: (props.log?.format ?? "json") === "json" ? props.log?.level?.toUpperCase() : undefined,
104941
+ systemLogLevel: (props.log?.format ?? "json") === "json" ? props.log?.system?.toUpperCase() : undefined
104942
+ }
104943
+ }, {
104944
+ dependsOn
104945
+ });
104946
+ variables.APP = ctx.appConfig.name;
104947
+ variables.APP_ID = ctx.appId;
104948
+ variables.AWS_ACCOUNT_ID = ctx.accountId;
104949
+ variables.REGION = ctx.appConfig.region;
104950
+ variables.STAGE = ctx.appConfig.stage ?? "default";
104951
+ if ("stackConfig" in ctx) {
104952
+ variables.STACK = ctx.stackConfig.name;
104953
+ }
104954
+ if (props.vpc) {
104955
+ variables.AWS_USE_DUALSTACK_ENDPOINT = "true";
104956
+ }
104957
+ const retention = props.log?.retention;
104958
+ if (retention && retention.value > 0n) {
104959
+ const logGroup = new aws.cloudwatch.LogGroup(group, "log", {
104960
+ name: `/aws/lambda/${name}`,
104961
+ retentionInDays: toDays6(retention)
104962
+ });
104963
+ addPermission({
104964
+ actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
104965
+ resources: [logGroup.arn.pipe((arn) => `${arn}:*`)]
104966
+ });
104967
+ if (ctx.shared.has("on-error-log", "subscriber-arn")) {
104968
+ new aws.cloudwatch.LogSubscriptionFilter(group, "on-error-log", {
104969
+ name: "error-log-subscription",
104970
+ destinationArn: ctx.shared.get("on-error-log", "subscriber-arn"),
104971
+ logGroupName: logGroup.name,
104972
+ filterPattern
104973
+ }, {
104974
+ dependsOn: [ctx.shared.get("on-error-log", "permission")]
104975
+ });
104976
+ }
104977
+ }
104978
+ return {
104979
+ name,
104980
+ group,
104981
+ lambda,
104982
+ policy,
104983
+ code,
104984
+ setEnvironment(name2, value) {
104985
+ variables[name2] = value;
104986
+ },
104987
+ addPermission(...permissions) {
104988
+ addPermission(...permissions);
104989
+ }
104990
+ };
104991
+ };
104992
+
104993
+ // src/feature/function/index.ts
104994
+ var import_deepmerge2 = __toESM(require_cjs2(), 1);
104481
104995
  var typeGenCode3 = `
104482
104996
  import { InvokeOptions, InvokeResponse } from '@awsless/lambda'
104483
104997
  import type { PartialDeep } from 'type-fest'
@@ -104518,7 +105032,7 @@ var functionFeature = defineFeature({
104518
105032
  const mock = new TypeObject(2);
104519
105033
  const mockResponse = new TypeObject(2);
104520
105034
  for (const [name, local] of Object.entries(stack.functions || {})) {
104521
- const props = import_deepmerge.default(ctx.appConfig.defaults.function, local);
105035
+ const props = import_deepmerge2.default(ctx.appConfig.defaults.function, local);
104522
105036
  const varName = camelCase(`${stack.name}-${name}`);
104523
105037
  const funcName = formatLocalResourceName({
104524
105038
  appName: ctx.appConfig.name,
@@ -104561,25 +105075,20 @@ var functionFeature = defineFeature({
104561
105075
  },
104562
105076
  onStack(ctx) {
104563
105077
  for (const [id, props] of Object.entries(ctx.stackConfig.functions ?? {})) {
104564
- registerBundleFunction(ctx, formatRouteKey(ctx.stack.name, "function", id), props);
105078
+ const routeKey = formatRouteKey(ctx.stack.name, "function", id);
105079
+ if (!isStandaloneFunction(props)) {
105080
+ registerBundleFunction(ctx, routeKey, props);
105081
+ continue;
105082
+ }
105083
+ createLambdaFunction(ctx, id, props);
105084
+ const bundle = ctx.shared.get("bundle", "main");
105085
+ bundle.addEnv(formatRouteEnvName(routeKey, "STANDALONE"), "true");
104565
105086
  }
104566
105087
  }
104567
105088
  });
104568
105089
 
104569
105090
  // src/feature/on-error-log/index.ts
104570
- import { formatRouteEnvName } from "awsless";
104571
-
104572
- // src/feature/on-error-log/util.ts
104573
- var filterPattern = `{${[
104574
- `$.level = "WARN"`,
104575
- `$.level = "ERROR"`,
104576
- `$.level = "FATAL"`,
104577
- `($.type = "platform.report" && $.record.status = "timeout")`,
104578
- `($.type = "platform.report" && $.record.status = "error")`,
104579
- `($.type = "platform.report" && $.record.status = "failure")`
104580
- ].join(" || ")}}`;
104581
-
104582
- // src/feature/on-error-log/index.ts
105091
+ import { formatRouteEnvName as formatRouteEnvName2 } from "awsless";
104583
105092
  import { dirname as dirname7, join as join12 } from "path";
104584
105093
  import { fileURLToPath as fileURLToPath4 } from "url";
104585
105094
  var onErrorLogFeature = defineFeature({
@@ -104599,7 +105108,7 @@ var onErrorLogFeature = defineFeature({
104599
105108
  file: join12(dirname7(fileURLToPath4(import.meta.url)), "/handlers/on-error-log.js"),
104600
105109
  exportName: "default"
104601
105110
  });
104602
- bundle.addEnv(formatRouteEnvName(handlerRoute, "CONSUMER"), consumerRoute);
105111
+ bundle.addEnv(formatRouteEnvName2(handlerRoute, "CONSUMER"), consumerRoute);
104603
105112
  const requestTable = new aws.dynamodb.Table(group, "requests", {
104604
105113
  name: formatGlobalResourceName({
104605
105114
  appName: ctx.app.name,
@@ -104619,7 +105128,7 @@ var onErrorLogFeature = defineFeature({
104619
105128
  }
104620
105129
  ]
104621
105130
  });
104622
- bundle.addEnv(formatRouteEnvName(handlerRoute, "TABLE"), requestTable.name);
105131
+ bundle.addEnv(formatRouteEnvName2(handlerRoute, "TABLE"), requestTable.name);
104623
105132
  bundle.addPermission({
104624
105133
  effect: "allow",
104625
105134
  actions: ["dynamodb:PutItem", "dynamodb:GetItem"],
@@ -104654,204 +105163,6 @@ var onErrorLogFeature = defineFeature({
104654
105163
  import { days as days8, toSeconds as toSeconds5 } from "@awsless/duration";
104655
105164
  import { dirname as dirname8, join as join13 } from "path";
104656
105165
  import { fileURLToPath as fileURLToPath5 } from "url";
104657
-
104658
- // src/feature/function/prebuild.ts
104659
- import { seconds as seconds4, toDays as toDays6, toSeconds as toSeconds4 } from "@awsless/duration";
104660
- var createPrebuildLambdaFunction = (parentGroup, ctx, ns, id, props) => {
104661
- let name;
104662
- let roleName;
104663
- const group = new Group(parentGroup, "function", id);
104664
- if ("stack" in ctx) {
104665
- name = formatLocalResourceName({
104666
- appName: ctx.app.name,
104667
- stackName: ctx.stack.name,
104668
- resourceType: ns,
104669
- resourceName: id
104670
- });
104671
- roleName = formatLocalResourceName({
104672
- appName: ctx.app.name,
104673
- stackName: ctx.stack.name,
104674
- resourceType: ns,
104675
- resourceName: id,
104676
- postfix: ctx.appId
104677
- });
104678
- } else {
104679
- name = formatGlobalResourceName({
104680
- appName: ctx.app.name,
104681
- resourceType: ns,
104682
- resourceName: id
104683
- });
104684
- roleName = formatGlobalResourceName({
104685
- appName: ctx.app.name,
104686
- resourceType: ns,
104687
- resourceName: id,
104688
- postfix: ctx.appId
104689
- });
104690
- }
104691
- const sourceHash = $file(props.bundleHash);
104692
- const code = new aws.s3.BucketObject(group, "code", {
104693
- bucket: ctx.shared.get("asset", "bucket").name,
104694
- key: `lambda/${name}.zip`,
104695
- source: relativePath(props.bundleFile),
104696
- sourceHash
104697
- }, {
104698
- replaceOnChanges: ["bucket", "key"]
104699
- });
104700
- const role = new aws.iam.Role(group, "role", {
104701
- name: roleName,
104702
- description: name,
104703
- assumeRolePolicy: JSON.stringify({
104704
- Version: "2012-10-17",
104705
- Statement: [
104706
- {
104707
- Effect: "Allow",
104708
- Action: "sts:AssumeRole",
104709
- Principal: {
104710
- Service: ["lambda.amazonaws.com"]
104711
- }
104712
- }
104713
- ]
104714
- })
104715
- });
104716
- const statements = [];
104717
- const statementDeps = new Set;
104718
- const addPermission = (...permissions) => {
104719
- statements.push(...permissions);
104720
- for (const dep of findInputDeps(permissions)) {
104721
- statementDeps.add(dep);
104722
- }
104723
- };
104724
- const policy = new aws.iam.RolePolicy(group, "policy", {
104725
- role: role.name,
104726
- name: "lambda-policy",
104727
- policy: new Output(statementDeps, async (resolve3) => {
104728
- const list2 = await resolveInputs(statements);
104729
- resolve3(JSON.stringify({
104730
- Version: "2012-10-17",
104731
- Statement: compactPolicyStatements(list2).map((statement) => ({
104732
- Effect: pascalCase(statement.effect ?? "allow"),
104733
- Action: statement.actions,
104734
- Resource: statement.resources,
104735
- Condition: statement.conditions
104736
- }))
104737
- }));
104738
- })
104739
- });
104740
- const dependsOn = [policy];
104741
- if (props.vpc) {
104742
- dependsOn.push(new aws.iam.RolePolicy(group, "vpc-policy", {
104743
- role: role.name,
104744
- name: "lambda-vpc-policy",
104745
- policy: JSON.stringify({
104746
- Version: "2012-10-17",
104747
- Statement: [
104748
- {
104749
- Effect: "Allow",
104750
- Action: [
104751
- "ec2:CreateNetworkInterface",
104752
- "ec2:DescribeNetworkInterfaces",
104753
- "ec2:DescribeSubnets",
104754
- "ec2:DeleteNetworkInterface",
104755
- "ec2:AssignPrivateIpAddresses",
104756
- "ec2:UnassignPrivateIpAddresses"
104757
- ],
104758
- Resource: ["*"]
104759
- }
104760
- ]
104761
- })
104762
- }));
104763
- }
104764
- const variables = {};
104765
- const logFormats = {
104766
- text: "Text",
104767
- json: "JSON"
104768
- };
104769
- const lambda = new aws.lambda.Function(group, "function", {
104770
- functionName: name,
104771
- description: name,
104772
- role: role.arn,
104773
- runtime: props.runtime,
104774
- handler: props.handler,
104775
- timeout: toSeconds4(props.timeout ?? seconds4(10)),
104776
- memorySize: toMebibytes(props.memorySize ?? mebibytes(128)),
104777
- architectures: [props.architecture ?? "arm64"],
104778
- timeouts: {
104779
- create: "30s",
104780
- update: "30s",
104781
- delete: "30s"
104782
- },
104783
- s3Bucket: code.bucket,
104784
- s3ObjectVersion: code.versionId,
104785
- s3Key: code.key.pipe((name2) => {
104786
- if (name2.startsWith("/")) {
104787
- return name2.substring(1);
104788
- }
104789
- return name2;
104790
- }),
104791
- sourceCodeHash: sourceHash,
104792
- environment: {
104793
- variables
104794
- },
104795
- vpcConfig: props.vpc ? {
104796
- securityGroupIds: [ctx.shared.get("vpc", "security-group-id")],
104797
- subnetIds: ctx.shared.get("vpc", "private-subnets"),
104798
- ipv6AllowedForDualStack: true
104799
- } : undefined,
104800
- loggingConfig: {
104801
- logGroup: `/aws/lambda/${name}`,
104802
- logFormat: logFormats[props.log?.format ?? "json"],
104803
- applicationLogLevel: (props.log?.format ?? "json") === "json" ? props.log?.level?.toUpperCase() : undefined,
104804
- systemLogLevel: (props.log?.format ?? "json") === "json" ? props.log?.system?.toUpperCase() : undefined
104805
- }
104806
- }, {
104807
- dependsOn
104808
- });
104809
- variables.APP = ctx.appConfig.name;
104810
- variables.APP_ID = ctx.appId;
104811
- variables.AWS_ACCOUNT_ID = ctx.accountId;
104812
- if ("stackConfig" in ctx) {
104813
- variables.STACK = ctx.stackConfig.name;
104814
- }
104815
- if (props.vpc) {
104816
- variables.AWS_USE_DUALSTACK_ENDPOINT = "true";
104817
- }
104818
- const retention = props.log?.retention;
104819
- if (retention && retention.value > 0n) {
104820
- const logGroup = new aws.cloudwatch.LogGroup(group, "log", {
104821
- name: `/aws/lambda/${name}`,
104822
- retentionInDays: toDays6(retention)
104823
- });
104824
- addPermission({
104825
- actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
104826
- resources: [logGroup.arn.pipe((arn) => `${arn}:*`)]
104827
- });
104828
- if (ctx.shared.has("on-error-log", "subscriber-arn")) {
104829
- new aws.cloudwatch.LogSubscriptionFilter(group, "on-error-log", {
104830
- name: "error-log-subscription",
104831
- destinationArn: ctx.shared.get("on-error-log", "subscriber-arn"),
104832
- logGroupName: logGroup.name,
104833
- filterPattern
104834
- }, {
104835
- dependsOn: [ctx.shared.get("on-error-log", "permission")]
104836
- });
104837
- }
104838
- }
104839
- return {
104840
- name,
104841
- group,
104842
- lambda,
104843
- policy,
104844
- code,
104845
- setEnvironment(name2, value) {
104846
- variables[name2] = value;
104847
- },
104848
- addPermission(...permissions) {
104849
- addPermission(...permissions);
104850
- }
104851
- };
104852
- };
104853
-
104854
- // src/feature/on-failure/index.ts
104855
105166
  var onFailureFeature = defineFeature({
104856
105167
  name: "on-failure",
104857
105168
  onBefore(ctx) {
@@ -105078,18 +105389,18 @@ var onFailureFeature = defineFeature({
105078
105389
  import { createHmac as createHmac2 } from "crypto";
105079
105390
  import { fileURLToPath as fileURLToPath7 } from "url";
105080
105391
  import { dirname as dirname10, join as join16 } from "path";
105081
- import { formatRouteEnvName as formatRouteEnvName2 } from "awsless";
105392
+ import { formatRouteEnvName as formatRouteEnvName3 } from "awsless";
105082
105393
 
105083
105394
  // src/feature/pubsub/util.ts
105084
105395
  import { toDays as toDays7 } from "@awsless/duration";
105085
105396
  import { stringify } from "@awsless/json";
105086
- import { createHash as createHash11 } from "crypto";
105397
+ import { createHash as createHash12 } from "crypto";
105087
105398
  import { readFile as readFile10 } from "fs/promises";
105088
105399
  import { fileURLToPath as fileURLToPath6 } from "url";
105089
105400
  import { dirname as dirname9, join as join15 } from "path";
105090
105401
 
105091
105402
  // src/feature/instance/build/executable.ts
105092
- import { createHash as createHash10 } from "crypto";
105403
+ import { createHash as createHash11 } from "crypto";
105093
105404
  import { readFile as readFile9 } from "fs/promises";
105094
105405
  import { join as join14 } from "path";
105095
105406
  var buildExecutable = async (input, outputPath, architecture) => {
@@ -105132,7 +105443,7 @@ ${result.logs?.map((log) => log.message).join(`
105132
105443
  }
105133
105444
  const file2 = await readFile9(filePath);
105134
105445
  return {
105135
- hash: createHash10("sha1").update(file2).update("x86_64").digest("hex"),
105446
+ hash: createHash11("sha1").update(file2).update("x86_64").digest("hex"),
105136
105447
  file: file2
105137
105448
  };
105138
105449
  };
@@ -105156,7 +105467,7 @@ var createPubSubService = (parentGroup, ctx, id, props, inputs) => {
105156
105467
  const image = "public.ecr.aws/aws-cli/aws-cli:arm64";
105157
105468
  const bundleFile = join15(__dirname2, "handlers/pubsub-server.js");
105158
105469
  ctx.registerBuild("pubsub", name, async (build2) => {
105159
- const hash2 = createHash11("sha1").update(await readFile10(bundleFile)).digest("hex");
105470
+ const hash2 = createHash12("sha1").update(await readFile10(bundleFile)).digest("hex");
105160
105471
  const fingerprint = `${hash2}-${ARCHITECTURE}`;
105161
105472
  return build2(fingerprint, async (write) => {
105162
105473
  const temp = await createTempFolder(`pubsub--${name}`);
@@ -105431,7 +105742,7 @@ var createPubSubService = (parentGroup, ctx, id, props, inputs) => {
105431
105742
  variables.APP_ID = ctx.appId;
105432
105743
  variables.AWS_ACCOUNT_ID = ctx.accountId;
105433
105744
  variables.CODE_HASH = code.sourceHash;
105434
- variables.PUBSUB_CONFIG_HASH = createHash11("sha1").update(stringify(props)).digest("hex");
105745
+ variables.PUBSUB_CONFIG_HASH = createHash12("sha1").update(stringify(props)).digest("hex");
105435
105746
  for (const [key, value] of Object.entries(inputs.environment)) {
105436
105747
  variables[key] = value;
105437
105748
  for (const dep of findInputDeps([value])) {
@@ -105688,9 +105999,9 @@ var pubsubFeature = defineFeature({
105688
105999
  file: join16(__dirname3, "/handlers/pubsub-publisher.js"),
105689
106000
  exportName: "default"
105690
106001
  });
105691
- bundle.addEnv(formatRouteEnvName2(publisherRouteKey, "REDIS_HOST"), redisHost);
105692
- bundle.addEnv(formatRouteEnvName2(publisherRouteKey, "REDIS_PORT"), redisPort.pipe((port) => port.toString()));
105693
- bundle.addEnv(formatRouteEnvName2(publisherRouteKey, "CHANNEL"), channel);
106002
+ bundle.addEnv(formatRouteEnvName3(publisherRouteKey, "REDIS_HOST"), redisHost);
106003
+ bundle.addEnv(formatRouteEnvName3(publisherRouteKey, "REDIS_PORT"), redisPort.pipe((port) => port.toString()));
106004
+ bundle.addEnv(formatRouteEnvName3(publisherRouteKey, "CHANNEL"), channel);
105694
106005
  const routerProps = ctx.appConfig.defaults.router?.[props.router];
105695
106006
  if (!routerProps?.domain) {
105696
106007
  throw new FileError("app.json", `The pubsub "${id}" requires the "${props.router}" router to have a domain configured.`);
@@ -105728,7 +106039,7 @@ var pubsubFeature = defineFeature({
105728
106039
  });
105729
106040
 
105730
106041
  // src/feature/queue/index.ts
105731
- var import_deepmerge2 = __toESM(require_cjs2(), 1);
106042
+ var import_deepmerge3 = __toESM(require_cjs2(), 1);
105732
106043
  import { relative as relative4 } from "path";
105733
106044
  import { minutes as minutes7, seconds as seconds5, toSeconds as toSeconds6 } from "@awsless/duration";
105734
106045
  var typeGenCode5 = `
@@ -105798,7 +106109,7 @@ var queueFeature = defineFeature({
105798
106109
  onStack(ctx) {
105799
106110
  const bundleTimeout = toSeconds6(ctx.appConfig.defaults.function.timeout);
105800
106111
  for (const [id, local] of Object.entries(ctx.stackConfig.queues || {})) {
105801
- const props = import_deepmerge2.default(ctx.appConfig.defaults.queue, typeof local === "object" ? local : {});
106112
+ const props = import_deepmerge3.default(ctx.appConfig.defaults.queue, typeof local === "object" ? local : {});
105802
106113
  const group = new Group(ctx.stack, "queue", id);
105803
106114
  const baseName = formatLocalResourceName({
105804
106115
  appName: ctx.app.name,
@@ -105945,7 +106256,7 @@ var restFeature = defineFeature({
105945
106256
  });
105946
106257
 
105947
106258
  // src/feature/rpc/index.ts
105948
- import { formatRouteEnvName as formatRouteEnvName3 } from "awsless";
106259
+ import { formatRouteEnvName as formatRouteEnvName4 } from "awsless";
105949
106260
  import { dirname as dirname11, join as join17, relative as relative5 } from "path";
105950
106261
  import { fileURLToPath as fileURLToPath8 } from "url";
105951
106262
  import { toSeconds as toSeconds7 } from "@awsless/duration";
@@ -106002,7 +106313,7 @@ var rpcFeature = defineFeature({
106002
106313
  file: join17(dirname11(fileURLToPath8(import.meta.url)), "/handlers/rpc.js"),
106003
106314
  exportName: "default"
106004
106315
  });
106005
- bundle.addEnv(formatRouteEnvName3(serverRouteKey, "TIMEOUT"), toSeconds7(ctx.appConfig.defaults.function.timeout).toString());
106316
+ bundle.addEnv(formatRouteEnvName4(serverRouteKey, "TIMEOUT"), toSeconds7(ctx.appConfig.defaults.function.timeout).toString());
106006
106317
  const lockTable = new aws.dynamodb.Table(group, "lock", {
106007
106318
  name: formatGlobalResourceName({
106008
106319
  appName: ctx.app.name,
@@ -106022,7 +106333,7 @@ var rpcFeature = defineFeature({
106022
106333
  }
106023
106334
  ]
106024
106335
  });
106025
- bundle.addEnv(formatRouteEnvName3(serverRouteKey, "LOCK_TABLE"), lockTable.name);
106336
+ bundle.addEnv(formatRouteEnvName4(serverRouteKey, "LOCK_TABLE"), lockTable.name);
106026
106337
  bundle.addPermission({
106027
106338
  effect: "allow",
106028
106339
  actions: ["dynamodb:UpdateItem", "dynamodb:DeleteItem"],
@@ -106031,7 +106342,7 @@ var rpcFeature = defineFeature({
106031
106342
  if (props.auth) {
106032
106343
  const authRouteKey = formatRouteKey("base", "rpc", `${id}-auth`);
106033
106344
  registerBundleFunction(ctx, authRouteKey, props.auth);
106034
- bundle.addEnv(formatRouteEnvName3(serverRouteKey, "AUTH"), authRouteKey);
106345
+ bundle.addEnv(formatRouteEnvName4(serverRouteKey, "AUTH"), authRouteKey);
106035
106346
  }
106036
106347
  const addRoutes = ctx.shared.entry("router", "addRoutes", props.router);
106037
106348
  addRoutes({
@@ -106056,7 +106367,7 @@ var rpcFeature = defineFeature({
106056
106367
  const entryId = kebabCase(`${id}-${shortId(name)}`);
106057
106368
  const routeKey = formatRouteKey(ctx.stack.name, "rpc", entryId);
106058
106369
  registerBundleFunction(ctx, routeKey, props.function);
106059
- bundle.addEnv(formatRouteEnvName3(serverRouteKey, `QUERY:${name}`), JSON.stringify({ function: routeKey, lock: props.lock }));
106370
+ bundle.addEnv(formatRouteEnvName4(serverRouteKey, `QUERY:${name}`), JSON.stringify({ function: routeKey, lock: props.lock }));
106060
106371
  }
106061
106372
  }
106062
106373
  }
@@ -106148,8 +106459,8 @@ var searchFeature = defineFeature({
106148
106459
  });
106149
106460
 
106150
106461
  // src/feature/site/index.ts
106151
- import { createHash as createHash12 } from "crypto";
106152
- import { dirname as dirname12, join as join20 } from "path";
106462
+ import { createHash as createHash13 } from "crypto";
106463
+ import { dirname as dirname13, join as join20 } from "path";
106153
106464
 
106154
106465
  // src/util/cache.ts
106155
106466
  import { lstat as lstat3, readdir as readdir4 } from "fs/promises";
@@ -106189,36 +106500,41 @@ var listAllFiles = async (list2) => {
106189
106500
  };
106190
106501
 
106191
106502
  // src/feature/site/static-routes.ts
106192
- import { basename as basename3, join as join19 } from "path";
106503
+ import { basename as basename3, dirname as dirname12, join as join19 } from "path";
106504
+ var isPageFile = (file2) => {
106505
+ return file2.endsWith(".html") || !basename3(file2).includes(".");
106506
+ };
106507
+ var pageUrl = (file2) => {
106508
+ if (!file2.endsWith(".html")) {
106509
+ return file2;
106510
+ }
106511
+ const url = file2.slice(0, -".html".length);
106512
+ if (basename3(url) === "index") {
106513
+ return dirname12(url);
106514
+ }
106515
+ return url;
106516
+ };
106193
106517
  var planStaticRoutes = (files, sitePath) => {
106194
106518
  const plan = { files: {}, dirs: [] };
106195
- const assetDirs = new Set;
106196
- for (const file2 of files) {
106197
- if (file2.endsWith(".html")) {
106198
- const strippedHtmlFile = file2.endsWith("index.html") ? file2.slice(0, -11) : file2.slice(0, -5);
106199
- const urlFriendlyFile = strippedHtmlFile.endsWith("/") ? strippedHtmlFile.slice(0, -1) : strippedHtmlFile;
106200
- plan.files[join19(sitePath, urlFriendlyFile)] = file2;
106201
- continue;
106202
- }
106203
- if (!basename3(file2).includes(".")) {
106204
- plan.files[join19(sitePath, file2)] = file2;
106205
- continue;
106206
- }
106207
- if (sitePath !== "/") {
106208
- continue;
106209
- }
106210
- const firstSegment = file2.split("/")[0];
106211
- if (file2.includes("/") && !firstSegment.includes(".")) {
106212
- assetDirs.add(firstSegment);
106213
- continue;
106214
- }
106215
- plan.files[join19(sitePath, file2)] = file2;
106519
+ const pages = files.filter((file2) => isPageFile(file2));
106520
+ const assets = files.filter((file2) => !isPageFile(file2));
106521
+ for (const page of pages) {
106522
+ plan.files[join19(sitePath, pageUrl(page))] = page;
106216
106523
  }
106217
- if (sitePath === "/") {
106218
- plan.dirs = [...assetDirs].map((dir) => join19(sitePath, dir, "*."));
106219
- } else {
106524
+ if (sitePath !== "/") {
106220
106525
  plan.catchAll = join19(sitePath, "*.");
106526
+ return plan;
106527
+ }
106528
+ const folders = new Set;
106529
+ for (const asset of assets) {
106530
+ const folder = asset.split("/")[0];
106531
+ if (asset.includes("/") && !folder.includes(".")) {
106532
+ folders.add(folder);
106533
+ continue;
106534
+ }
106535
+ plan.files[join19(sitePath, asset)] = asset;
106221
106536
  }
106537
+ plan.dirs = [...folders].map((folder) => join19(sitePath, folder, "*."));
106222
106538
  return plan;
106223
106539
  };
106224
106540
 
@@ -106243,7 +106559,7 @@ var siteFeature = defineFeature({
106243
106559
  return build2(fingerprint, async (write) => {
106244
106560
  const credentialProvider = await getCredentials(ctx.appConfig.profile);
106245
106561
  const credentials2 = await credentialProvider();
106246
- const cwd = join20(directories.root, dirname12(ctx.stackConfig.file));
106562
+ const cwd = join20(directories.root, dirname13(ctx.stackConfig.file));
106247
106563
  const env2 = {
106248
106564
  ...process.env,
106249
106565
  APP: ctx.appConfig.name,
@@ -106309,7 +106625,7 @@ ${(errors3.trim() || output.trim()).slice(-2000)}`);
106309
106625
  }).sort();
106310
106626
  const hashes = files.map((file2) => $hash(join20(staticDir, file2)));
106311
106627
  const version = $combine(...hashes).pipe((hashes2) => {
106312
- const hash2 = createHash12("sha1");
106628
+ const hash2 = createHash13("sha1");
106313
106629
  for (const [index, file2] of files.entries()) {
106314
106630
  hash2.update(file2);
106315
106631
  hash2.update(hashes2[index]);
@@ -107127,8 +107443,8 @@ var layerFeature = defineFeature({
107127
107443
 
107128
107444
  // src/feature/image/index.ts
107129
107445
  import { toDays as toDays9 } from "@awsless/duration";
107130
- import { formatRouteEnvName as formatRouteEnvName4 } from "awsless";
107131
- import { dirname as dirname13, join as join22 } from "path";
107446
+ import { formatRouteEnvName as formatRouteEnvName5 } from "awsless";
107447
+ import { dirname as dirname14, join as join22 } from "path";
107132
107448
  import { fileURLToPath as fileURLToPath9 } from "url";
107133
107449
  var imageFeature = defineFeature({
107134
107450
  name: "image",
@@ -107143,7 +107459,7 @@ var imageFeature = defineFeature({
107143
107459
  throw new FileError("app.json", "The image feature requires an arm64 function bundle.");
107144
107460
  }
107145
107461
  const group = new Group(ctx.base, "image", "layer");
107146
- const path2 = join22(dirname13(fileURLToPath9(import.meta.url)), "/layers/sharp-arm.zip");
107462
+ const path2 = join22(dirname14(fileURLToPath9(import.meta.url)), "/layers/sharp-arm.zip");
107147
107463
  const layerId = formatGlobalResourceName({
107148
107464
  appName: ctx.appConfig.name,
107149
107465
  resourceType: "layer",
@@ -107208,7 +107524,7 @@ var imageFeature = defineFeature({
107208
107524
  const serverRouteKey = formatRouteKey(ctx.stack.name, "image", id);
107209
107525
  bundle.addHandler({
107210
107526
  routeKey: serverRouteKey,
107211
- file: join22(dirname13(fileURLToPath9(import.meta.url)), "/handlers/image.js"),
107527
+ file: join22(dirname14(fileURLToPath9(import.meta.url)), "/handlers/image.js"),
107212
107528
  exportName: "default",
107213
107529
  external: ["sharp"]
107214
107530
  });
@@ -107224,17 +107540,17 @@ var imageFeature = defineFeature({
107224
107540
  }
107225
107541
  }
107226
107542
  });
107227
- bundle.addEnv(formatRouteEnvName4(serverRouteKey, "IMAGE_CONFIG"), JSON.stringify({
107543
+ bundle.addEnv(formatRouteEnvName5(serverRouteKey, "IMAGE_CONFIG"), JSON.stringify({
107228
107544
  presets: props.presets,
107229
107545
  extensions: props.extensions
107230
107546
  }));
107231
- bundle.addEnv(formatRouteEnvName4(serverRouteKey, "IMAGE_BUCKET"), bucket.name);
107232
- bundle.addEnv(formatRouteEnvName4(serverRouteKey, "IMAGE_FOLDER"), folder);
107547
+ bundle.addEnv(formatRouteEnvName5(serverRouteKey, "IMAGE_BUCKET"), bucket.name);
107548
+ bundle.addEnv(formatRouteEnvName5(serverRouteKey, "IMAGE_FOLDER"), folder);
107233
107549
  if (originRouteKey) {
107234
- bundle.addEnv(formatRouteEnvName4(serverRouteKey, "IMAGE_ORIGIN"), originRouteKey);
107550
+ bundle.addEnv(formatRouteEnvName5(serverRouteKey, "IMAGE_ORIGIN"), originRouteKey);
107235
107551
  }
107236
107552
  if (props.origin.static) {
107237
- bundle.addEnv(formatRouteEnvName4(serverRouteKey, "IMAGE_ORIGIN_S3"), "true");
107553
+ bundle.addEnv(formatRouteEnvName5(serverRouteKey, "IMAGE_ORIGIN_S3"), "true");
107238
107554
  }
107239
107555
  ctx.onReady(() => {
107240
107556
  if (props.origin.static) {
@@ -107262,8 +107578,8 @@ var imageFeature = defineFeature({
107262
107578
 
107263
107579
  // src/feature/icon/index.ts
107264
107580
  import { toDays as toDays10 } from "@awsless/duration";
107265
- import { formatRouteEnvName as formatRouteEnvName5 } from "awsless";
107266
- import { dirname as dirname14, join as join23 } from "path";
107581
+ import { formatRouteEnvName as formatRouteEnvName6 } from "awsless";
107582
+ import { dirname as dirname15, join as join23 } from "path";
107267
107583
  import { fileURLToPath as fileURLToPath10 } from "url";
107268
107584
  var iconFeature = defineFeature({
107269
107585
  name: "icon",
@@ -107295,7 +107611,7 @@ var iconFeature = defineFeature({
107295
107611
  const serverRouteKey = formatRouteKey(ctx.stack.name, "icon", id);
107296
107612
  bundle.addHandler({
107297
107613
  routeKey: serverRouteKey,
107298
- file: join23(dirname14(fileURLToPath10(import.meta.url)), "/handlers/icon.js"),
107614
+ file: join23(dirname15(fileURLToPath10(import.meta.url)), "/handlers/icon.js"),
107299
107615
  exportName: "default"
107300
107616
  });
107301
107617
  addRoutes({
@@ -107310,17 +107626,17 @@ var iconFeature = defineFeature({
107310
107626
  }
107311
107627
  }
107312
107628
  });
107313
- bundle.addEnv(formatRouteEnvName5(serverRouteKey, "ICON_CONFIG"), JSON.stringify({
107629
+ bundle.addEnv(formatRouteEnvName6(serverRouteKey, "ICON_CONFIG"), JSON.stringify({
107314
107630
  preserveIds: props.preserveIds,
107315
107631
  symbols: props.symbols
107316
107632
  }));
107317
- bundle.addEnv(formatRouteEnvName5(serverRouteKey, "ICON_BUCKET"), bucket.name);
107318
- bundle.addEnv(formatRouteEnvName5(serverRouteKey, "ICON_FOLDER"), folder);
107633
+ bundle.addEnv(formatRouteEnvName6(serverRouteKey, "ICON_BUCKET"), bucket.name);
107634
+ bundle.addEnv(formatRouteEnvName6(serverRouteKey, "ICON_FOLDER"), folder);
107319
107635
  if (originRouteKey) {
107320
- bundle.addEnv(formatRouteEnvName5(serverRouteKey, "ICON_ORIGIN"), originRouteKey);
107636
+ bundle.addEnv(formatRouteEnvName6(serverRouteKey, "ICON_ORIGIN"), originRouteKey);
107321
107637
  }
107322
107638
  if (props.origin.static) {
107323
- bundle.addEnv(formatRouteEnvName5(serverRouteKey, "ICON_ORIGIN_S3"), "true");
107639
+ bundle.addEnv(formatRouteEnvName6(serverRouteKey, "ICON_ORIGIN_S3"), "true");
107324
107640
  }
107325
107641
  ctx.onReady(() => {
107326
107642
  if (props.origin.static) {
@@ -107350,18 +107666,18 @@ var iconFeature = defineFeature({
107350
107666
  });
107351
107667
 
107352
107668
  // src/feature/job/index.ts
107353
- var import_deepmerge4 = __toESM(require_cjs2(), 1);
107669
+ var import_deepmerge5 = __toESM(require_cjs2(), 1);
107354
107670
  import { relative as relative7 } from "path";
107355
107671
 
107356
107672
  // src/feature/job/util.ts
107357
- import { createHash as createHash14 } from "crypto";
107673
+ import { createHash as createHash15 } from "crypto";
107358
107674
  import { toDays as toDays11, toSeconds as toSeconds9 } from "@awsless/duration";
107359
107675
  import { stringify as stringify2 } from "@awsless/json";
107360
- import { generateFileHash as generateFileHash2 } from "@awsless/ts-file-cache";
107361
- var import_deepmerge3 = __toESM(require_cjs2(), 1);
107676
+ import { generateFileHash as generateFileHash3 } from "@awsless/ts-file-cache";
107677
+ var import_deepmerge4 = __toESM(require_cjs2(), 1);
107362
107678
 
107363
107679
  // src/feature/job/build/executable.ts
107364
- import { createHash as createHash13 } from "crypto";
107680
+ import { createHash as createHash14 } from "crypto";
107365
107681
  import { readFile as readFile11, writeFile as writeFile7 } from "fs/promises";
107366
107682
  import { join as join24, resolve as resolve3 } from "path";
107367
107683
  var buildJobExecutable = async (input, outputPath, architecture) => {
@@ -107419,7 +107735,7 @@ ${result.logs?.map((log) => log.message).join(`
107419
107735
  }
107420
107736
  const file2 = await readFile11(filePath);
107421
107737
  return {
107422
- hash: createHash13("sha1").update(file2).update(target2).digest("hex"),
107738
+ hash: createHash14("sha1").update(file2).update(target2).digest("hex"),
107423
107739
  file: file2
107424
107740
  };
107425
107741
  };
@@ -107434,10 +107750,10 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
107434
107750
  resourceName: id
107435
107751
  });
107436
107752
  const shortName = shortId(`${ctx.app.name}:${ctx.stack.name}:${ns}:${id}:${ctx.appId}`);
107437
- const props = import_deepmerge3.default(ctx.appConfig.defaults.job, local);
107753
+ const props = import_deepmerge4.default(ctx.appConfig.defaults.job, local);
107438
107754
  const image = props.image || (props.architecture === "arm64" ? "public.ecr.aws/aws-cli/aws-cli:arm64" : "public.ecr.aws/aws-cli/aws-cli:amd64");
107439
107755
  ctx.registerBuild("job", name, async (build2, { workspace }) => {
107440
- const fingerprint = [await generateFileHash2(workspace, local.code.file), props.architecture].join(":");
107756
+ const fingerprint = [await generateFileHash3(workspace, local.code.file), props.architecture].join(":");
107441
107757
  return build2(fingerprint, async (write) => {
107442
107758
  const temp = await createTempFolder(`job--${name}`);
107443
107759
  const executable = await buildJobExecutable(local.code.file, temp.path, props.architecture);
@@ -107682,7 +107998,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
107682
107998
  variables.AWS_ACCOUNT_ID = ctx.accountId;
107683
107999
  variables.STACK = ctx.stackConfig.name;
107684
108000
  variables.CODE_HASH = code.sourceHash;
107685
- variables.JOB_CONFIG_HASH = createHash14("sha1").update(stringify2(props)).digest("hex");
108001
+ variables.JOB_CONFIG_HASH = createHash15("sha1").update(stringify2(props)).digest("hex");
107686
108002
  if (props.environment) {
107687
108003
  for (const [key, value] of Object.entries(props.environment)) {
107688
108004
  variables[key] = value;
@@ -107799,7 +108115,7 @@ var jobFeature = defineFeature({
107799
108115
  });
107800
108116
  ctx.shared.set("job", "security-group-id", securityGroup.id);
107801
108117
  const needsPersistentStorage = ctx.stackConfigs.some((stack) => Object.values(stack.jobs ?? {}).some((job) => {
107802
- const merged = import_deepmerge4.default(ctx.appConfig.defaults.job, job);
108118
+ const merged = import_deepmerge5.default(ctx.appConfig.defaults.job, job);
107803
108119
  return merged.persistentStorage;
107804
108120
  }));
107805
108121
  if (needsPersistentStorage) {
@@ -107829,6 +108145,8 @@ var jobFeature = defineFeature({
107829
108145
  fileSystemId: fileSystem.id,
107830
108146
  subnetId,
107831
108147
  securityGroups: [securityGroup.id]
108148
+ }, {
108149
+ replaceOnChanges: ["subnetId"]
107832
108150
  });
107833
108151
  }
107834
108152
  ctx.shared.set("job", "persistent-storage-file-system-id", fileSystem.id);
@@ -107873,9 +108191,9 @@ import { days as days9, seconds as seconds6, toSeconds as toSeconds11 } from "@a
107873
108191
  // src/feature/instance/util.ts
107874
108192
  import { toDays as toDays12, toSeconds as toSeconds10 } from "@awsless/duration";
107875
108193
  import { stringify as stringify3 } from "@awsless/json";
107876
- import { generateFileHash as generateFileHash3 } from "@awsless/ts-file-cache";
107877
- var import_deepmerge5 = __toESM(require_cjs2(), 1);
107878
- import { createHash as createHash15 } from "crypto";
108194
+ import { generateFileHash as generateFileHash4 } from "@awsless/ts-file-cache";
108195
+ var import_deepmerge6 = __toESM(require_cjs2(), 1);
108196
+ import { createHash as createHash16 } from "crypto";
107879
108197
  import { join as join25 } from "path";
107880
108198
  var createFargateTask = (parentGroup, ctx, ns, id, local) => {
107881
108199
  const group = new Group(parentGroup, "instance", ns);
@@ -107886,10 +108204,10 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
107886
108204
  resourceName: id
107887
108205
  });
107888
108206
  const shortName = shortId(`${ctx.app.name}:${ctx.stack.name}:${ns}:${id}:${ctx.appId}`);
107889
- const props = import_deepmerge5.default(ctx.appConfig.defaults.instance, local);
108207
+ const props = import_deepmerge6.default(ctx.appConfig.defaults.instance, local);
107890
108208
  const image = props.image || (props.architecture === "arm64" ? "public.ecr.aws/aws-cli/aws-cli:arm64" : "public.ecr.aws/aws-cli/aws-cli:amd64");
107891
108209
  ctx.registerBuild("instance", name, async (build2, { workspace }) => {
107892
- const fingerprint = await generateFileHash3(workspace, local.code.file);
108210
+ const fingerprint = await generateFileHash4(workspace, local.code.file);
107893
108211
  return build2(fingerprint, async (write) => {
107894
108212
  const temp = await createTempFolder(`instance--${name}`);
107895
108213
  const executable = await buildExecutable(local.code.file, temp.path, props.architecture);
@@ -108168,7 +108486,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
108168
108486
  variables.AWS_ACCOUNT_ID = ctx.accountId;
108169
108487
  variables.STACK = ctx.stackConfig.name;
108170
108488
  variables.CODE_HASH = code.sourceHash;
108171
- variables.INSTANCE_CONFIG_HASH = createHash15("sha1").update(stringify3(props)).digest("hex");
108489
+ variables.INSTANCE_CONFIG_HASH = createHash16("sha1").update(stringify3(props)).digest("hex");
108172
108490
  if (props.environment) {
108173
108491
  for (const [key, value] of Object.entries(props.environment)) {
108174
108492
  variables[key] = value;
@@ -110237,6 +110555,9 @@ var createApp = (props) => {
110237
110555
  builder
110238
110556
  });
110239
110557
  },
110558
+ registerConfig(name) {
110559
+ configs.add(name);
110560
+ },
110240
110561
  registerCommand(command) {
110241
110562
  commands.push(command);
110242
110563
  },
@@ -110278,6 +110599,7 @@ var createApp = (props) => {
110278
110599
  shared,
110279
110600
  onPermission(callback) {
110280
110601
  globalPermissionCallbacks.push(callback);
110602
+ appPermissionCallbacks.push(callback);
110281
110603
  },
110282
110604
  addGlobalPermission(permission) {
110283
110605
  globalPermissions.push(permission);
@@ -110289,7 +110611,7 @@ var createApp = (props) => {
110289
110611
  warnings.push(props2);
110290
110612
  },
110291
110613
  addFunction(lambda) {
110292
- for (const configName of stackConfig.configs ?? []) {
110614
+ for (const configName of props.appConfig.configs ?? []) {
110293
110615
  functionsByConfig[configName] ??= [];
110294
110616
  functionsByConfig[configName].push(lambda);
110295
110617
  }
@@ -110782,7 +111104,7 @@ import { parse as parse5, stringify as stringify4 } from "@awsless/json";
110782
111104
  import { generateFolderHash, loadWorkspace as loadWorkspace2 } from "@awsless/ts-file-cache";
110783
111105
 
110784
111106
  // src/test/start.ts
110785
- import { dirname as dirname15, join as join26 } from "path";
111107
+ import { dirname as dirname16, join as join26 } from "path";
110786
111108
  import { fileURLToPath as fileURLToPath11 } from "url";
110787
111109
  import { configDefaults } from "vitest/config";
110788
111110
  import { startVitest } from "vitest/node";
@@ -110790,7 +111112,7 @@ import { startVitest } from "vitest/node";
110790
111112
  class NullReporter {
110791
111113
  }
110792
111114
  var startTest = async (props) => {
110793
- const __dirname4 = dirname15(fileURLToPath11(import.meta.url));
111115
+ const __dirname4 = dirname16(fileURLToPath11(import.meta.url));
110794
111116
  const startTime = process.hrtime.bigint();
110795
111117
  process.noDeprecation = true;
110796
111118
  const vitest = await startVitest("test", props.filters, {
@@ -112311,7 +112633,7 @@ var watchConfig = async (options, resolve4, reject) => {
112311
112633
 
112312
112634
  // src/type-gen/generate.ts
112313
112635
  import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
112314
- import { dirname as dirname16, join as join28, relative as relative8 } from "path";
112636
+ import { dirname as dirname17, join as join28, relative as relative8 } from "path";
112315
112637
  var generateTypes = async (props) => {
112316
112638
  const files = [];
112317
112639
  await Promise.all(features.map((feature) => {
@@ -112324,7 +112646,7 @@ var generateTypes = async (props) => {
112324
112646
  if (include) {
112325
112647
  files.push(relative8(directories.root, path2));
112326
112648
  }
112327
- await mkdir7(dirname16(path2), { recursive: true });
112649
+ await mkdir7(dirname17(path2), { recursive: true });
112328
112650
  await writeFile9(path2, code);
112329
112651
  }
112330
112652
  }
@@ -115633,12 +115955,12 @@ import { join as join33 } from "path";
115633
115955
 
115634
115956
  // ../../node_modules/.pnpm/@aws-sdk+util-user-agent-node@3.973.14_aws-crt@1.30.0_supports-color@8.1.1_/node_modules/@aws-sdk/util-user-agent-node/dist-es/getNodeModulesParentDirs.js
115635
115957
  import { normalize as normalize3, sep as sep3 } from "path";
115636
- var getNodeModulesParentDirs = (dirname18) => {
115958
+ var getNodeModulesParentDirs = (dirname19) => {
115637
115959
  const cwd = process.cwd();
115638
- if (!dirname18) {
115960
+ if (!dirname19) {
115639
115961
  return [cwd];
115640
115962
  }
115641
- const normalizedPath = normalize3(dirname18);
115963
+ const normalizedPath = normalize3(dirname19);
115642
115964
  const parts = normalizedPath.split(sep3);
115643
115965
  const nodeModulesIndex = parts.indexOf("node_modules");
115644
115966
  const parentDir = nodeModulesIndex !== -1 ? parts.slice(0, nodeModulesIndex).join(sep3) : normalizedPath;
@@ -115692,8 +116014,8 @@ var getTypeScriptUserAgentPair = async () => {
115692
116014
  tscVersion = null;
115693
116015
  return;
115694
116016
  }
115695
- const dirname18 = typeof __dirname !== "undefined" ? __dirname : undefined;
115696
- const nodeModulesParentDirs = getNodeModulesParentDirs(dirname18);
116017
+ const dirname19 = typeof __dirname !== "undefined" ? __dirname : undefined;
116018
+ const nodeModulesParentDirs = getNodeModulesParentDirs(dirname19);
115697
116019
  let versionFromApp;
115698
116020
  for (const nodeModulesParentDir of nodeModulesParentDirs) {
115699
116021
  try {
@@ -115841,7 +116163,7 @@ var toUtf82 = (input) => {
115841
116163
 
115842
116164
  // ../../node_modules/.pnpm/@smithy+hash-node@4.2.12/node_modules/@smithy/hash-node/dist-es/index.js
115843
116165
  import { Buffer as Buffer3 } from "buffer";
115844
- import { createHash as createHash17, createHmac as createHmac3 } from "crypto";
116166
+ import { createHash as createHash18, createHmac as createHmac3 } from "crypto";
115845
116167
 
115846
116168
  class Hash {
115847
116169
  algorithmIdentifier;
@@ -115859,7 +116181,7 @@ class Hash {
115859
116181
  return Promise.resolve(this.hash.digest());
115860
116182
  }
115861
116183
  reset() {
115862
- this.hash = this.secret ? createHmac3(this.algorithmIdentifier, castSourceData(this.secret)) : createHash17(this.algorithmIdentifier);
116184
+ this.hash = this.secret ? createHmac3(this.algorithmIdentifier, castSourceData(this.secret)) : createHash18(this.algorithmIdentifier);
115863
116185
  }
115864
116186
  }
115865
116187
  function castSourceData(toCast, encoding) {