@wraps.dev/cli 2.21.15 → 2.21.17

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.
Binary file
package/dist/cli.js CHANGED
@@ -32520,9 +32520,9 @@ Run ${pc43.cyan("wraps email init")} or ${pc43.cyan("wraps sms init")} first.
32520
32520
  let webhookSecret;
32521
32521
  let needsDeployment = false;
32522
32522
  if (hasEmail) {
32523
- const emailConfig = metadata.services.email?.config;
32523
+ const emailConfig2 = metadata.services.email?.config;
32524
32524
  const existingSecret = metadata.services.email?.webhookSecret;
32525
- if (!emailConfig?.eventTracking?.enabled) {
32525
+ if (!emailConfig2?.eventTracking?.enabled) {
32526
32526
  progress.stop();
32527
32527
  log37.warn(
32528
32528
  "Event tracking must be enabled to connect to the Wraps Platform."
@@ -32539,7 +32539,7 @@ Run ${pc43.cyan("wraps email init")} or ${pc43.cyan("wraps sms init")} first.
32539
32539
  process.exit(0);
32540
32540
  }
32541
32541
  metadata.services.email.config = {
32542
- ...emailConfig,
32542
+ ...emailConfig2,
32543
32543
  eventTracking: {
32544
32544
  enabled: true,
32545
32545
  eventBridge: true,
@@ -32551,8 +32551,8 @@ Run ${pc43.cyan("wraps email init")} or ${pc43.cyan("wraps sms init")} first.
32551
32551
  "BOUNCE",
32552
32552
  "COMPLAINT"
32553
32553
  ],
32554
- dynamoDBHistory: emailConfig?.eventTracking?.dynamoDBHistory ?? false,
32555
- archiveRetention: emailConfig?.eventTracking?.archiveRetention ?? "90days"
32554
+ dynamoDBHistory: emailConfig2?.eventTracking?.dynamoDBHistory ?? false,
32555
+ archiveRetention: emailConfig2?.eventTracking?.archiveRetention ?? "90days"
32556
32556
  }
32557
32557
  };
32558
32558
  needsDeployment = true;
@@ -32661,6 +32661,7 @@ Run ${pc43.cyan("wraps email init")} or ${pc43.cyan("wraps sms init")} first.
32661
32661
  }
32662
32662
  const roleName = "wraps-console-access-role";
32663
32663
  const iam11 = new IAMClient3({ region: "us-east-1" });
32664
+ const trustedAccountId = metadata.services?.selfhost ? metadata.accountId : WRAPS_PLATFORM_ACCOUNT_ID;
32664
32665
  let roleExists2 = false;
32665
32666
  try {
32666
32667
  await iam11.send(new GetRoleCommand({ RoleName: roleName }));
@@ -32671,20 +32672,66 @@ Run ${pc43.cyan("wraps email init")} or ${pc43.cyan("wraps sms init")} first.
32671
32672
  throw error;
32672
32673
  }
32673
32674
  }
