@awsless/awsless 0.0.323 → 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."
@@ -1958,22 +1963,30 @@ var TypeObject = class {
1958
1963
 
1959
1964
  // src/util/name.ts
1960
1965
  import { paramCase as paramCase3 } from "change-case";
1961
- var formatGlobalResourceName = (appName, ns, id, seperator = "--") => {
1966
+ import { createHmac } from "crypto";
1967
+ var formatGlobalResourceName = (opt) => {
1962
1968
  return [
1963
1969
  //
1964
- appName,
1965
- ns,
1966
- id
1967
- ].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 ?? "--");
1968
1976
  };
1969
- var formatLocalResourceName = (appName, stackName, ns, id, seperator = "--") => {
1977
+ var formatLocalResourceName = (opt) => {
1970
1978
  return [
1971
1979
  //
1972
- appName,
1973
- stackName,
1974
- ns,
1975
- id
1976
- ].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);
1977
1990
  };
1978
1991
 
1979
1992
  // src/feature/function/util.ts
@@ -2173,10 +2186,19 @@ var zipFiles = (files) => {
2173
2186
  import { hashElement } from "folder-hash";
2174
2187
  var createLambdaFunction = (group, ctx, ns, id, local2) => {
2175
2188
  let name;
2176
- if ("stackConfig" in ctx) {
2177
- 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
+ });
2178
2196
  } else {
2179
- name = formatGlobalResourceName(ctx.appConfig.name, ns, id);
2197
+ name = formatGlobalResourceName({
2198
+ appName: ctx.appConfig.name,
2199
+ resourceType: ns,
2200
+ resourceName: id
2201
+ });
2180
2202
  }
2181
2203
  const props = deepmerge(ctx.appConfig.defaults.function, local2);
2182
2204
  let code;
@@ -2190,7 +2212,12 @@ var createLambdaFunction = (group, ctx, ns, id, local2) => {
2190
2212
  }
2191
2213
  });
2192
2214
  return build3(version.hash + props.architecture, async (write) => {
2193
- 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
+ });
2194
2221
  const platform = props.architecture === "arm64" ? "linux/arm64" : "linux/amd64";
