@awsless/awsless 0.0.322 → 0.0.325

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
@@ -322,7 +322,7 @@ var bootstrapAwsless = async (props) => {
322
322
  hasStateBucket(s3, props.accountId)
323
323
  ]);
324
324
  if (!table2 || !bucket) {
325
- log.warn(`Your Awsless hasn't been bootstrapped yet.`);
325
+ log.warn(`Awsless hasn't been bootstrapped yet.`);
326
326
  if (!process.env.SKIP_PROMPT) {
327
327
  const confirmed = await confirm({
328
328
  message: "Would you like to bootstrap now?"
@@ -338,7 +338,7 @@ var bootstrapAwsless = async (props) => {
338
338
  if (!bucket) {
339
339
  await createStateBucket(s3, props.accountId);
340
340
  }
341
- update("Done deploying the bootstrap stack");
341
+ update("Done deploying the bootstrap stack.");
342
342
  });
343
343
  } else {
344
344
  log.step("Awsless has already been bootstrapped.");
@@ -968,6 +968,7 @@ var AppSchema = z18.object({
968
968
  http: HttpDefaultSchema,
969
969
  rest: RestDefaultSchema,
970
970
  pubsub: PubSubDefaultSchema
971
+ // dataRetention: z.boolean().describe('Configure how your resources are handled on delete.').default(false),
971
972
  }).default({}).describe("Default properties")
972
973
  });
973
974
 
@@ -1310,6 +1311,7 @@ var SitesSchema = z25.record(
1310
1311
 
1311
1312
  // src/feature/store/schema.ts
1312
1313
  import { z as z26 } from "zod";
1314
+ var DeletionProtectionSchema = z26.boolean().describe("Specifies if you want to protect the store from being deleted by awsless.");
1313
1315
  var StoresSchema = z26.union([
1314
1316
  z26.array(ResourceIdSchema).transform((list4) => {
1315
1317
  const stores = {};
@@ -1322,6 +1324,7 @@ var StoresSchema = z26.union([
1322
1324
  ResourceIdSchema,
1323
1325
  z26.object({
1324
1326
  // cors: CorsSchema,
1327
+ deletionProtection: DeletionProtectionSchema.optional(),
1325
1328
  versioning: z26.boolean().default(false).describe("Enable versioning of your store."),
1326
1329
  events: z26.object({
1327
1330
  // create
@@ -1381,6 +1384,7 @@ var StreamsSchema = z27.record(
1381
1384
  // src/feature/table/schema.ts
1382
1385
  import { z as z28 } from "zod";
1383
1386
  var KeySchema = z28.string().min(1).max(255);
1387
+ var DeletionProtectionSchema2 = z28.boolean().describe("Specifies if you want to protect the table from being deleted by awsless.");
1384
1388
  var TablesSchema = z28.record(
1385
1389
  ResourceIdSchema,
1386
1390
  z28.object({
@@ -1398,6 +1402,7 @@ var TablesSchema = z28.record(
1398
1402
  timeToLiveAttribute: KeySchema.optional().describe(
1399
1403
  "The name of the TTL attribute used to store the expiration time for items in the table. To update this property, you must first disable TTL and then enable TTL with the new attribute name."
1400
1404
  ),
1405
+ deletionProtection: DeletionProtectionSchema2.optional(),
1401
1406
  stream: z28.object({
1402
1407
  type: z28.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]).describe(
1403
1408
  "When an item in the table is modified, stream.type determines what information is written to the stream for this table. Valid values are:\n- keys-only - Only the key attributes of the modified item are written to the stream.\n- new-image - The entire item, as it appears after it was modified, is written to the stream.\n- old-image - The entire item, as it appeared before it was modified, is written to the stream.\n- new-and-old-images - Both the new and the old item images of the item are written to the stream."
@@ -1577,17 +1582,16 @@ var loadStackConfigs = async (options) => {
1577
1582
 
1578
1583
  // src/cli/ui/app.ts
1579
1584
  import { note } from "@clack/prompts";
1580
- var logApp = (app) => {
1581
- note(
1582
- wrap(
1583
- list({
1584
- App: app.name,
1585
- Region: app.region,
1586
- Profile: app.profile
1587
- })
1588
- ),
1589
- "App Config"
1590
- );
1585
+ var logApp = (app, opt) => {
1586
+ const data = {
1587
+ App: app.name,
1588
+ Region: app.region,
1589
+ Profile: app.profile
1590
+ };
1591
+ if (opt.stage) {
1592
+ data.Stage = color.warning(opt.stage);
1593
+ }
1594
+ note(wrap(list(data)), "App Config");
1591
1595
  };
1592
1596
 
1593
1597
  // src/cli/ui/error/error.ts
@@ -1810,7 +1814,7 @@ var layout = async (command, cb) => {
1810
1814
  try {
1811
1815
  const options = program.optsWithGlobals();
1812
1816
  const appConfig = await loadAppConfig(options);
1813
- logApp(appConfig);
1817
+ logApp(appConfig, options);
1814
1818
  const stackConfigs = await loadStackConfigs(options);
1815
1819
  const result = await cb({
1816
1820
  options,
@@ -1959,22 +1963,30 @@ var TypeObject = class {
1959
1963
 
1960
1964
  // src/util/name.ts
1961
1965
  import { paramCase as paramCase3 } from "change-case";
1962
- var formatGlobalResourceName = (appName, ns, id, seperator = "--") => {
1966
+ import { createHmac } from "crypto";
1967
+ var formatGlobalResourceName = (opt) => {
1963
1968
  return [
1964
1969
  //
1965
- appName,
1966
- ns,
1967
- id
1968
- ].map((v) => paramCase3(v)).join(seperator);
1970
+ opt.prefix,
1971
+ opt.appName,
1972
+ opt.resourceType,
1973
+ opt.resourceName,
1974
+ opt.postfix
1975
+ ].filter((v) => typeof v === "string").map((v) => paramCase3(v)).join(opt.seperator ?? "--");
1969
1976
  };
1970
- var formatLocalResourceName = (appName, stackName, ns, id, seperator = "--") => {
1977
+ var formatLocalResourceName = (opt) => {
1971
1978
  return [
1972
1979
  //
1973
- appName,
1974
- stackName,
1975
- ns,
1976
- id
1977
- ].map((v) => paramCase3(v)).join(seperator);
1980
+ opt.prefix,
1981
+ opt.appName,
1982
+ opt.stackName,
1983
+ opt.resourceType,
1984
+ opt.resourceName,
1985
+ opt.postfix
1986
+ ].filter((v) => typeof v === "string").map((v) => paramCase3(v)).join(opt.seperator ?? "--");
1987
+ };
1988
+ var generateGlobalAppId = (opt) => {
1989
+ return createHmac("sha1", "awsless").update(opt.accountId).update(opt.region).update(opt.appName).digest("hex").substring(0, 8);
1978
1990
  };
1979
1991
 
1980
1992
  // src/feature/function/util.ts
@@ -2174,10 +2186,19 @@ var zipFiles = (files) => {
2174
2186
  import { hashElement } from "folder-hash";
2175
2187
  var createLambdaFunction = (group, ctx, ns, id, local2) => {
2176
2188
  let name;
2177
- if ("stackConfig" in ctx) {
2178
- name = formatLocalResourceName(ctx.appConfig.name, ctx.stackConfig.name, ns, id);
2189
+ if ("stack" in ctx) {
2190
+ name = formatLocalResourceName({
2191
+ appName: ctx.app.name,
2192
+ stackName: ctx.stack.name,
2193
+ resourceType: ns,
2194
+ resourceName: id
2195
+ });
2179
2196
  } else {
2180
- name = formatGlobalResourceName(ctx.appConfig.name, ns, id);
2197
+ name = formatGlobalResourceName({
2198
+ appName: ctx.appConfig.name,
2199
+ resourceType: ns,
2200
+ resourceName: id
2201
+ });
2181
2202
  }
2182
2203
  const props = deepmerge(ctx.appConfig.defaults.function, local2);
2183
2204
  let code;
@@ -2191,7 +2212,12 @@ var createLambdaFunction = (group, ctx, ns, id, local2) => {
2191
2212
  }
2192
2213
  });
2193
2214
  return build3(version.hash + props.architecture, async (write) => {
2194
- const repoName = formatGlobalResourceName(ctx.appConfig.name, "function", "repository", "-");
2215
+ const repoName = formatGlobalResourceName({
2216
+ appName: ctx.app.name,
2217
+ resourceType: "function",
2218
+ resourceName: "repository",
2219
+ seperator: "-"
2220
+ });
2195
2221
  const platform = props.architecture === "arm64" ? "linux/arm64" : "linux/amd64";
2196
2222
  await exec(`docker buildx build --platform ${platform} -t ${name} .`, {
2197
2223
  cwd: basePath2
@@ -2278,6 +2304,7 @@ var createLambdaFunction = (group, ctx, ns, id, local2) => {
2278
2304
  });
2279
2305
  ctx.registerPolicy(policy);
2280
2306
  lambda.addEnvironment("APP", ctx.appConfig.name);
2307
+ lambda.addEnvironment("APP_ID", ctx.appId);
2281
2308
  if ("stackConfig" in ctx) {
2282
2309
  lambda.addEnvironment("STACK", ctx.stackConfig.name);
2283
2310
  }
@@ -2458,7 +2485,11 @@ var authFeature = defineFeature({
2458
2485
  from: props.messaging.fromName ? `${props.messaging.fromName} <${props.messaging.fromEmail}>` : props.messaging.fromEmail
2459
2486
  };
2460
2487
  }
2461
- const name = formatGlobalResourceName(ctx.appConfig.name, "auth", id);
2488
+ const name = formatGlobalResourceName({
2489
+ appName: ctx.app.name,
2490
+ resourceType: "auth",
2491
+ resourceName: id
2492
+ });
2462
2493
  const userPool = new aws3.cognito.UserPool(group, "user-pool", {
2463
2494
  name,
2464
2495
  // deletionProtection: true,
@@ -2518,7 +2549,13 @@ var cacheFeature = defineFeature({
2518
2549
  onStack(ctx) {
2519
2550
  for (const [id, props] of Object.entries(ctx.stackConfig.caches ?? {})) {
2520
2551
  const group = new Node3(ctx.stack, this.name, id);
2521
- const name = formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, this.name, id, "-");
2552
+ const name = formatLocalResourceName({
2553
+ appName: ctx.app.name,
2554
+ stackName: ctx.stack.name,
2555
+ resourceType: "cache",
2556
+ resourceName: id,
2557
+ seperator: "-"
2558
+ });
2522
2559
  const subnetGroup = new aws4.memorydb.SubnetGroup(group, "subnets", {
2523
2560
  name,
2524
2561
  subnetIds: [
@@ -2716,7 +2753,12 @@ var cronFeature = defineFeature({
2716
2753
  const group = new Node4(ctx.stack, "cron", id);
2717
2754
  const { lambda } = createAsyncLambdaFunction(group, ctx, "cron", id, props.consumer);
2718
2755
  const rule = new aws5.events.Rule(group, "rule", {
2719
- name: formatLocalResourceName(ctx.app.name, ctx.stack.name, this.name, id),
2756
+ name: formatLocalResourceName({
2757
+ appName: ctx.app.name,
2758
+ stackName: ctx.stack.name,
2759
+ resourceType: "cron",
2760
+ resourceName: id
2761
+ }),
2720
2762
  schedule: props.schedule,
2721
2763
  enabled: props.enabled,
2722
2764
  targets: [
@@ -2890,7 +2932,12 @@ var functionFeature = defineFeature({
2890
2932
  for (const [name, local2] of Object.entries(stack.functions || {})) {
2891
2933
  const props = deepmerge2(ctx.appConfig.defaults.function, local2);
2892
2934
  const varName = camelCase3(`${stack.name}-${name}`);
2893
- const funcName = formatLocalResourceName(ctx.appConfig.name, stack.name, "function", name);
2935
+ const funcName = formatLocalResourceName({
2936
+ appName: ctx.appConfig.name,
2937
+ stackName: stack.name,
2938
+ resourceType: "function",
2939
+ resourceName: name
2940
+ });
2894
2941
  const relFile = relative(directories.types, props.file);
2895
2942
  if (props.runtime === "container") {
2896
2943
  resource2.addType(name, `Invoke<'${funcName}', Func>`);
@@ -2916,13 +2963,23 @@ var functionFeature = defineFeature({
2916
2963
  onApp(ctx) {
2917
2964
  const group = new Node6(ctx.base, "function", "asset");
2918
2965
  const bucket = new aws7.s3.Bucket(group, "bucket", {
2919
- name: formatGlobalResourceName(ctx.appConfig.name, "function", "assets"),
2966
+ name: formatGlobalResourceName({
2967
+ appName: ctx.app.name,
2968
+ resourceType: "function",
2969
+ resourceName: "assets",
2970
+ postfix: ctx.appId
2971
+ }),
2920
2972
  versioning: true,
2921
2973
  forceDelete: true
2922
2974
  });
2923
2975
  ctx.shared.set("function-bucket-name", bucket.name);
2924
2976
  const repository = new aws7.ecr.Repository(group, "repository", {
2925
- name: formatGlobalResourceName(ctx.appConfig.name, "function", "repository", "-"),
2977
+ name: formatGlobalResourceName({
2978
+ appName: ctx.app.name,
2979
+ resourceType: "function",
2980
+ resourceName: "repository",
2981
+ seperator: "-"
2982
+ }),
2926
2983
  imageTagMutability: true
2927
2984
  });
2928
2985
  ctx.shared.set("function-repository-name", repository.name);
@@ -3126,7 +3183,11 @@ var graphqlFeature = defineFeature({
3126
3183
  const { lambda } = createLambdaFunction(group, ctx, "graphql-auth", id, props.auth.authorizer);
3127
3184
  authorizer = lambda;
3128
3185
  }
3129
- const name = formatGlobalResourceName(ctx.app.name, "graphql", id);
3186
+ const name = formatGlobalResourceName({
3187
+ appName: ctx.app.name,
3188
+ resourceType: "graphql",
3189
+ resourceName: id
3190
+ });
3130
3191
  const api = new aws8.appsync.GraphQLApi(group, "api", {
3131
3192
  name,
3132
3193
  type: "graphql",
@@ -3380,7 +3441,11 @@ var httpFeature = defineFeature({
3380
3441
  const group = new Node8(ctx.base, "http", "main");
3381
3442
  const securityGroup = new aws9.ec2.SecurityGroup(group, "http", {
3382
3443
  vpcId: ctx.shared.get(`vpc-id`),
3383
- name: formatGlobalResourceName(ctx.app.name, "http", "http"),
3444
+ name: formatGlobalResourceName({
3445
+ appName: ctx.app.name,
3446
+ resourceType: "http",
3447
+ resourceName: "http"
3448
+ }),
3384
3449
  description: `Global security group for HTTP api.`
3385
3450
  });
3386
3451
  const port = aws9.ec2.Port.tcp(443);
@@ -3389,7 +3454,11 @@ var httpFeature = defineFeature({
3389
3454
  for (const [id, props] of Object.entries(ctx.appConfig.defaults?.http ?? {})) {
3390
3455
  const group2 = new Node8(ctx.base, "http", id);
3391
3456
  const loadBalancer = new aws9.elb.LoadBalancer(group2, "balancer", {
3392
- name: formatGlobalResourceName(ctx.app.name, "http", id),
3457
+ name: formatGlobalResourceName({
3458
+ appName: ctx.app.name,
3459
+ resourceType: "http",
3460
+ resourceName: id
3461
+ }),
3393
3462
  type: "application",
3394
3463
  securityGroups: [securityGroup.id],
3395
3464
  subnets: [
@@ -3443,7 +3512,12 @@ var httpFeature = defineFeature({
3443
3512
  ...routeProps,
3444
3513
  description: routeKey
3445
3514
  });
3446
- const name = formatLocalResourceName(ctx.app.name, ctx.stack.name, "http", routeId);
3515
+ const name = formatLocalResourceName({
3516
+ appName: ctx.app.name,
3517
+ stackName: ctx.stack.name,
3518
+ resourceType: "http",
3519
+ resourceName: routeId
3520
+ });
3447
3521
  const permission = new aws9.lambda.Permission(routeGroup, id, {
3448
3522
  action: "lambda:InvokeFunction",
3449
3523
  principal: "elasticloadbalancing.amazonaws.com",
@@ -3481,13 +3555,18 @@ var instanceFeature = defineFeature({
3481
3555
  onApp(ctx) {
3482
3556
  const group = new Node9(ctx.base, "instance", "asset");
3483
3557
  const bucket = new aws10.s3.Bucket(group, "bucket", {
3484
- name: formatGlobalResourceName(ctx.appConfig.name, "instance", "assets"),
3558
+ name: formatGlobalResourceName({
3559
+ appName: ctx.app.name,
3560
+ resourceType: "instance",
3561
+ resourceName: "assets",
3562
+ postfix: ctx.appId
3563
+ }),
3485
3564
  forceDelete: true
3486
3565
  });
3487
3566
  ctx.shared.set("instance-bucket-name", bucket.name);
3488
3567
  if (ctx.appConfig.defaults.instance.connect) {
3489
3568
  new aws10.ec2.InstanceConnectEndpoint(group, "connect", {
3490
- name: ctx.appConfig.name,
3569
+ name: ctx.app.name,
3491
3570
  subnetId: ctx.shared.get(`vpc-public-subnet-id-1`),
3492
3571
  securityGroupIds: [ctx.shared.get("vpc-security-group-id")]
3493
3572
  });
@@ -3496,10 +3575,16 @@ var instanceFeature = defineFeature({
3496
3575
  onStack(ctx) {
3497
3576
  for (const [id, props] of Object.entries(ctx.stackConfig.instances ?? {})) {
3498
3577
  const group = new Node9(ctx.stack, "instance", id);
3499
- const name = formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, "instance", id);
3578
+ const name = formatLocalResourceName({
3579
+ appName: ctx.app.name,
3580
+ stackName: ctx.stack.name,
3581
+ resourceType: "instance",
3582
+ resourceName: id
3583
+ });
3500
3584
  const env = {
3501
- APP: ctx.appConfig.name,
3502
- STACK: ctx.stackConfig.name
3585
+ APP: ctx.app.name,
3586
+ APP_ID: ctx.appId,
3587
+ STACK: ctx.stack.name
3503
3588
  };
3504
3589
  ctx.onEnv((name2, value) => {
3505
3590
  env[name2] = value;
@@ -3622,7 +3707,11 @@ var onFailureFeature = defineFeature({
3622
3707
  throw new TypeError("Only 1 onFailure configuration is allowed in your app.");
3623
3708
  }
3624
3709
  const queue2 = new aws11.sqs.Queue(ctx.base, "on-failure", {
3625
- name: formatGlobalResourceName(ctx.appConfig.name, "on-failure", "failure")
3710
+ name: formatGlobalResourceName({
3711
+ appName: ctx.app.name,
3712
+ resourceType: "on-failure",
3713
+ resourceName: "failure"
3714
+ })
3626
3715
  });
3627
3716
  ctx.shared.set("on-failure-queue-arn", queue2.arn);
3628
3717
  },
@@ -3665,7 +3754,11 @@ var pubsubFeature = defineFeature({
3665
3754
  const { lambda } = createLambdaFunction(group, ctx, "pubsub-authorizer", id, functionProps);
3666
3755
  lambda.addEnvironment("PUBSUB_POLICY", JSON.stringify(props.policy));
3667
3756
  lambda.addEnvironment("AWS_ACCOUNT_ID", ctx.accountId);
3668
- const name = formatGlobalResourceName(ctx.app.name, "pubsub", id);
3757
+ const name = formatGlobalResourceName({
3758
+ appName: ctx.app.name,
3759
+ resourceType: "pubsub",
3760
+ resourceName: id
3761
+ });
3669
3762
  const authorizer = new aws12.iot.Authorizer(group, "authorizer", {
3670
3763
  name,
3671
3764
  functionArn: lambda.arn
@@ -3714,7 +3807,12 @@ var pubsubFeature = defineFeature({
3714
3807
  for (const [id, props] of Object.entries(ctx.stackConfig.pubsub ?? {})) {
3715
3808
  const group = new Node11(ctx.stack, "pubsub", id);
3716
3809
  const { lambda } = createAsyncLambdaFunction(group, ctx, `pubsub`, id, props.consumer);
3717
- const name = formatLocalResourceName(ctx.app.name, ctx.stack.name, "pubsub", id);
3810
+ const name = formatLocalResourceName({
3811
+ appName: ctx.app.name,
3812
+ stackName: ctx.stack.name,
3813
+ resourceType: "pubsub",
3814
+ resourceName: id
3815
+ });
3718
3816
  const topic = new aws12.iot.TopicRule(group, "rule", {
3719
3817
  name: name.replaceAll("-", "_"),
3720
3818
  sql: props.sql,
@@ -3766,7 +3864,12 @@ var queueFeature = defineFeature({
3766
3864
  const mockResponse = new TypeObject(2);
3767
3865
  for (const [name, fileOrProps] of Object.entries(stack.queues || {})) {
3768
3866
  const varName = camelCase5(`${stack.name}-${name}`);
3769
- const queueName = formatLocalResourceName(ctx.appConfig.name, stack.name, "queue", name);
3867
+ const queueName = formatLocalResourceName({
3868
+ appName: ctx.appConfig.name,
3869
+ stackName: stack.name,
3870
+ resourceType: "queue",
3871
+ resourceName: name
3872
+ });
3770
3873
  const file = typeof fileOrProps === "string" ? fileOrProps : typeof fileOrProps.consumer === "string" ? fileOrProps.consumer : fileOrProps.consumer.file;
3771
3874
  const relFile = relative3(directories.types, file);
3772
3875
  gen.addImport(varName, relFile);
@@ -3788,8 +3891,14 @@ var queueFeature = defineFeature({
3788
3891
  for (const [id, local2] of Object.entries(ctx.stackConfig.queues || {})) {
3789
3892
  const props = deepmerge3(ctx.appConfig.defaults.queue, local2);
3790
3893
  const group = new Node12(ctx.stack, "queue", id);
3894
+ const name = formatLocalResourceName({
3895
+ appName: ctx.app.name,
3896
+ stackName: ctx.stack.name,
3897
+ resourceType: "queue",
3898
+ resourceName: id
3899
+ });
3791
3900
  const queue2 = new aws13.sqs.Queue(group, "queue", {
3792
- name: formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, "queue", id),
3901
+ name,
3793
3902
  deadLetterArn: getGlobalOnFailure(ctx),
3794
3903
  ...props
3795
3904
  });
@@ -3822,8 +3931,13 @@ var restFeature = defineFeature({
3822
3931
  onApp(ctx) {
3823
3932
  for (const [id, props] of Object.entries(ctx.appConfig.defaults?.rest ?? {})) {
3824
3933
  const group = new Node13(ctx.base, "rest", id);
3934
+ const name = formatGlobalResourceName({
3935
+ appName: ctx.app.name,
3936
+ resourceType: "rest",
3937
+ resourceName: id
3938
+ });
3825
3939
  const api = new aws14.apiGatewayV2.Api(group, "api", {
3826
- name: formatGlobalResourceName(ctx.app.name, "rest", id),
3940
+ name,
3827
3941
  protocolType: "HTTP"
3828
3942
  });
3829
3943
  const stage = new aws14.apiGatewayV2.Stage(group, "stage", {
@@ -4003,7 +4117,12 @@ var siteFeature = defineFeature({
4003
4117
  onStack(ctx) {
4004
4118
  for (const [id, props] of Object.entries(ctx.stackConfig.sites ?? {})) {
4005
4119
  const group = new Node15(ctx.stack, "site", id);
4006
- const name = formatLocalResourceName(ctx.app.name, ctx.stack.name, "site", id);
4120
+ const name = formatLocalResourceName({
4121
+ appName: ctx.app.name,
4122
+ stackName: ctx.stack.name,
4123
+ resourceType: "site",
4124
+ resourceName: id
4125
+ });
4007
4126
  const origins = [];
4008
4127
  const originGroups = [];
4009
4128
  let bucket;
@@ -4038,7 +4157,13 @@ var siteFeature = defineFeature({
4038
4157
  }
4039
4158
  if (props.static) {
4040
4159
  bucket = new aws16.s3.Bucket(group, "bucket", {
4041
- name,
4160
+ name: formatLocalResourceName({
4161
+ appName: ctx.app.name,
4162
+ stackName: ctx.stack.name,
4163
+ resourceType: "site",
4164
+ resourceName: id,
4165
+ postfix: ctx.appId
4166
+ }),
4042
4167
  forceDelete: true,
4043
4168
  website: {
4044
4169
  indexDocument: "index.html",
@@ -4214,7 +4339,12 @@ var storeFeature = defineFeature({
4214
4339
  for (const stack of ctx.stackConfigs) {
4215
4340
  const list4 = new TypeObject(2);
4216
4341
  for (const id of Object.keys(stack.stores ?? {})) {
4217
- const storeName = formatLocalResourceName(ctx.appConfig.name, stack.name, "store", id);
4342
+ const storeName = formatLocalResourceName({
4343
+ appName: ctx.appConfig.name,
4344
+ stackName: stack.name,
4345
+ resourceType: "store",
4346
+ resourceName: id
4347
+ });
4218
4348
  list4.addType(id, `Store<'${storeName}'>`);
4219
4349
  }
4220
4350
  resources.addType(stack.name, list4);
@@ -4223,10 +4353,19 @@ var storeFeature = defineFeature({
4223
4353
  gen.addInterface("StoreResources", resources);
4224
4354
  await ctx.write("store.d.ts", gen, true);
4225
4355
  },
4356
+ onApp(ctx) {
4357
+ ctx.addEnv("STORE_POSTFIX", ctx.appId);
4358
+ },
4226
4359
  onStack(ctx) {
4227
4360
  for (const [id, props] of Object.entries(ctx.stackConfig.stores ?? {})) {
4228
4361
  const group = new Node16(ctx.stack, "store", id);
4229
- const bucketName = formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, "store", id);
4362
+ const name = formatLocalResourceName({
4363
+ appName: ctx.app.name,
4364
+ stackName: ctx.stack.name,
4365
+ resourceType: "store",
4366
+ resourceName: id,
4367
+ postfix: ctx.appId
4368
+ });
4230
4369
  const lambdaConfigs = [];
4231
4370
  const eventMap = {
4232
4371
  "created:*": "s3:ObjectCreated:*",
@@ -4249,7 +4388,7 @@ var storeFeature = defineFeature({
4249
4388
  action: "lambda:InvokeFunction",
4250
4389
  principal: "s3.amazonaws.com",
4251
4390
  functionArn: lambda.arn,
4252
- sourceArn: `arn:aws:s3:::${bucketName}`
4391
+ sourceArn: `arn:aws:s3:::${name}`
4253
4392
  });
4254
4393
  lambdaConfigs.push({
4255
4394
  event: eventMap[event],
@@ -4257,7 +4396,7 @@ var storeFeature = defineFeature({
4257
4396
  });
4258
4397
  }
4259
4398
  const bucket = new aws17.s3.Bucket(group, "store", {
4260
- name: bucketName,
4399
+ name,
4261
4400
  versioning: props.versioning,
4262
4401
  forceDelete: true,
4263
4402
  lambdaConfigs,
@@ -4272,6 +4411,9 @@ var storeFeature = defineFeature({
4272
4411
  // ---------------------------------------------
4273
4412
  ]
4274
4413
  });
4414
+ if (props.deletionProtection) {
4415
+ bucket.deletionPolicy = "retain";
4416
+ }
4275
4417
  ctx.onPolicy((policy) => {
4276
4418
  policy.addStatement(bucket.permissions);
4277
4419
  });
@@ -4287,7 +4429,12 @@ var streamFeature = defineFeature({
4287
4429
  onStack(ctx) {
4288
4430
  for (const [id, props] of Object.entries(ctx.stackConfig.streams ?? {})) {
4289
4431
  const group = new Node17(ctx.stack, "stream", id);
4290
- const name = formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, "stream", id);
4432
+ const name = formatLocalResourceName({
4433
+ appName: ctx.app.name,
4434
+ stackName: ctx.stack.name,
4435
+ resourceType: "stream",
4436
+ resourceName: id
4437
+ });
4291
4438
  const channel = new aws18.ivs.Channel(group, "channel", {
4292
4439
  name,
4293
4440
  ...props
@@ -4313,7 +4460,12 @@ var tableFeature = defineFeature({
4313
4460
  for (const stack of ctx.stackConfigs) {
4314
4461
  const list4 = new TypeObject(2);
4315
4462
  for (const name of Object.keys(stack.tables || {})) {
4316
- const tableName = formatLocalResourceName(ctx.appConfig.name, stack.name, "table", name);
4463
+ const tableName = formatLocalResourceName({
4464
+ appName: ctx.appConfig.name,
4465
+ stackName: stack.name,
4466
+ resourceType: "table",
4467
+ resourceName: name
4468
+ });
4317
4469
  list4.addType(name, `'${tableName}'`);
4318
4470
  }
4319
4471
  resources.addType(stack.name, list4);
@@ -4324,11 +4476,21 @@ var tableFeature = defineFeature({
4324
4476
  onStack(ctx) {
4325
4477
  for (const [id, props] of Object.entries(ctx.stackConfig.tables ?? {})) {
4326
4478
  const group = new Node18(ctx.stack, "table", id);
4479
+ const name = formatLocalResourceName({
4480
+ appName: ctx.app.name,
4481
+ stackName: ctx.stack.name,
4482
+ resourceType: "table",
4483
+ resourceName: id
4484
+ });
4327
4485
  const table2 = new aws19.dynamodb.Table(group, "table", {
4328
4486
  ...props,
4329
- name: formatLocalResourceName(ctx.appConfig.name, ctx.stackConfig.name, "table", id),
4330
- stream: props.stream?.type
4487
+ name,
4488
+ stream: props.stream?.type,
4489
+ deletionProtection: props.deletionProtection
4331
4490
  });
4491
+ if (props.deletionProtection) {
4492
+ table2.deletionPolicy = "retain";
4493
+ }
4332
4494
  if (props.stream) {
4333
4495
  const { lambda, policy } = createLambdaFunction(group, ctx, "table", id, props.stream.consumer);
4334
4496
  lambda.addEnvironment("LOG_VIEWABLE_ERROR", "1");
@@ -4398,7 +4560,12 @@ var taskFeature = defineFeature({
4398
4560
  const mockResponse = new TypeObject(2);
4399
4561
  for (const [name, props] of Object.entries(stack.tasks || {})) {
4400
4562
  const varName = camelCase6(`${stack.name}-${name}`);
4401
- const funcName = formatLocalResourceName(ctx.appConfig.name, stack.name, "task", name);
4563
+ const funcName = formatLocalResourceName({
4564
+ appName: ctx.appConfig.name,
4565
+ stackName: stack.name,
4566
+ resourceType: "task",
4567
+ resourceName: name
4568
+ });
4402
4569
  const relFile = relative4(directories.types, props.consumer.file);
4403
4570
  types2.addImport(varName, relFile);
4404
4571
  resource2.addType(name, `Invoke<'${funcName}', typeof ${varName}>`);
@@ -4456,7 +4623,11 @@ var topicFeature = defineFeature({
4456
4623
  const mockResponses = new TypeObject(1);
4457
4624
  for (const stack of ctx.stackConfigs) {
4458
4625
  for (const topic of stack.topics || []) {
4459
- const name = formatGlobalResourceName(ctx.appConfig.name, "topic", topic);
4626
+ const name = formatGlobalResourceName({
4627
+ appName: ctx.appConfig.name,
4628
+ resourceType: "topic",
4629
+ resourceName: topic
4630
+ });
4460
4631
  mockResponses.addType(topic, "Mock");
4461
4632
  resources.addType(topic, `Publish<'${name}'>`);
4462
4633
  mocks.addType(topic, `MockBuilder`);
@@ -4472,8 +4643,13 @@ var topicFeature = defineFeature({
4472
4643
  for (const stack of ctx.stackConfigs) {
4473
4644
  for (const id of stack.topics ?? []) {
4474
4645
  const group = new Node20(ctx.base, "topic", id);
4646
+ const name = formatGlobalResourceName({
4647
+ appName: ctx.appConfig.name,
4648
+ resourceType: "topic",
4649
+ resourceName: id
4650
+ });
4475
4651
  const topic = new aws20.sns.Topic(group, "topic", {
4476
- name: formatGlobalResourceName(ctx.appConfig.name, "topic", id)
4652
+ name
4477
4653
  });
4478
4654
  ctx.shared.set(`topic-${id}-arn`, topic.arn);
4479
4655
  }
@@ -4657,6 +4833,11 @@ var createApp = (props, filters = []) => {
4657
4833
  const app = new App2(props.appConfig.name);
4658
4834
  const base = new Stack(app, "base");
4659
4835
  const shared = new SharedData();
4836
+ const appId = generateGlobalAppId({
4837
+ accountId: props.accountId,
4838
+ region: props.appConfig.region,
4839
+ appName: props.appConfig.name
4840
+ });
4660
4841
  const commands7 = [];
4661
4842
  const configs = /* @__PURE__ */ new Set();
4662
4843
  const tests = [];
@@ -4679,6 +4860,7 @@ var createApp = (props, filters = []) => {
4679
4860
  feature.onApp?.({
4680
4861
  ...props,
4681
4862
  app,
4863
+ appId,
4682
4864
  // env,
4683
4865
  base,
4684
4866
  shared,
@@ -4743,6 +4925,7 @@ var createApp = (props, filters = []) => {
4743
4925
  ...props,
4744
4926
  stackConfig,
4745
4927
  app,
4928
+ appId,
4746
4929
  // env,
4747
4930
  base,
4748
4931
  stack,
@@ -886,6 +886,7 @@ var SitesSchema = z22.record(
886
886
 
887
887
  // src/feature/store/schema.ts
888
888
  import { z as z23 } from "zod";
889
+ var DeletionProtectionSchema = z23.boolean().describe("Specifies if you want to protect the store from being deleted by awsless.");
889
890
  var StoresSchema = z23.union([
890
891
  z23.array(ResourceIdSchema).transform((list) => {
891
892
  const stores = {};
@@ -898,6 +899,7 @@ var StoresSchema = z23.union([
898
899
  ResourceIdSchema,
899
900
  z23.object({
900
901
  // cors: CorsSchema,
902
+ deletionProtection: DeletionProtectionSchema.optional(),
901
903
  versioning: z23.boolean().default(false).describe("Enable versioning of your store."),
902
904
  events: z23.object({
903
905
  // create
@@ -957,6 +959,7 @@ var StreamsSchema = z24.record(
957
959
  // src/feature/table/schema.ts
958
960
  import { z as z25 } from "zod";
959
961
  var KeySchema = z25.string().min(1).max(255);
962
+ var DeletionProtectionSchema2 = z25.boolean().describe("Specifies if you want to protect the table from being deleted by awsless.");
960
963
  var TablesSchema = z25.record(
961
964
  ResourceIdSchema,
962
965
  z25.object({
@@ -974,6 +977,7 @@ var TablesSchema = z25.record(
974
977
  timeToLiveAttribute: KeySchema.optional().describe(
975
978
  "The name of the TTL attribute used to store the expiration time for items in the table. To update this property, you must first disable TTL and then enable TTL with the new attribute name."
976
979
  ),
980
+ deletionProtection: DeletionProtectionSchema2.optional(),
977
981
  stream: z25.object({
978
982
  type: z25.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]).describe(
979
983
  "When an item in the table is modified, stream.type determines what information is written to the stream for this table. Valid values are:\n- keys-only - Only the key attributes of the modified item are written to the stream.\n- new-image - The entire item, as it appears after it was modified, is written to the stream.\n- old-image - The entire item, as it appeared before it was modified, is written to the stream.\n- new-and-old-images - Both the new and the old item images of the item are written to the stream."
@@ -1140,6 +1144,7 @@ var AppSchema = z32.object({
1140
1144
  http: HttpDefaultSchema,
1141
1145
  rest: RestDefaultSchema,
1142
1146
  pubsub: PubSubDefaultSchema
1147
+ // dataRetention: z.boolean().describe('Configure how your resources are handled on delete.').default(false),
1143
1148
  }).default({}).describe("Default properties")
1144
1149
  });
1145
1150