@wraps.dev/cli 3.5.0 → 3.5.2

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/cli.js CHANGED
@@ -2575,8 +2575,16 @@ var init_client = __esm({
2575
2575
  });
2576
2576
 
2577
2577
  // src/telemetry/events.ts
2578
+ function trackCommandFallback(command6, metadata) {
2579
+ const failing = metadata?.success === false;
2580
+ if (failing ? reportedOutcome === "failure" : reportedOutcome !== "none") {
2581
+ return;
2582
+ }
2583
+ trackCommand(command6, metadata);
2584
+ }
2578
2585
  function trackCommand(command6, metadata) {
2579
2586
  const client2 = getTelemetryClient();
2587
+ reportedOutcome = metadata?.success === false || reportedOutcome === "failure" ? "failure" : "success";
2580
2588
  const sanitized = metadata ? { ...metadata } : {};
2581
2589
  sanitized.domain = void 0;
2582
2590
  sanitized.accountId = void 0;
@@ -2624,11 +2632,13 @@ function trackServiceRemoved(service, metadata) {
2624
2632
  ...metadata
2625
2633
  });
2626
2634
  }
2635
+ var reportedOutcome;
2627
2636
  var init_events = __esm({
2628
2637
  "src/telemetry/events.ts"() {
2629
2638
  "use strict";
2630
2639
  init_esm_shims();
2631
2640
  init_client();
2641
+ reportedOutcome = "none";
2632
2642
  }
2633
2643
  });
2634
2644
 
@@ -2641,6 +2651,7 @@ __export(metadata_exports, {
2641
2651
  applyConfigUpdates: () => applyConfigUpdates,
2642
2652
  buildEmailStackConfig: () => buildEmailStackConfig,
2643
2653
  connectionExists: () => connectionExists,
2654
+ createAdoptedConnectionMetadata: () => createAdoptedConnectionMetadata,
2644
2655
  createConnectionMetadata: () => createConnectionMetadata,
2645
2656
  deleteConnectionMetadata: () => deleteConnectionMetadata,
2646
2657
  findConnectionsForAccount: () => findConnectionsForAccount,
@@ -2875,6 +2886,16 @@ function createConnectionMetadata(accountId, region, provider, emailConfig, pres
2875
2886
  }
2876
2887
  };
2877
2888
  }
2889
+ function createAdoptedConnectionMetadata(accountId, region, provider) {
2890
+ return {
2891
+ version: "1.0.0",
2892
+ accountId,
2893
+ region,
2894
+ provider,
2895
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2896
+ services: {}
2897
+ };
2898
+ }
2878
2899
  function setConfigValue(config2, key, value) {
2879
2900
  config2[key] = value;
2880
2901
  }
@@ -32435,6 +32456,21 @@ var remediations = {
32435
32456
  id: "aws.env-vars-incomplete",
32436
32457
  level: "informational",
32437
32458
  summary: "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must both be set, or neither."
32459
+ }),
32460
+ /**
32461
+ * Resources exist in AWS but this machine has no connection record.
32462
+ * `listConnections()` reads only the local ~/.wraps directory — it never
32463
+ * syncs the S3 state bucket that `loadConnectionMetadata()` falls back to —
32464
+ * so this fires for a CloudFormation-first connection AND for a second
32465
+ * machine. `wraps platform connect` adopts the existing deployment: it
32466
+ * registers the connection, repairs the trust policy and writes the local
32467
+ * record, without deploying anything.
32468
+ */
32469
+ adoptConnection: (region) => ({
32470
+ id: "platform.connect.adopt",
32471
+ level: "auto",
32472
+ command: withRegion("wraps platform connect", region),
32473
+ summary: "Register this account and write a local connection record \u2014 adopts the existing AWS resources without deploying anything."
32438
32474
  })
32439
32475
  };
32440
32476
  function formatRemediation(remediation) {
@@ -37347,6 +37383,15 @@ async function wrapsDoctor(options) {
37347
37383
  })
37348
37384
  );
37349
37385
  findings.push(...email.findings);