2195
2222
  await exec(`docker buildx build --platform ${platform} -t ${name} .`, {
2196
2223
  cwd: basePath2
@@ -2277,6 +2304,7 @@ var createLambdaFunction = (group, ctx, ns, id, local2) => {
2277
2304
  });
2278
2305
  ctx.registerPolicy(policy);
2279
2306
  lambda.addEnvironment("APP", ctx.appConfig.name);
2307
+ lambda.addEnvironment("APP_ID", ctx.appId);
2280
2308
  if ("stackConfig" in ctx) {
2281
2309
  lambda.addEnvironment("STACK", ctx.stackConfig.name);
2282
2310
  }
@@ -2457,7 +2485,11 @@ var authFeature = defineFeature({
2457
2485
  from: props.messaging.fromName ? `${props.messaging.fromName} <${props.messaging.fromEmail}>` : props.messaging.fromEmail
2458
2486
  };
2459
2487
  }
2460
- const name = formatGlobalResourceName(ctx.appConfig.name, "auth", id);
2488
+ const name = formatGlobalResourceName({
2489
+ appName: ctx.app.name,
2490
+ resourceType: "auth",
2491
+ resourceName: id
2492
+ });
2461
2493
  const userPool = new aws3.cognito.UserPool(group, "user-pool", {
2462
2494
  name,
2463
2495
  // deletionProtection: true,
@@ -2517,7 +2549,13 @@ var cacheFeature = defineFeature({
2517
2549
  onStack(ctx) {
2518
2550
  for (const [id, props] of Object.entries(ctx.stackConfig.caches ?? {})) {
2519
2551
  const group = new Node3(ctx.stack, this.name, id);
2520
- 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
+ });
2521
2559
  const subnetGroup = new aws4.memorydb.SubnetGroup(group, "subnets", {
2522
2560
  name,
2523
2561
  subnetIds: [
@@ -2715,7 +2753,12 @@ var cronFeature = defineFeature({
2715
2753
  const group = new Node4(ctx.stack, "cron", id);
2716
2754
  const { lambda } = createAsyncLambdaFunction(group, ctx, "cron", id, props.consumer);
2717
2755
  const rule = new aws5.events.Rule(group, "rule", {
2718
- 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
+ }),
2719
2762
  schedule: props.schedule,
2720
2763
  enabled: props.enabled,
2721
2764
  targets: [
@@ -2889,7 +2932,12 @@ var functionFeature = defineFeature({
2889
2932
  for (const [name, local2] of Object.entries(stack.functions || {})) {
2890
2933
  const props = deepmerge2(ctx.appConfig.defaults.function, local2);
2891
2934
  const varName = camelCase3(`${stack.name}-${name}`);
2892
- 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
+ });
2893
2941
  const relFile = relative(directories.types, props.file);
2894
2942
  if (props.runtime === "container") {
2895
2943
  resource2.addType(name, `Invoke<'${funcName}', Func>`);
@@ -2915,13 +2963,23 @@ var functionFeature = defineFeature({
2915
2963
  onApp(ctx) {
2916
2964
  const group = new Node6(ctx.base, "function", "asset");
2917
2965
  const bucket = new aws7.s3.Bucket(group, "bucket", {
2918
- 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
+ }),
2919
2972
  versioning: true,
2920
2973
  forceDelete: true
2921
2974
  });
2922
2975
  ctx.shared.set("function-bucket-name", bucket.name);
2923
2976
  const repository = new aws7.ecr.Repository(group, "repository", {
2924
- name: formatGlobalResourceName(ctx.appConfig.name, "function", "repository", "-"),
2977
+ name: formatGlobalResourceName({
2978
+ appName: ctx.app.name,
2979
+ resourceType: "function",
2980
+ resourceName: "repository",
2981
+ seperator: "-"
2982
+ }),
2925
2983
  imageTagMutability: true
2926
2984
  });
2927
2985
  ctx.shared.set("function-repository-name", repository.name);
@@ -3125,7 +3183,11 @@ var graphqlFeature = defineFeature({
3125
3183
  const { lambda } = createLambdaFunction(group, ctx, "graphql-auth", id, props.auth.authorizer);
3126
3184
  authorizer = lambda;
3127
3185
  }
3128
- const name = formatGlobalResourceName(ctx.app.name, "graphql", id);
3186
+ const name = formatGlobalResourceName({
3187
+ appName: ctx.app.name,
3188
+ resourceType: "graphql",
3189
+ resourceName: id
3190
+ });
3129
3191
  const api = new aws8.appsync.GraphQLApi(group, "api", {
3130
3192
  name,
3131
3193
  type: "graphql",
@@ -3379,7 +3441,11 @@ var httpFeature = defineFeature({
3379
3441
  const group = new Node8(ctx.base, "http", "main");
3380
3442
  const securityGroup = new aws9.ec2.SecurityGroup(group, "http", {
3381
3443
  vpcId: ctx.shared.get(`vpc-id`),
3382
- name: formatGlobalResourceName(ctx.app.name, "http", "http"),
3444
+ name: formatGlobalResourceName({
3445
+ appName: ctx.app.name,
3446
+ resourceType: "http",
3447
+ resourceName: "http"
3448
+ }),
3383
3449
  description: `Global security group for HTTP api.`
3384
3450
  });
3385
3451
  const port = aws9.ec2.Port.tcp(443);
@@ -3388,7 +3454,11 @@ var httpFeature = defineFeature({
3388
3454
  for (const [id, props] of Object.entries(ctx.appConfig.defaults?.http ?? {})) {
3389
3455
  const group2 = new Node8(ctx.base, "http", id);
3390
3456
  const loadBalancer = new aws9.elb.LoadBalancer(group2, "balancer", {
3391
- name: formatGlobalResourceName(ctx.app.name, "http", id),
3457
+ name: formatGlobalResourceName({
3458
+ appName: ctx.app.name,
3459
+ resourceType: "http",
3460
+ resourceName: id
3461
+ }),
3392
3462
  type: "application",
3393
3463
  securityGroups: [securityGroup.id],
3394
3464
  subnets: [
@@ -3442,7 +3512,12 @@ var httpFeature = defineFeature({
3442
3512
  ...routeProps,
3443
3513
  description: routeKey
3444
3514
  });
3445
- 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
+ });
3446
3521
  const permission = new aws9.lambda.Permission(routeGroup, id, {
3447
3522
  action: "lambda:InvokeFunction",
3448
3523
  principal: "elasticloadbalancing.amazonaws.com",
@@ -3480,13 +3555,18 @@ var instanceFeature = defineFeature({
3480
3555
  onApp(ctx) {
3481
3556
  const group = new Node9(ctx.base, "instance", "asset");
3482
3557
  const bucket = new aws10.s3.Bucket(group, "bucket", {
3483
- 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
+ }),
3484
3564
  forceDelete: true
3485
3565
  });
3486
3566
  ctx.shared.set("instance-bucket-name", bucket.name);
3487
3567
  if (ctx.appConfig.defaults.instance.connect) {
3488
3568
  new aws10.ec2.InstanceConnectEndpoint(group, "connect", {
3489
- name: ctx.appConfig.name,
3569
+ name: ctx.app.name,
3490
3570
  subnetId: ctx.shared.get(`vpc-public-subnet-id-1`),
3491
3571
  securityGroupIds: [ctx.shared.get("vpc-security-group-id")]
3492
3572
  });
@@ -3495,10 +3575,16 @@ var instanceFeature = defineFeature({
3495
3575
  onStack(ctx) {
3496
3576
  for (const [id, props] of Object.entries(ctx.stackConfig.instances ?? {})) {
3497
3577
  const group = new Node9(ctx.stack, "instance", id);
3498
- 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
+ });
3499
3584
  const env = {
3500
- APP: ctx.appConfig.name,
3501
- STACK: ctx.stackConfig.name
3585
+ APP: ctx.app.name,
3586
+ APP_ID: ctx.appId,
3587
+ STACK: ctx.stack.name
3502
3588
  };
3503
3589
  ctx.onEnv((name2, value) => {
3504
3590
  env[name2] = value;
@@ -3621,7 +3707,11 @@ var onFailureFeature = defineFeature({
3621
3707
  throw new TypeError("Only 1 onFailure configuration is allowed in your app.");
3622
3708
  }
3623
3709
  const queue2 = new aws11.sqs.Queue(ctx.base, "on-failure", {
3624
- name: formatGlobalResourceName(ctx.appConfig.name, "on-failure", "failure")
3710
+ name: formatGlobalResourceName({
3711
+ appName: ctx.app.name,
3712
+ resourceType: "on-failure",
3713
+ resourceName: "failure"
3714
+ })
3625
3715
  });
3626
3716
  ctx.shared.set("on-failure-queue-arn", queue2.arn);
3627
3717
  },
@@ -3664,7 +3754,11 @@ var pubsubFeature = defineFeature({
3664
3754
  const { lambda } = createLambdaFunction(group, ctx, "pubsub-authorizer", id, functionProps);
3665
3755
  lambda.addEnvironment("PUBSUB_POLICY", JSON.stringify(props.policy));
3666
3756
  lambda.addEnvironment("AWS_ACCOUNT_ID", ctx.accountId);
3667
- const name = formatGlobalResourceName(ctx.app.name, "pubsub", id);
3757
+ const name = formatGlobalResourceName({
3758
+ appName: ctx.app.name,
3759
+ resourceType: "pubsub",
3760
+ resourceName: id
3761
+ });
3668
3762
  const authorizer = new aws12.iot.Authorizer(group, "authorizer", {
3669
3763
  name,
3670
3764
  functionArn: lambda.arn
@@ -3713,7 +3807,12 @@ var pubsubFeature = defineFeature({
3713
3807
  for (const [id, props] of Object.entries(ctx.stackConfig.pubsub ?? {})) {
3714
3808
  const group = new Node11(ctx.stack, "pubsub", id);
3715
3809
  const { lambda } = createAsyncLambdaFunction(group, ctx, `pubsub`, id, props.consumer);
3716
- 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
+ });
3717
3816
  const topic = new aws12.iot.TopicRule(group, "rule", {
3718
3817
  name: name.replaceAll("-", "_"),
3719
3818
  sql: props.sql,
@@ -3765,7 +3864,12 @@ var queueFeature = defineFeature({
3765
3864
  const mockResponse = new TypeObject(2);
3766
3865
  for (const [name, fileOrProps] of Object.entries(stack.queues || {})) {
3767
3866
  const varName = camelCase5(`${stack.name}-${name}`);
3768
- 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
+ });
3769
3873
  const file = typeof fileOrProps === "string" ? fileOrProps : typeof fileOrProps.consumer === "string" ? fileOrProps.consumer : fileOrProps.consumer.file;
3770
3874
  const relFile = relative3(directories.types, file);
3771
3875
  gen.addImport(varName, relFile);
@@ -3787,8 +3891,14 @@ var queueFeature = defineFeature({
3787
3891
  for (const [id, local2] of Object.entries(ctx.stackConfig.queues || {})) {
3788
3892
  const props = deepmerge3(ctx.appConfig.defaults.queue, local2);
3789
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
+ });
3790
3900
  const queue2 = new aws13.sqs.Queue(group, "queue", {
3791
- name: formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, "queue", id),
3901
+ name,
3792
3902
  deadLetterArn: getGlobalOnFailure(ctx),
3793
3903
  ...props
3794
3904
  });
@@ -3821,8 +3931,13 @@ var restFeature = defineFeature({
3821
3931
  onApp(ctx) {
3822
3932
  for (const [id, props] of Object.entries(ctx.appConfig.defaults?.rest ?? {})) {
3823
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
+ });
3824
3939
  const api = new aws14.apiGatewayV2.Api(group, "api", {
3825
- name: formatGlobalResourceName(ctx.app.name, "rest", id),
3940
+ name,
3826
3941
  protocolType: "HTTP"
3827
3942
  });
3828
3943
  const stage = new aws14.apiGatewayV2.Stage(group, "stage", {
@@ -4002,7 +4117,12 @@ var siteFeature = defineFeature({
4002
4117
  onStack(ctx) {
4003
4118
  for (const [id, props] of Object.entries(ctx.stackConfig.sites ?? {})) {
4004
4119
  const group = new Node15(ctx.stack, "site", id);
4005
- 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
+ });
4006
4126
  const origins = [];
4007
4127
  const originGroups = [];
4008
4128
  let bucket;
@@ -4037,7 +4157,13 @@ var siteFeature = defineFeature({
4037
4157
  }
4038
4158
  if (props.static) {
4039
4159
  bucket = new aws16.s3.Bucket(group, "bucket", {
4040
- 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
+ }),
4041
4167
  forceDelete: true,
4042
4168
  website: {
4043
4169
  indexDocument: "index.html",
@@ -4213,7 +4339,12 @@ var storeFeature = defineFeature({
4213
4339
  for (const stack of ctx.stackConfigs) {
4214
4340
  const list4 = new TypeObject(2);
4215
4341
  for (const id of Object.keys(stack.stores ?? {})) {
4216
- 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
+ });
4217
4348
  list4.addType(id, `Store<'${storeName}'>`);
4218
4349
  }
4219
4350
  resources.addType(stack.name, list4);
@@ -4222,10 +4353,19 @@ var storeFeature = defineFeature({
4222
4353
  gen.addInterface("StoreResources", resources);
4223
4354
  await ctx.write("store.d.ts", gen, true);
4224
4355
  },
4356
+ onApp(ctx) {
4357
+ ctx.addEnv("STORE_POSTFIX", ctx.appId);
4358
+ },
4225
4359
  onStack(ctx) {
4226
4360
  for (const [id, props] of Object.entries(ctx.stackConfig.stores ?? {})) {
4227
4361
  const group = new Node16(ctx.stack, "store", id);
4228
- 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
+ });
4229
4369
  const lambdaConfigs = [];
4230
4370
  const eventMap = {
4231
4371
  "created:*": "s3:ObjectCreated:*",
@@ -4248,7 +4388,7 @@ var storeFeature = defineFeature({
4248
4388
  action: "lambda:InvokeFunction",
4249
4389
  principal: "s3.amazonaws.com",
4250
4390
  functionArn: lambda.arn,
4251
- sourceArn: `arn:aws:s3:::${bucketName}`
4391
+ sourceArn: `arn:aws:s3:::${name}`
4252
4392
  });
4253
4393
  lambdaConfigs.push({
4254
4394
  event: eventMap[event],
@@ -4256,7 +4396,7 @@ var storeFeature = defineFeature({
4256
4396
  });
4257
4397
  }
4258
4398
  const bucket = new aws17.s3.Bucket(group, "store", {
4259
- name: bucketName,
4399
+ name,
4260
4400
  versioning: props.versioning,
4261
4401
  forceDelete: true,
4262
4402
  lambdaConfigs,
@@ -4271,6 +4411,9 @@ var storeFeature = defineFeature({
4271
4411
  // ---------------------------------------------
4272
4412
  ]
4273
4413
  });
4414
+ if (props.deletionProtection) {
4415
+ bucket.deletionPolicy = "retain";
4416
+ }
4274
4417
  ctx.onPolicy((policy) => {
4275
4418
  policy.addStatement(bucket.permissions);
4276
4419
  });
@@ -4286,7 +4429,12 @@ var streamFeature = defineFeature({
4286
4429
  onStack(ctx) {
4287
4430
  for (const [id, props] of Object.entries(ctx.stackConfig.streams ?? {})) {
4288
4431
  const group = new Node17(ctx.stack, "stream", id);
4289
- 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
+ });
4290
4438
  const channel = new aws18.ivs.Channel(group, "channel", {
4291
4439
  name,
4292
4440
  ...props
@@ -4312,7 +4460,12 @@ var tableFeature = defineFeature({
4312
4460
  for (const stack of ctx.stackConfigs) {
4313
4461
  const list4 = new TypeObject(2);
4314
4462
  for (const name of Object.keys(stack.tables || {})) {
4315
- 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
+ });
4316
4469
  list4.addType(name, `'${tableName}'`);
4317
4470
  }
4318
4471
  resources.addType(stack.name, list4);
@@ -4323,11 +4476,21 @@ var tableFeature = defineFeature({
4323
4476
  onStack(ctx) {
4324
4477
  for (const [id, props] of Object.entries(ctx.stackConfig.tables ?? {})) {
4325
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
+ });
4326
4485
  const table2 = new aws19.dynamodb.Table(group, "table", {
4327
4486
  ...props,
4328
- name: formatLocalResourceName(ctx.appConfig.name, ctx.stackConfig.name, "table", id),
4329
- stream: props.stream?.type
4487
+ name,
4488
+ stream: props.stream?.type,
4489
+ deletionProtection: props.deletionProtection
4330
4490
  });
4491
+ if (props.deletionProtection) {
4492
+ table2.deletionPolicy = "retain";
4493
+ }
4331
4494
  if (props.stream) {
4332
4495
  const { lambda, policy } = createLambdaFunction(group, ctx, "table", id, props.stream.consumer);
4333
4496
  lambda.addEnvironment("LOG_VIEWABLE_ERROR", "1");
@@ -4397,7 +4560,12 @@ var taskFeature = defineFeature({
4397
4560
  const mockResponse = new TypeObject(2);
4398
4561
  for (const [name, props] of Object.entries(stack.tasks || {})) {
4399
4562
  const varName = camelCase6(`${stack.name}-${name}`);
4400
- 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
+ });
4401
4569
  const relFile = relative4(directories.types, props.consumer.file);
4402
4570
  types2.addImport(varName, relFile);
4403
4571
  resource2.addType(name, `Invoke<'${funcName}', typeof ${varName}>`);
@@ -4455,7 +4623,11 @@ var topicFeature = defineFeature({
4455
4623
  const mockResponses = new TypeObject(1);
4456
4624
  for (const stack of ctx.stackConfigs) {
4457
4625
  for (const topic of stack.topics || []) {
4458
- const name = formatGlobalResourceName(ctx.appConfig.name, "topic", topic);
4626
+ const name = formatGlobalResourceName({
4627
+ appName: ctx.appConfig.name,
4628
+ resourceType: "topic",
4629
+ resourceName: topic
4630
+ });
4459
4631
  mockResponses.addType(topic, "Mock");
4460
4632
  resources.addType(topic, `Publish<'${name}'>`);
4461
4633
  mocks.addType(topic, `MockBuilder`);
@@ -4471,8 +4643,13 @@ var topicFeature = defineFeature({
4471
4643
  for (const stack of ctx.stackConfigs) {
4472
4644
  for (const id of stack.topics ?? []) {
4473
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
+ });
4474
4651
  const topic = new aws20.sns.Topic(group, "topic", {
4475
- name: formatGlobalResourceName(ctx.appConfig.name, "topic", id)
4652
+ name
4476
4653
  });
4477
4654
  ctx.shared.set(`topic-${id}-arn`, topic.arn);
4478
4655
  }
@@ -4656,6 +4833,11 @@ var createApp = (props, filters = []) => {
4656
4833
  const app = new App2(props.appConfig.name);
4657
4834
  const base = new Stack(app, "base");
4658
4835
  const shared = new SharedData();
4836
+ const appId = generateGlobalAppId({
4837
+ accountId: props.accountId,
4838
+ region: props.appConfig.region,
4839
+ appName: props.appConfig.name
4840
+ });
4659
4841
  const commands7 = [];
4660
4842
  const configs = /* @__PURE__ */ new Set();
4661
4843
  const tests = [];
@@ -4678,6 +4860,7 @@ var createApp = (props, filters = []) => {
4678
4860
  feature.onApp?.({
4679
4861
  ...props,
4680
4862
  app,
4863
+ appId,
4681
4864
  // env,
4682
4865
  base,
4683
4866
  shared,
@@ -4742,6 +4925,7 @@ var createApp = (props, filters = []) => {
4742
4925
  ...props,
4743
4926
  stackConfig,
4744
4927
  app,
4928
+ appId,
4745
4929
  // env,
4746
4930
  base,
4747
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
 
package/dist/server.d.ts CHANGED
@@ -93,9 +93,9 @@ interface SearchResources {
93
93
  }
94
94
  declare const Search: SearchResources;
95
95
 
96
- declare const getSiteBucketName: <N extends string, S extends string = "stack">(name: N, stack?: S) => `app--${S}--site--${N}`;
96
+ declare const getSiteBucketName: <N extends string, S extends string = "stack">(name: N, stack?: S) => `app--${S}--site--${N}--${string}`;
97
97
 
98
- declare const getStoreName: <N extends string, S extends string = "stack">(name: N, stack?: S) => `app--${S}--store--${N}`;
98
+ declare const getStoreName: <N extends string, S extends string = "stack">(name: N, stack?: S) => `app--${S}--store--${N}--${string}`;
99
99
  interface StoreResources {
100
100
  }
101
101
  declare const Store: StoreResources;