@awsless/awsless 0.0.188 → 0.0.190

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
@@ -165,6 +165,9 @@ var directories = {
165
165
  get cache() {
166
166
  return join(this.output, "cache");
167
167
  },
168
+ get state() {
169
+ return join(this.output, "state");
170
+ },
168
171
  get build() {
169
172
  return join(this.output, "build");
170
173
  },
@@ -1462,11 +1465,12 @@ import {
1462
1465
  ScalarAttributeType
1463
1466
  } from "@aws-sdk/client-dynamodb";
1464
1467
  import { confirm, log as log6 } from "@clack/prompts";
1465
- var hasStateTable = async (client) => {
1468
+ import { CreateBucketCommand, HeadBucketCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
1469
+ var hasLockTable = async (client) => {
1466
1470
  try {
1467
1471
  const result = await client.send(
1468
1472
  new DescribeTableCommand({
1469
- TableName: "awsless-state"
1473
+ TableName: "awsless-locks"
1470
1474
  })
1471
1475
  );
1472
1476
  return !!result.Table;
@@ -1477,10 +1481,26 @@ var hasStateTable = async (client) => {
1477
1481
  throw error;
1478
1482
  }
1479
1483
  };
1480
- var createStateTable = (client) => {
1484
+ var hasStateBucket = async (client) => {
1485
+ try {
1486
+ const result = await client.send(
1487
+ new HeadBucketCommand({
1488
+ Bucket: "awsless-state"
1489
+ })
1490
+ );
1491
+ return !!result.BucketRegion;
1492
+ } catch (error) {
1493
+ console.log(error);
1494
+ if (error instanceof S3ServiceException) {
1495
+ return false;
1496
+ }
1497
+ throw error;
1498
+ }
1499
+ };
1500
+ var createLockTable = (client) => {
1481
1501
  return client.send(
1482
1502
  new CreateTableCommand({
1483
- TableName: "awsless-state",
1503
+ TableName: "awsless-locks",
1484
1504
  BillingMode: BillingMode.PAY_PER_REQUEST,
1485
1505
  KeySchema: [
1486
1506
  {
@@ -1497,10 +1517,22 @@ var createStateTable = (client) => {
1497
1517
  })
1498
1518
  );
1499
1519
  };
1500
- var bootstrapAwsless = async (opts) => {
1501
- const client = new DynamoDB(opts);
1502
- const table2 = await hasStateTable(client);
1503
- if (!table2) {
1520
+ var createStateBucket = (client) => {
1521
+ return client.send(
1522
+ new CreateBucketCommand({
1523
+ Bucket: "awsless-state"
1524
+ })
1525
+ );
1526
+ };
1527
+ var bootstrapAwsless = async (props) => {
1528
+ const dynamo = new DynamoDB(props);
1529
+ const s3 = new S3Client(props);
1530
+ const [table2, bucket] = await Promise.all([
1531
+ //
1532
+ hasLockTable(dynamo),
1533
+ hasStateBucket(s3)
1534
+ ]);
1535
+ if (!table2 || !bucket) {
1504
1536
  log6.warn(`Your Awsless hasn't been bootstrapped yet.`);
1505
1537
  if (!process.env.SKIP_PROMPT) {
1506
1538
  const confirmed = await confirm({
@@ -1511,7 +1543,12 @@ var bootstrapAwsless = async (opts) => {
1511
1543
  }
1512
1544
  }
1513
1545
  await task("Bootstrapping", async (update) => {
1514
- await createStateTable(client);
1546
+ if (!table2) {
1547
+ await createLockTable(dynamo);
1548
+ }
1549
+ if (!bucket) {
1550
+ await createStateBucket(s3);
1551
+ }
1515
1552
  update("Done deploying the bootstrap stack");
1516
1553
  });
1517
1554
  } else {
@@ -1991,14 +2028,14 @@ var build = (type, name, builder) => {
1991
2028
  };
1992
2029
 
1993
2030
  // src/feature/function/util.ts
1994
- var createLambdaFunction = (group, ctx, ns, id, local) => {
2031
+ var createLambdaFunction = (group, ctx, ns, id, local2) => {
1995
2032
  let name;
1996
2033
  if ("stackConfig" in ctx) {
1997
2034
  name = formatLocalResourceName(ctx.appConfig.name, ctx.stackConfig.name, ns, id);
1998
2035
  } else {
1999
2036
  name = formatGlobalResourceName(ctx.appConfig.name, ns, id);
2000
2037
  }
2001
- const props = deepmerge(ctx.appConfig.defaults.function, local);
2038
+ const props = deepmerge(ctx.appConfig.defaults.function, local2);
2002
2039
  ctx.registerBuild("function", name, async (build3) => {
2003
2040
  const version = await fingerprintFromFile(props.file);
2004
2041
  return build3(version, async (write) => {
@@ -2073,8 +2110,8 @@ var createLambdaFunction = (group, ctx, ns, id, local) => {
2073
2110
  if (ctx.appConfig.defaults.function.permissions) {
2074
2111
  policy.addStatement(...ctx.appConfig.defaults.function.permissions);
2075
2112
  }
2076
- if ("permissions" in local && local.permissions) {
2077
- policy.addStatement(...local.permissions);
2113
+ if ("permissions" in local2 && local2.permissions) {
2114
+ policy.addStatement(...local2.permissions);
2078
2115
  }
2079
2116
  if (props.warm) {
2080
2117
  const rule = new aws2.events.Rule(group, "warm", {
@@ -2640,6 +2677,15 @@ export function response(ctx) {
2640
2677
  return ctx.result
2641
2678
  }
2642
2679
  `;
2680
+ var baseSchema = `
2681
+ type Query
2682
+ type Mutation
2683
+
2684
+ schema {
2685
+ query: Query
2686
+ mutation: Mutation
2687
+ }
2688
+ `;
2643
2689
  var scalarSchema = `
2644
2690
  scalar AWSDate
2645
2691
  scalar AWSTime
@@ -2799,7 +2845,7 @@ var graphqlFeature = defineFeature({
2799
2845
  const source = await readFile5(props.schema, "utf8");
2800
2846
  const finger = createHash4("sha1").update(source).digest("hex");
2801
2847
  return build3(finger, async (write) => {
2802
- const defs = mergeTypeDefs([scalarSchema, source]);
2848
+ const defs = mergeTypeDefs([scalarSchema, baseSchema, source]);
2803
2849
  const output = print(defs);
2804
2850
  const schema2 = buildSchema(output);
2805
2851
  for (const [typeName, fields] of Object.entries(props.resolvers ?? {})) {
@@ -3028,8 +3074,8 @@ var queueFeature = defineFeature({
3028
3074
  await ctx.write("queue.d.ts", gen, true);
3029
3075
  },
3030
3076
  onStack(ctx) {
3031
- for (const [id, local] of Object.entries(ctx.stackConfig.queues || {})) {
3032
- const props = deepmerge2(ctx.appConfig.defaults.queue, local);
3077
+ for (const [id, local2] of Object.entries(ctx.stackConfig.queues || {})) {
3078
+ const props = deepmerge2(ctx.appConfig.defaults.queue, local2);
3033
3079
  const group = new Node9(ctx.stack, "queue", id);
3034
3080
  const queue2 = new aws9.sqs.Queue(group, "queue", {
3035
3081
  name: formatLocalResourceName(ctx.appConfig.name, ctx.stack.name, "queue", id),
@@ -4153,8 +4199,50 @@ var config = (program2) => {
4153
4199
 
4154
4200
  // src/cli/command/delete.ts
4155
4201
  import { confirm as confirm3 } from "@clack/prompts";
4156
- import { WorkSpace, aws as aws18 } from "@awsless/formation";
4202
+
4203
+ // src/util/workspace.ts
4204
+ import { WorkSpace, aws as aws18, local } from "@awsless/formation";
4157
4205
  import { minutes as minutes4 } from "@awsless/duration";
4206
+ import { dirname as dirname8, join as join9 } from "path";
4207
+ import { mkdir as mkdir2, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
4208
+ var createWorkSpace = (props) => {
4209
+ const lockProvider = new aws18.dynamodb.LockProvider({
4210
+ ...props,
4211
+ tableName: "awsless-locks"
4212
+ });
4213
+ const stateProvider = new aws18.s3.StateProvider({
4214
+ ...props,
4215
+ bucket: "awsless-state"
4216
+ });
4217
+ const cloudProviders = aws18.createCloudProviders({
4218
+ ...props,
4219
+ timeout: minutes4(60)
4220
+ });
4221
+ const workspace = new WorkSpace({
4222
+ lockProvider,
4223
+ stateProvider,
4224
+ cloudProviders
4225
+ });
4226
+ return {
4227
+ workspace,
4228
+ lockProvider,
4229
+ stateProvider
4230
+ };
4231
+ };
4232
+ var pullRemoteState = async (app, stateProvider) => {
4233
+ const file = join9(directories.state, `${app.urn}.json`);
4234
+ const state2 = await stateProvider.get(app.urn);
4235
+ await mkdir2(dirname8(file), { recursive: true });
4236
+ await writeFile2(file, JSON.stringify(state2, void 0, 2));
4237
+ };
4238
+ var pushRemoteState = async (app, stateProvider) => {
4239
+ const file = join9(directories.state, `${app.urn}.json`);
4240
+ const data = await readFile6(file, "utf8");
4241
+ const state2 = JSON.parse(data);
4242
+ await stateProvider.update(app.urn, state2);
4243
+ };
4244
+
4245
+ // src/cli/command/delete.ts
4158
4246
  var del2 = (program2) => {
4159
4247
  program2.command("delete").argument("[stacks...]", "Optionally filter stacks to delete").description("Delete your app from AWS").action(async (filters) => {
4160
4248
  await layout("delete", async ({ appConfig, stackConfigs }) => {
@@ -4177,20 +4265,13 @@ var del2 = (program2) => {
4177
4265
  throw new Cancelled();
4178
4266
  }
4179
4267
  }
4180
- const workspace = new WorkSpace({
4181
- stateProvider: new aws18.dynamodb.StateProvider({
4182
- credentials,
4183
- region,
4184
- tableName: "awsless-state"
4185
- }),
4186
- cloudProviders: aws18.createCloudProviders({
4187
- credentials,
4188
- region: appConfig.region,
4189
- timeout: minutes4(30)
4190
- })
4268
+ const { workspace, stateProvider } = createWorkSpace({
4269
+ credentials,
4270
+ region
4191
4271
  });
4192
4272
  await task("Deleting the stacks to AWS", async (update) => {
4193
4273
  await workspace.deleteApp(app);
4274
+ await pullRemoteState(app, stateProvider);
4194
4275
  update("Done deleting the stacks to AWS.");
4195
4276
  });
4196
4277
  return "Your app has been deleted!";
@@ -4199,12 +4280,11 @@ var del2 = (program2) => {
4199
4280
  };
4200
4281
 
4201
4282
  // src/cli/command/deploy.ts
4202
- import { WorkSpace as WorkSpace2, aws as aws19 } from "@awsless/formation";
4203
4283
  import { confirm as confirm4 } from "@clack/prompts";
4204
4284
 
4205
4285
  // src/cli/ui/complex/run-tests.ts
4206
- import { join as join9 } from "path";
4207
- import { mkdir as mkdir2, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
4286
+ import { join as join10 } from "path";
4287
+ import { mkdir as mkdir3, readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
4208
4288
 
4209
4289
  // src/test/reporter.ts
4210
4290
  import { getSuites, getTests } from "@vitest/runner/utils";
@@ -4388,12 +4468,12 @@ var logTestErrors = (event) => {
4388
4468
  });
4389
4469
  };
4390
4470
  var runTest = async (stack, dir, filters) => {
4391
- await mkdir2(directories.test, { recursive: true });
4471
+ await mkdir3(directories.test, { recursive: true });
4392
4472
  const fingerprint = await fingerprintFromDirectory(dir);
4393
- const file = join9(directories.test, `${stack}.json`);
4473
+ const file = join10(directories.test, `${stack}.json`);
4394
4474
  const exists = await fileExist(file);
4395
4475
  if (exists && !process.env.NO_CACHE) {
4396
- const raw = await readFile6(file, { encoding: "utf8" });
4476
+ const raw = await readFile7(file, { encoding: "utf8" });
4397
4477
  const data = JSON.parse(raw);
4398
4478
  if (data.fingerprint === fingerprint) {
4399
4479
  log8.step(
@@ -4434,7 +4514,7 @@ var runTest = async (stack, dir, filters) => {
4434
4514
  });
4435
4515
  logTestLogs(result);
4436
4516
  logTestErrors(result);
4437
- await writeFile2(
4517
+ await writeFile3(
4438
4518
  file,
4439
4519
  JSON.stringify({
4440
4520
  ...result,
@@ -4456,7 +4536,6 @@ var runTests = async (tests, filters = []) => {
4456
4536
  };
4457
4537
 
4458
4538
  // src/cli/command/deploy.ts
4459
- import { minutes as minutes5 } from "@awsless/duration";
4460
4539
  var deploy = (program2) => {
4461
4540
  program2.command("deploy").argument("[stacks...]", "Optionally filter stacks to deploy").description("Deploy your app to AWS").action(async (filters) => {
4462
4541
  await layout("deploy", async ({ appConfig, stackConfigs }) => {
@@ -4483,20 +4562,13 @@ var deploy = (program2) => {
4483
4562
  throw new Cancelled();
4484
4563
  }
4485
4564
  await buildAssets(builders);
4486
- const workspace = new WorkSpace2({
4487
- stateProvider: new aws19.dynamodb.StateProvider({
4488
- credentials,
4489
- region,
4490
- tableName: "awsless-state"
4491
- }),
4492
- cloudProviders: aws19.createCloudProviders({
4493
- credentials,
4494
- region: appConfig.region,
4495
- timeout: minutes5(60)
4496
- })
4565
+ const { workspace, stateProvider } = createWorkSpace({
4566
+ credentials,
4567
+ region
4497
4568
  });
4498
4569
  await task("Deploying the stacks to AWS", async (update) => {
4499
4570
  await workspace.deployApp(app);
4571
+ await pullRemoteState(app, stateProvider);
4500
4572
  update("Done deploying the stacks to AWS.");
4501
4573
  });
4502
4574
  return "Your app is ready!";
@@ -4505,7 +4577,7 @@ var deploy = (program2) => {
4505
4577
  };
4506
4578
 
4507
4579
  // src/cli/command/diff.ts
4508
- import { WorkSpace as WorkSpace3, aws as aws20 } from "@awsless/formation";
4580
+ import { WorkSpace as WorkSpace2, aws as aws19 } from "@awsless/formation";
4509
4581
  import chalk7 from "chalk";
4510
4582
  var diff = (program2) => {
4511
4583
  program2.command("diff").description("Diff your app with AWS").action(async (filters) => {
@@ -4516,13 +4588,13 @@ var diff = (program2) => {
4516
4588
  await bootstrapAwsless({ credentials, region });
4517
4589
  const { app, builders } = createApp({ appConfig, stackConfigs, accountId }, filters);
4518
4590
  await buildAssets(builders);
4519
- const workspace = new WorkSpace3({
4520
- stateProvider: new aws20.dynamodb.DynamoDBStateProvider({
4591
+ const workspace = new WorkSpace2({
4592
+ stateProvider: new aws19.dynamodb.DynamoDBStateProvider({
4521
4593
  credentials,
4522
4594
  region,
4523
4595
  tableName: "awsless-state"
4524
4596
  }),
4525
- cloudProviders: aws20.createCloudProviders({
4597
+ cloudProviders: aws19.createCloudProviders({
4526
4598
  credentials,
4527
4599
  region: appConfig.region
4528
4600
  })
@@ -4577,8 +4649,8 @@ var diff = (program2) => {
4577
4649
  import { log as log9 } from "@clack/prompts";
4578
4650
 
4579
4651
  // src/type-gen/generate.ts
4580
- import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
4581
- import { dirname as dirname8, join as join10, relative as relative4 } from "path";
4652
+ import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
4653
+ import { dirname as dirname9, join as join11, relative as relative4 } from "path";
4582
4654
  var generateTypes = async (props) => {
4583
4655
  const files = [];
4584
4656
  await Promise.all(
@@ -4587,13 +4659,13 @@ var generateTypes = async (props) => {
4587
4659
  ...props,
4588
4660
  async write(file, data, include = false) {
4589
4661
  const code = data?.toString("utf8");
4590
- const path = join10(directories.types, file);
4662
+ const path = join11(directories.types, file);
4591
4663
  if (code) {
4592
4664
  if (include) {
4593
4665
  files.push(relative4(directories.root, path));
4594
4666
  }
4595
- await mkdir3(dirname8(path), { recursive: true });
4596
- await writeFile3(path, code);
4667
+ await mkdir4(dirname9(path), { recursive: true });
4668
+ await writeFile4(path, code);
4597
4669
  }
4598
4670
  }
4599
4671
  });
@@ -4601,7 +4673,7 @@ var generateTypes = async (props) => {
4601
4673
  );
4602
4674
  if (files.length) {
4603
4675
  const code = files.map((file) => `/// <reference path='${file}' />`).join("\n");
4604
- await writeFile3(join10(directories.root, `awsless.d.ts`), code);
4676
+ await writeFile4(join11(directories.root, `awsless.d.ts`), code);
4605
4677
  }
4606
4678
  };
4607
4679
 
@@ -4727,8 +4799,53 @@ var dev = (program2) => {
4727
4799
  });
4728
4800
  };
4729
4801
 
4802
+ // src/cli/command/state/pull.ts
4803
+ var pull = (program2) => {
4804
+ program2.command("pull").description("Pull the remote state and store it locally").action(async () => {
4805
+ await layout("state pull", async ({ appConfig, stackConfigs }) => {
4806
+ const region = appConfig.region;
4807
+ const credentials = getCredentials(appConfig.profile);
4808
+ const accountId = await getAccountId(credentials, region);
4809
+ const { app } = createApp({ appConfig, stackConfigs, accountId });
4810
+ const { stateProvider } = createWorkSpace({ credentials, region });
4811
+ await pullRemoteState(app, stateProvider);
4812
+ return "State pull was successful.";
4813
+ });
4814
+ });
4815
+ };
4816
+
4817
+ // src/cli/command/state/push.ts
4818
+ import { confirm as confirm5 } from "@clack/prompts";
4819
+ var push = (program2) => {
4820
+ program2.command("push").description("Push the local state to the remote server").action(async () => {
4821
+ await layout("state pull", async ({ appConfig, stackConfigs }) => {
4822
+ const region = appConfig.region;
4823
+ const credentials = getCredentials(appConfig.profile);
4824
+ const accountId = await getAccountId(credentials, region);
4825
+ const { app } = createApp({ appConfig, stackConfigs, accountId });
4826
+ const { stateProvider } = createWorkSpace({ credentials, region });
4827
+ const ok = await confirm5({
4828
+ message: "Pushing up the local state might corrupt your remote state. Are you sure?",
4829
+ initialValue: false
4830
+ });
4831
+ if (!ok) {
4832
+ throw new Cancelled();
4833
+ }
4834
+ await pushRemoteState(app, stateProvider);
4835
+ return "State push was successful.";
4836
+ });
4837
+ });
4838
+ };
4839
+
4840
+ // src/cli/command/state/index.ts
4841
+ var commands3 = [pull, push];
4842
+ var state = (program2) => {
4843
+ const command = program2.command("state").description(`Manage app state`);
4844
+ commands3.forEach((cb) => cb(command));
4845
+ };
4846
+
4730
4847
  // src/cli/command/index.ts
4731
- var commands3 = [
4848
+ var commands4 = [
4732
4849
  bootstrap,
4733
4850
  types,
4734
4851
  build2,
@@ -4737,6 +4854,7 @@ var commands3 = [
4737
4854
  del2,
4738
4855
  dev,
4739
4856
  // bind,
4857
+ state,
4740
4858
  resource,
4741
4859
  config,
4742
4860
  test
@@ -4762,7 +4880,7 @@ program.on("option:skip-prompt", () => {
4762
4880
  program.on("option:no-cache", () => {
4763
4881
  process.env.NO_CACHE = program.opts().noCache ? "1" : void 0;
4764
4882
  });
4765
- commands3.forEach((fn) => fn(program));
4883
+ commands4.forEach((fn) => fn(program));
4766
4884
 
4767
4885
  // src/bin.ts
4768
4886
  program.parse(process.argv);
@@ -42,6 +42,9 @@ var directories = {
42
42
  get cache() {
43
43
  return join(this.output, "cache");
44
44
  },
45
+ get state() {
46
+ return join(this.output, "state");
47
+ },
45
48
  get build() {
46
49
  return join(this.output, "build");
47
50
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awsless/awsless",
3
- "version": "0.0.188",
3
+ "version": "0.0.190",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -30,8 +30,8 @@
30
30
  "peerDependencies": {
31
31
  "@awsless/redis": "^0.0.12",
32
32
  "@awsless/s3": "^0.0.10",
33
- "@awsless/sns": "^0.0.7",
34
33
  "@awsless/lambda": "^0.0.18",
34
+ "@awsless/sns": "^0.0.7",
35
35
  "@awsless/sqs": "^0.0.7",
36
36
  "@awsless/ssm": "^0.0.7",
37
37
  "@awsless/validate": "^0.0.13",
@@ -97,10 +97,10 @@
97
97
  "zod": "^3.21.4",
98
98
  "zod-to-json-schema": "^3.22.3",
99
99
  "@awsless/duration": "^0.0.1",
100
+ "@awsless/formation": "^0.0.13",
100
101
  "@awsless/size": "^0.0.1",
101
- "@awsless/formation": "^0.0.12",
102
- "@awsless/graphql": "^0.0.9",
103
102
  "@awsless/validate": "^0.0.13",
103
+ "@awsless/graphql": "^0.0.9",
104
104
  "@awsless/code": "^0.0.10"
105
105
  },
106
106
  "scripts": {