37386
+ if (email.totalResources > 0 && emailConnections.length === 0) {
37387
+ findings.push({
37388
+ status: "warn",
37389
+ category: "Email",
37390
+ name: "Wraps resources found in AWS, but no connection record on this machine",
37391
+ details: `Found ${email.totalResources} wraps-* resource(s) in ${region}, with no local deployment record for account ${state2.accountId}. CLI commands that resolve connection metadata will not see this deployment.`,
37392
+ remediation: remediations.adoptConnection(region)
37393
+ });
37394
+ }
37350
37395
  } catch (error) {
37351
37396
  findings.push({
37352
37397
  status: "warn",
@@ -56305,11 +56350,6 @@ ${pc46.dim("Documentation:")}`);
56305
56350
  }
56306
56351
  async function permissions(options) {
56307
56352
  const startTime = Date.now();
56308
- trackCommand("permissions", {
56309
- json: options.json,
56310
- preset: options.preset,
56311
- service: options.service
56312
- });
56313
56353
  const policy = buildPolicy(options.service, options.preset);
56314
56354
  if (isJsonMode()) {
56315
56355
  jsonSuccess("permissions", {
@@ -56332,7 +56372,10 @@ async function permissions(options) {
56332
56372
  }
56333
56373
  trackCommand("permissions", {
56334
56374
  success: true,
56335
- duration_ms: Date.now() - startTime
56375
+ duration_ms: Date.now() - startTime,
56376
+ json: options.json,
56377
+ preset: options.preset,
56378
+ service: options.service
56336
56379
  });
56337
56380
  }
56338
56381
 
@@ -56540,22 +56583,47 @@ async function validateAndLoadMetadata(options, progress) {
56540
56583
  optionRegion: options.region,
56541
56584
  label: "connection"
56542
56585
  });
56543
- const metadata = await loadConnectionMetadata(identity.accountId, region);
56586
+ let metadata = await loadConnectionMetadata(identity.accountId, region);
56587
+ let adopted = false;
56544
56588
  if (!metadata) {
56545
- progress.stop();
56546
- log41.error(
56547
- `No Wraps deployment found for account ${pc47.cyan(identity.accountId)} in region ${pc47.cyan(region)}`
56548
- );
56549
- console.log(
56550
- `
56589
+ if (!isJsonMode()) {
56590
+ progress.stop();
56591
+ log41.warn(
56592
+ `No Wraps deployment found for account ${pc47.cyan(identity.accountId)} in region ${pc47.cyan(region)}`
56593
+ );
56594
+ console.log(
56595
+ `
56596
+ This is expected if infrastructure here was deployed another way \u2014 for example, through the dashboard's CloudFormation flow instead of ${pc47.cyan("wraps email init")}.
56597
+ `
56598
+ );
56599
+ }
56600
+ const shouldAdopt = options.yes === true || isJsonMode() || await confirm21({
56601
+ message: `Register AWS account ${identity.accountId} with Wraps without deploying new infrastructure?`,
56602
+ initialValue: true
56603
+ });
56604
+ if (isCancel29(shouldAdopt) || !shouldAdopt) {
56605
+ if (!isJsonMode()) {
56606
+ log41.error(
56607
+ `No Wraps deployment found for account ${identity.accountId}.`
56608
+ );
56609
+ console.log(
56610
+ `
56551
56611
  Run ${pc47.cyan("wraps email init")} to deploy infrastructure first.
56552
56612
  `
56613
+ );
56614
+ }
56615
+ process.exit(0);
56616
+ }
56617
+ metadata = createAdoptedConnectionMetadata(
56618
+ identity.accountId,
56619
+ region,
56620
+ "other"
56553
56621
  );
56554
- process.exit(1);
56622
+ adopted = true;
56555
56623
  }
56556
56624
  const hasEmail = !!metadata.services.email?.config;
56557
56625
  const hasSms = !!metadata.services.sms?.config;
56558
- if (!(hasEmail || hasSms)) {
56626
+ if (!(adopted || hasEmail || hasSms)) {
56559
56627
  progress.stop();
56560
56628
  log41.error("No services deployed in this region.");
56561
56629
  console.log(
@@ -56565,10 +56633,16 @@ Run ${pc47.cyan("wraps email init")} or ${pc47.cyan("wraps sms init")} first.
56565
56633
  );
56566
56634
  process.exit(1);
56567
56635
  }
56568
- progress.info(
56569
- `Found services: ${[hasEmail && "email", hasSms && "sms"].filter(Boolean).join(", ")}`
56570
- );
56571
- return { identity, region, metadata };
56636
+ if (adopted) {
56637
+ progress.info(
56638
+ "Adopting existing AWS infrastructure \u2014 no new resources will be deployed."
56639
+ );
56640
+ } else {
56641
+ progress.info(
56642
+ `Found services: ${[hasEmail && "email", hasSms && "sms"].filter(Boolean).join(", ")}`
56643
+ );
56644
+ }
56645
+ return { identity, region, metadata, adopted };
56572
56646
  }
56573
56647
  async function deployEventBridge(metadata, region, identity, webhookSecret, progress, selfhostTarget) {
56574
56648
  if (metadata.provider === "vercel" && !metadata.vercel) {
@@ -56641,17 +56715,20 @@ async function updatePlatformRole(metadata, progress, externalId, selfhosted) {
56641
56715
  }
56642
56716
  const emailConfig = metadata.services.email?.config;
56643
56717
  const smsConfig = metadata.services.sms?.config;
56644
- const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
56718
+ const hasPolicySource = Boolean(emailConfig || smsConfig);
56645
56719
  if (roleExists2) {
56646
- await progress.execute("Updating platform access role", async () => {
56647
- await iam13.send(
56648
- new PutRolePolicyCommand({
56649
- RoleName: roleName,
56650
- PolicyName: "wraps-console-access-policy",
56651
- PolicyDocument: JSON.stringify(policy, null, 2)
56652
- })
56653
- );
56654
- });
56720
+ if (hasPolicySource) {
56721
+ const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
56722
+ await progress.execute("Updating platform access role", async () => {
56723
+ await iam13.send(
56724
+ new PutRolePolicyCommand({
56725
+ RoleName: roleName,
56726
+ PolicyName: "wraps-console-access-policy",
56727
+ PolicyDocument: JSON.stringify(policy, null, 2)
56728
+ })
56729
+ );
56730
+ });
56731
+ }
56655
56732
  if (externalId) {
56656
56733
  const trustPolicy = {
56657
56734
  Version: "2012-10-17",
@@ -56710,6 +56787,7 @@ async function updatePlatformRole(metadata, progress, externalId, selfhosted) {
56710
56787
  ]
56711
56788
  })
56712
56789
  );
56790
+ const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
56713
56791
  await iam13.send(
56714
56792
  new PutRolePolicyCommand({
56715
56793
  RoleName: roleName,
@@ -56781,10 +56859,7 @@ async function authenticatedConnect(options, saasToken) {
56781
56859
  }
56782
56860
  const progress = new DeploymentProgress();
56783
56861
  try {
56784
- const { identity, region, metadata } = await validateAndLoadMetadata(
56785
- options,
56786
- progress
56787
- );
56862
+ const { identity, region, metadata, adopted } = await validateAndLoadMetadata(options, progress);
56788
56863
  const selfhostService = metadata.services.selfhost;
56789
56864
  if (selfhosted && selfhostService) {
56790
56865
  await reconcileSelfhostApiUrl(metadata, region);
@@ -56953,7 +57028,7 @@ You can try the manual flow: ${pc47.cyan("wraps auth logout")} then ${pc47.cyan(
56953
57028
  }
56954
57029
  }
56955
57030
  await saveConnectionMetadata(metadata);
56956
- if (hasEmail) {
57031
+ if (hasEmail && !adopted) {
56957
57032
  await deployEventBridge(
56958
57033
  metadata,
56959
57034
  region,
@@ -56987,9 +57062,25 @@ You can try the manual flow: ${pc47.cyan("wraps auth logout")} then ${pc47.cyan(
56987
57062
  region,
56988
57063
  organizationId: org.id,
56989
57064
  connectionId: result.connectionId,
56990
- webhookConnected: true,
56991
- selfhosted
57065
+ webhookConnected: !adopted,
57066
+ selfhosted,
57067
+ adopted
56992
57068
  });
57069
+ } else if (adopted) {
57070
+ outro26(pc47.green("AWS account adopted!"));
57071
+ console.log();
57072
+ console.log(
57073
+ pc47.dim(
57074
+ "Registered this account and repaired the IAM trust policy so the dashboard can reach it."
57075
+ )
57076
+ );
57077
+ console.log(
57078
+ pc47.dim(
57079
+ "No infrastructure was deployed and no event wiring was changed."
57080
+ )
57081
+ );
57082
+ console.log(` Dashboard: ${pc47.cyan(dashboardUrl)}`);
57083
+ console.log();
56993
57084
  } else {
56994
57085
  outro26(
56995
57086
  pc47.green(
@@ -66744,14 +66835,22 @@ function suggestCommand(input, known = TOP_LEVEL_COMMANDS) {
66744
66835
  var UNKNOWN = "unknown";
66745
66836
  var COMMAND_WORD = /^[a-z][a-z0-9-]{0,31}$/;
66746
66837
  var COMMANDS_WITH_DATA_SECOND_POSITIONAL = ["push"];
66747
- function telemetryCommandName(primaryCommand2, subCommand2) {
66838
+ var PAIRS_WITH_DATA_THIRD_POSITIONAL = ["email:check"];
66839
+ function telemetryCommandName(primaryCommand2, subCommand2, thirdPositional) {
66748
66840
  if (!(primaryCommand2 && TOP_LEVEL_COMMANDS.includes(primaryCommand2))) {
66749
66841
  return UNKNOWN;
66750
66842
  }
66751
66843
  if (!subCommand2 || COMMANDS_WITH_DATA_SECOND_POSITIONAL.includes(primaryCommand2)) {
66752
66844
  return primaryCommand2;
66753
66845
  }
66754
- return COMMAND_WORD.test(subCommand2) ? `${primaryCommand2}:${subCommand2}` : `${primaryCommand2}:${UNKNOWN}`;
66846
+ if (!COMMAND_WORD.test(subCommand2)) {
66847
+ return `${primaryCommand2}:${UNKNOWN}`;
66848
+ }
66849
+ const pair = `${primaryCommand2}:${subCommand2}`;
66850
+ if (!(thirdPositional && COMMAND_WORD.test(thirdPositional)) || PAIRS_WITH_DATA_THIRD_POSITIONAL.includes(pair)) {
66851
+ return pair;
66852
+ }
66853
+ return `${pair}:${thirdPositional}`;
66755
66854
  }
66756
66855
 
66757
66856
  // src/cli.ts
@@ -67860,7 +67959,7 @@ async function run() {
67860
67959
  }
67861
67960
  const emailDuration = Date.now() - startTime;
67862
67961
  const emailCommandName = `email:${subCommand}`;
67863
- trackCommand(emailCommandName, {
67962
+ trackCommandFallback(emailCommandName, {
67864
67963
  success: true,
67865
67964
  duration_ms: emailDuration,
67866
67965
  service: "email"
@@ -67884,7 +67983,7 @@ async function run() {
67884
67983
  "Run wraps --help for available commands."
67885
67984
  );
67886
67985
  }
67887
- trackCommand(`license:${subCommand}`, {
67986
+ trackCommandFallback(`license:${subCommand}`, {
67888
67987
  success: true,
67889
67988
  duration_ms: Date.now() - startTime,
67890
67989
  service: "license"
@@ -67958,7 +68057,7 @@ async function run() {
67958
68057
  }
67959
68058
  const selfhostDuration = Date.now() - startTime;
67960
68059
  const selfhostCommandName = `selfhost:${subCommand}`;
67961
- trackCommand(selfhostCommandName, {
68060
+ trackCommandFallback(selfhostCommandName, {
67962
68061
  success: true,
67963
68062
  duration_ms: selfhostDuration,
67964
68063
  service: "selfhost"
@@ -68042,7 +68141,7 @@ async function run() {
68042
68141
  }
68043
68142
  const smsDuration = Date.now() - startTime;
68044
68143
  const smsCommandName = `sms:${subCommand}`;
68045
- trackCommand(smsCommandName, {
68144
+ trackCommandFallback(smsCommandName, {
68046
68145
  success: true,
68047
68146
  duration_ms: smsDuration,
68048
68147
  service: "sms"
@@ -68104,7 +68203,7 @@ async function run() {
68104
68203
  }
68105
68204
  const cdnDuration = Date.now() - startTime;
68106
68205
  const cdnCommandName = `cdn:${subCommand}`;
68107
- trackCommand(cdnCommandName, {
68206
+ trackCommandFallback(cdnCommandName, {
68108
68207
  success: true,
68109
68208
  duration_ms: cdnDuration,
68110
68209
  service: "cdn"
@@ -68127,7 +68226,7 @@ async function run() {
68127
68226
  }
68128
68227
  const workflowDuration = Date.now() - startTime;
68129
68228
  const workflowCommandName = `workflow:${subCommand}`;
68130
- trackCommand(workflowCommandName, {
68229
+ trackCommandFallback(workflowCommandName, {
68131
68230
  success: true,
68132
68231
  duration_ms: workflowDuration,
68133
68232
  service: "workflow"
@@ -68138,7 +68237,7 @@ async function run() {
68138
68237
  if (!subCommand) {
68139
68238
  await platform2();
68140
68239
  const platformDuration2 = Date.now() - startTime;
68141
- trackCommand("platform", {
68240
+ trackCommandFallback("platform", {
68142
68241
  success: true,
68143
68242
  duration_ms: platformDuration2
68144
68243
  });
@@ -68177,7 +68276,7 @@ async function run() {
68177
68276
  }
68178
68277
  const platformDuration = Date.now() - startTime;
68179
68278
  const platformCommandName = `platform:${subCommand}`;
68180
- trackCommand(platformCommandName, {
68279
+ trackCommandFallback(platformCommandName, {
68181
68280
  success: true,
68182
68281
  duration_ms: platformDuration
68183
68282
  });
@@ -68220,7 +68319,7 @@ async function run() {
68220
68319
  }
68221
68320
  const awsDuration = Date.now() - startTime;
68222
68321
  const awsCommandName = `aws:${subCommand}`;
68223
- trackCommand(awsCommandName, {
68322
+ trackCommandFallback(awsCommandName, {
68224
68323
  success: true,
68225
68324
  duration_ms: awsDuration
68226
68325
  });
@@ -68334,15 +68433,23 @@ Run wraps --help for available commands.` : "Run wraps --help for available comm
68334
68433
  }
68335
68434
  }
68336
68435
  const duration = Date.now() - startTime;
68337
- const commandName = telemetryCommandName(primaryCommand, subCommand);
68338
- trackCommand(commandName, {
68436
+ const commandName = telemetryCommandName(
68437
+ primaryCommand,
68438
+ subCommand,
68439
+ sub[2]
68440
+ );
68441
+ trackCommandFallback(commandName, {
68339
68442
  success: true,
68340
68443
  duration_ms: duration
68341
68444
  });
68342
68445
  } catch (error) {
68343
68446
  const duration = Date.now() - startTime;
68344
- const commandName = telemetryCommandName(primaryCommand, subCommand);
68345
- trackCommand(commandName, {
68447
+ const commandName = telemetryCommandName(
68448
+ primaryCommand,
68449
+ subCommand,
68450
+ sub[2]
68451
+ );
68452
+ trackCommandFallback(commandName, {
68346
68453
  success: false,
68347
68454
  duration_ms: duration
68348
68455
  });