32675
+ const emailConfig = metadata.services.email?.config;
32676
+ const smsConfig = metadata.services.sms?.config;
32677
+ const consolePolicy = buildConsolePolicyDocument(emailConfig, smsConfig);
32674
32678
  if (roleExists2) {
32675
- const emailConfig = metadata.services.email?.config;
32676
- const smsConfig = metadata.services.sms?.config;
32677
- const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
32678
32679
  await progress.execute("Updating platform access role", async () => {
32679
32680
  await iam11.send(
32680
32681
  new PutRolePolicyCommand({
32681
32682
  RoleName: roleName,
32682
32683
  PolicyName: "wraps-console-access-policy",
32683
- PolicyDocument: JSON.stringify(policy, null, 2)
32684
+ PolicyDocument: JSON.stringify(consolePolicy, null, 2)
32684
32685
  })
32685
32686
  );
32687
+ if (metadata.services?.selfhost) {
32688
+ const trustPolicy = {
32689
+ Version: "2012-10-17",
32690
+ Statement: [
32691
+ {
32692
+ Effect: "Allow",
32693
+ Principal: { AWS: `arn:aws:iam::${trustedAccountId}:root` },
32694
+ Action: "sts:AssumeRole"
32695
+ }
32696
+ ]
32697
+ };
32698
+ await iam11.send(
32699
+ new UpdateAssumeRolePolicyCommand({
32700
+ RoleName: roleName,
32701
+ PolicyDocument: JSON.stringify(trustPolicy)
32702
+ })
32703
+ );
32704
+ }
32686
32705
  });
32687
32706
  progress.succeed("Platform access role updated");
32707
+ } else if (metadata.services?.selfhost) {
32708
+ const trustPolicy = {
32709
+ Version: "2012-10-17",
32710
+ Statement: [
32711
+ {
32712
+ Effect: "Allow",
32713
+ Principal: { AWS: `arn:aws:iam::${trustedAccountId}:root` },
32714
+ Action: "sts:AssumeRole"
32715
+ }
32716
+ ]
32717
+ };
32718
+ await progress.execute("Creating platform access role", async () => {
32719
+ await iam11.send(
32720
+ new CreateRoleCommand({
32721
+ RoleName: roleName,
32722
+ AssumeRolePolicyDocument: JSON.stringify(trustPolicy),
32723
+ Description: "Wraps Platform console access role"
32724
+ })
32725
+ );
32726
+ await iam11.send(
32727
+ new PutRolePolicyCommand({
32728
+ RoleName: roleName,
32729
+ PolicyName: "wraps-console-access-policy",
32730
+ PolicyDocument: JSON.stringify(consolePolicy, null, 2)
32731
+ })
32732
+ );
32733
+ });
32734
+ progress.succeed("Platform access role created");
32688
32735
  } else {
32689
32736
  progress.info(
32690
32737
  `IAM role ${pc43.cyan(roleName)} will be created when you add your AWS account in the dashboard`
@@ -33559,28 +33606,64 @@ async function selfhostDeploy(options) {
33559
33606
  let neonOrgId;
33560
33607
  if (!resolvedDatabaseUrl) {
33561
33608
  neonApiKey = options.neonApiKey;
33609
+ neonOrgId = options.neonOrgId;
33562
33610
  if (!neonApiKey) {
33563
- const neonApiKeyAnswer = await clack43.password({
33564
- message: "Neon API key (create one at console.neon.tech/app/settings/api-keys):"
33611
+ const dbChoice = await clack43.select({
33612
+ message: "How do you want to connect the database?",
33613
+ options: [
33614
+ {
33615
+ value: "url",
33616
+ label: "Enter a connection string",
33617
+ hint: "Neon, Supabase, Railway, self-hosted Postgres..."
33618
+ },
33619
+ {
33620
+ value: "neon",
33621
+ label: "Provision a new Neon database",
33622
+ hint: "Requires a Neon API key"
33623
+ }
33624
+ ]
33565
33625
  });
33566
- if (clack43.isCancel(neonApiKeyAnswer)) {
33626
+ if (clack43.isCancel(dbChoice)) {
33567
33627
  clack43.cancel("Operation cancelled.");
33568
33628
  process.exit(0);
33569
33629
  }
33570
- neonApiKey = neonApiKeyAnswer;
33571
- }
33572
- neonOrgId = options.neonOrgId;
33573
- if (!neonOrgId) {
33574
- const neonOrgIdAnswer = await clack43.text({
33575
- message: "Neon organization ID (find at console.neon.tech/app/settings \u2014 leave blank for personal account):",
33576
- placeholder: "org-..."
33577
- });
33578
- if (clack43.isCancel(neonOrgIdAnswer)) {
33579
- clack43.cancel("Operation cancelled.");
33580
- process.exit(0);
33630
+ if (dbChoice === "url") {
33631
+ const dbUrlAnswer = await clack43.text({
33632
+ message: "Postgres connection string:",
33633
+ placeholder: "postgres://user:pass@host:5432/dbname",
33634
+ validate: (v) => {
33635
+ if (!v.trim()) return "Connection string cannot be empty";
33636
+ if (!v.startsWith("postgres://") && !v.startsWith("postgresql://"))
33637
+ return "Must be a valid postgres:// or postgresql:// connection string";
33638
+ }
33639
+ });
33640
+ if (clack43.isCancel(dbUrlAnswer)) {
33641
+ clack43.cancel("Operation cancelled.");
33642
+ process.exit(0);
33643
+ }
33644
+ resolvedDatabaseUrl = dbUrlAnswer;
33645
+ } else {
33646
+ const neonApiKeyAnswer = await clack43.password({
33647
+ message: "Neon API key (create one at console.neon.tech/app/settings/api-keys):"
33648
+ });
33649
+ if (clack43.isCancel(neonApiKeyAnswer)) {
33650
+ clack43.cancel("Operation cancelled.");
33651
+ process.exit(0);
33652
+ }
33653
+ neonApiKey = neonApiKeyAnswer;
33654
+ if (!neonOrgId) {
33655
+ const neonOrgIdAnswer = await clack43.text({
33656
+ message: "Neon organization ID (find at console.neon.tech/app/settings \u2014 leave blank for personal account):",
33657
+ placeholder: "org-..."
33658
+ });
33659
+ if (clack43.isCancel(neonOrgIdAnswer)) {
33660
+ clack43.cancel("Operation cancelled.");
33661
+ process.exit(0);
33662
+ }
33663
+ const trimmed = neonOrgIdAnswer.trim();
33664
+ if (trimmed) neonOrgId = trimmed;
33665
+ }
33581
33666
  }
33582
- const trimmed = neonOrgIdAnswer.trim();
33583
- if (trimmed) neonOrgId = trimmed;
33584
33667
  }
33585
33668
  }
33586
33669
  let licenseKey = options.licenseKey;
@@ -33864,6 +33947,16 @@ Run ${pc47.cyan("wraps selfhost deploy")} to deploy the self-hosted control plan
33864
33947
  return;
33865
33948
  }
33866
33949
  const { config: config2, apiUrl } = metadata.services.selfhost;
33950
+ if (!apiUrl) {
33951
+ clack44.log.error("Self-hosted deployment is incomplete \u2014 API URL is not available yet.");
33952
+ console.log(
33953
+ `
33954
+ The deployment may have failed partway through. Re-run ${pc47.cyan("wraps selfhost deploy")} to complete it.
33955
+ `
33956
+ );
33957
+ process.exit(1);
33958
+ return;
33959
+ }
33867
33960
  const env = {
33868
33961
  DATABASE_URL: config2.databaseUrl,
33869
33962
  NEXT_PUBLIC_APP_URL: config2.appUrl,