neon 8.0.2 → 8.0.3

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.
@@ -1,9 +1,10 @@
1
1
  import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
2
2
  import { codeFromBody, isNeonApiError, retryOnLock } from "../api.js";
3
+ import { stripAnsi } from "../human_table.js";
3
4
  import { writer } from "../writer.js";
4
5
  import { noPassthrough, single } from "../utils/flags.js";
5
6
  import { NeonAuthEmailVerificationMethod, NeonAuthOauthProviderId, NeonAuthOauthProviderType, NeonAuthSupportedAuthProvider } from "../utils/api_enums.js";
6
- import { branchIdFromProps, fillSingleProject } from "../utils/enrichers.js";
7
+ import { branchIdFromProps, fillSingleProject, resolveBranchFromProps } from "../utils/enrichers.js";
7
8
  import chalk from "chalk";
8
9
  //#region src/commands/neon_auth.ts
9
10
  var neon_auth_exports = /* @__PURE__ */ __exportAll({
@@ -12,13 +13,20 @@ var neon_auth_exports = /* @__PURE__ */ __exportAll({
12
13
  describe: () => describe,
13
14
  handler: () => handler
14
15
  });
16
+ const writeStyled = (text, stream = process.stdout) => {
17
+ stream.write(process.env.NO_COLOR ? stripAnsi(text) : text);
18
+ };
15
19
  const printKvBlock = (title, entries) => {
16
- process.stdout.write(`\n${chalk.green(title)}\n`);
17
- for (const [key, value] of entries) process.stdout.write(` ${chalk.green(key)} ${value ?? ""}\n`);
18
- process.stdout.write("\n");
20
+ const labels = entries.map(([key]) => key.trimEnd());
21
+ const width = Math.max(0, ...labels.map((label) => label.length));
22
+ let text = `\n${chalk.green(title)}\n`;
23
+ entries.forEach(([, value], i) => {
24
+ text += ` ${chalk.green(labels[i].padEnd(width))} ${value ?? ""}\n`;
25
+ });
26
+ writeStyled(`${text}\n`);
19
27
  };
20
28
  const printMessage = (message) => {
21
- process.stdout.write(`\n${chalk.green(message)}\n\n`);
29
+ writeStyled(`\n${chalk.green(message)}\n\n`);
22
30
  };
23
31
  const INTEGRATION_RESPONSE_FIELDS = [
24
32
  "auth_provider",
@@ -356,6 +364,15 @@ const handler = (args) => {
356
364
  const resolveBranch = async (props) => {
357
365
  return props.branchId ?? await branchIdFromProps(props);
358
366
  };
367
+ /** The branch name is only known when it was resolved from a listing, not from an id. */
368
+ const resolveBranchWithName = async (props) => {
369
+ if (props.branchId) return { branchId: props.branchId };
370
+ const { branchId, branch } = await resolveBranchFromProps(props);
371
+ return {
372
+ branchId,
373
+ branchName: branch?.name
374
+ };
375
+ };
359
376
  const enable = async (props) => {
360
377
  const branchId = await resolveBranch(props);
361
378
  let data;
@@ -378,19 +395,19 @@ const enable = async (props) => {
378
395
  const d = data;
379
396
  printKvBlock(alreadyEnabled ? "Neon Auth is already enabled" : "Neon Auth enabled", [
380
397
  ["Auth Provider:", data.auth_provider],
381
- ...d.db_name ? [["Database: ", d.db_name]] : [],
382
- ["Base URL: ", data.base_url],
383
- ...d.schema_name ? [["Schema Name: ", d.schema_name]] : [],
384
- ...d.table_name ? [["Table Name: ", d.table_name]] : [],
385
- ["JWKS URL: ", data.jwks_url]
398
+ ...d.db_name ? [["Database:", d.db_name]] : [],
399
+ ["Base URL:", data.base_url],
400
+ ...d.schema_name ? [["Schema Name:", d.schema_name]] : [],
401
+ ...d.table_name ? [["Table Name:", d.table_name]] : [],
402
+ ["JWKS URL:", data.jwks_url]
386
403
  ]);
387
404
  if (data.base_url) {
388
- process.stdout.write(` ${chalk.green("Set this environment variable in your application:")}\n`);
389
- process.stdout.write(` NEON_AUTH_BASE_URL=${data.base_url}\n\n`);
405
+ writeStyled(` ${chalk.green("Set this environment variable in your application:")}\n`);
406
+ writeStyled(` NEON_AUTH_BASE_URL=${data.base_url}\n\n`);
390
407
  }
391
408
  };
392
409
  const status = async (props) => {
393
- const branchId = await resolveBranch(props);
410
+ const { branchId, branchName } = await resolveBranchWithName(props);
394
411
  let data;
395
412
  try {
396
413
  ({data} = await props.apiClient.getNeonAuth(props.projectId, branchId));
@@ -407,11 +424,11 @@ const status = async (props) => {
407
424
  }
408
425
  printKvBlock("Neon Auth status", [
409
426
  ["Auth Provider:", data.auth_provider],
410
- ["Branch ID: ", data.branch_id],
411
- ["Database: ", data.db_name],
412
- ["Base URL: ", data.base_url],
413
- ["Created At: ", data.created_at],
414
- ["JWKS URL: ", data.jwks_url]
427
+ ["Branch:", branchName ? `${branchName} (${data.branch_id})` : data.branch_id],
428
+ ["Database:", data.db_name],
429
+ ["Base URL:", data.base_url],
430
+ ["Created At:", data.created_at],
431
+ ["JWKS URL:", data.jwks_url]
415
432
  ]);
416
433
  };
417
434
  const disable = async (props) => {
@@ -428,10 +445,11 @@ const oauthProviderList = async (props) => {
428
445
  return;
429
446
  }
430
447
  writer(props).end(data.providers, { fields: OAUTH_PROVIDER_FIELDS });
431
- if (data.providers.some((p) => p.type === NeonAuthOauthProviderType.Shared) && props.output === "table") process.stdout.write(`\n${chalk.yellow("Caution:")} ${SHARED_PROVIDER_DISCLAIMER}\n\n`);
448
+ if (data.providers.some((p) => p.type === NeonAuthOauthProviderType.Shared) && props.output === "table") writeStyled(`\n${chalk.yellow("Caution:")} ${SHARED_PROVIDER_DISCLAIMER}\n\n`);
432
449
  };
433
450
  const oauthProviderAdd = async (props) => {
434
451
  const branchId = await resolveBranch(props);
452
+ const baseUrlRequest = callbackBaseUrl(props, branchId, props.providerId);
435
453
  let data;
436
454
  try {
437
455
  ({data} = await props.apiClient.addBranchNeonAuthOauthProvider(props.projectId, branchId, {
@@ -445,14 +463,15 @@ const oauthProviderAdd = async (props) => {
445
463
  }
446
464
  if (props.output === "json" || props.output === "yaml") writer(props).end(data, { fields: OAUTH_PROVIDER_FIELDS });
447
465
  else printKvBlock("OAuth provider added", [
448
- ["ID: ", data.id],
449
- ["Type: ", data.type],
450
- ...data.client_id ? [["Client ID: ", data.client_id]] : []
466
+ ["ID:", data.id],
467
+ ["Type:", data.type],
468
+ ...data.client_id ? [["Client ID:", data.client_id]] : []
451
469
  ]);
452
- await printCallbackInstructions(props, branchId, props.providerId);
470
+ printCallbackInstructions(props.providerId, await baseUrlRequest);
453
471
  };
454
472
  const oauthProviderUpdate = async (props) => {
455
473
  const branchId = await resolveBranch(props);
474
+ const baseUrlRequest = callbackBaseUrl(props, branchId, props.providerId);
456
475
  let data;
457
476
  try {
458
477
  ({data} = await props.apiClient.updateBranchNeonAuthOauthProvider(props.projectId, branchId, props.providerId, {
@@ -465,11 +484,11 @@ const oauthProviderUpdate = async (props) => {
465
484
  }
466
485
  if (props.output === "json" || props.output === "yaml") writer(props).end(data, { fields: OAUTH_PROVIDER_FIELDS });
467
486
  else printKvBlock("OAuth provider updated", [
468
- ["ID: ", data.id],
469
- ["Type: ", data.type],
470
- ...data.client_id ? [["Client ID: ", data.client_id]] : []
487
+ ["ID:", data.id],
488
+ ["Type:", data.type],
489
+ ...data.client_id ? [["Client ID:", data.client_id]] : []
471
490
  ]);
472
- await printCallbackInstructions(props, branchId, props.providerId);
491
+ printCallbackInstructions(props.providerId, await baseUrlRequest);
473
492
  };
474
493
  const CALLBACK_INSTRUCTIONS = {
475
494
  github: {
@@ -485,20 +504,21 @@ const CALLBACK_INSTRUCTIONS = {
485
504
  urlLabel: "callback/google"
486
505
  }
487
506
  };
488
- const printCallbackInstructions = async (props, branchId, providerId) => {
507
+ /**
508
+ * Starts the base-URL read for the callback instructions, or resolves to undefined when none
509
+ * apply. It runs alongside the provider write (adding a provider does not change the base URL)
510
+ * and never rejects: a failed read prints no instructions, as before.
511
+ */
512
+ const callbackBaseUrl = (props, branchId, providerId) => {
513
+ if (!CALLBACK_INSTRUCTIONS[providerId]) return Promise.resolve(void 0);
514
+ if (props.output === "json" || props.output === "yaml") return Promise.resolve(void 0);
515
+ return props.apiClient.getNeonAuth(props.projectId, branchId).then(({ data }) => data.base_url, () => void 0);
516
+ };
517
+ const printCallbackInstructions = (providerId, baseUrl) => {
489
518
  const instructions = CALLBACK_INSTRUCTIONS[providerId];
490
- if (!instructions) return;
491
- if (props.output === "json" || props.output === "yaml") return;
492
- let baseUrl;
493
- try {
494
- const { data } = await props.apiClient.getNeonAuth(props.projectId, branchId);
495
- baseUrl = data.base_url;
496
- } catch {
497
- return;
498
- }
499
- if (!baseUrl) return;
519
+ if (!instructions || !baseUrl) return;
500
520
  const callbackUrl = `${baseUrl.replace(/\/$/, "")}/${instructions.urlLabel}`;
501
- printKvBlock(instructions.lead, [["URL: ", callbackUrl]]);
521
+ printKvBlock(instructions.lead, [["URL:", callbackUrl]]);
502
522
  };
503
523
  const oauthProviderDelete = async (props) => {
504
524
  const branchId = await resolveBranch(props);
@@ -563,13 +583,13 @@ const allowLocalhostDisable = async (props) => {
563
583
  printMessage("Localhost connections restricted");
564
584
  };
565
585
  const printEmailPasswordEntries = (data) => [
566
- ["Enabled: ", String(data.enabled)],
567
- ["Verification Method: ", data.email_verification_method],
568
- ["Require Verification: ", String(data.require_email_verification)],
586
+ ["Enabled:", String(data.enabled)],
587
+ ["Verification Method:", data.email_verification_method],
588
+ ["Require Verification:", String(data.require_email_verification)],
569
589
  ["Auto Sign In After Verify: ", String(data.auto_sign_in_after_verification)],
570
590
  ["Send Email On Sign Up: ", String(data.send_verification_email_on_sign_up)],
571
591
  ["Send Email On Sign In: ", String(data.send_verification_email_on_sign_in)],
572
- ["Disable Sign Up: ", String(data.disable_sign_up)]
592
+ ["Disable Sign Up:", String(data.disable_sign_up)]
573
593
  ];
574
594
  const emailPasswordGet = async (props) => {
575
595
  const branchId = await resolveBranch(props);
@@ -598,14 +618,14 @@ const emailPasswordUpdate = async (props) => {
598
618
  printKvBlock("Email & password auth configuration updated", printEmailPasswordEntries(data));
599
619
  };
600
620
  const printEmailProviderEntries = (data) => [
601
- ["Type: ", data.type],
621
+ ["Type:", data.type],
602
622
  ...data.type === "standard" ? [
603
- ["Host: ", data.host],
623
+ ["Host:", data.host],
604
624
  ["Port: ", data.port != null ? String(data.port) : void 0],
605
- ["Username: ", data.username]
625
+ ["Username:", data.username]
606
626
  ] : [],
607
- ["Sender Email: ", data.sender_email],
608
- ["Sender Name: ", data.sender_name]
627
+ ["Sender Email:", data.sender_email],
628
+ ["Sender Name:", data.sender_name]
609
629
  ];
610
630
  const emailProviderGet = async (props) => {
611
631
  const branchId = await resolveBranch(props);
@@ -634,7 +654,7 @@ const emailProviderUpdate = async (props) => {
634
654
  const { data } = await props.apiClient.updateNeonAuthEmailProvider(props.projectId, branchId, config);
635
655
  if (props.output === "json" || props.output === "yaml") writer(props).end(data, { fields: EMAIL_PROVIDER_FIELDS });
636
656
  else printKvBlock("Email provider configuration updated", printEmailProviderEntries(data));
637
- if (warnSharedSender) process.stderr.write(`${chalk.yellow("Warning:")} --sender-email and --sender-name are ignored for the shared email provider. These values only take effect with --type standard.\n\n`);
657
+ if (warnSharedSender) writeStyled(`${chalk.yellow("Warning:")} --sender-email and --sender-name are ignored for the shared email provider. These values only take effect with --type standard.\n\n`, process.stderr);
638
658
  };
639
659
  const emailProviderTest = async (props) => {
640
660
  const branchId = await resolveBranch(props);
@@ -655,9 +675,9 @@ const emailProviderTestFailureMessage = (recipientEmail, errorMessage) => {
655
675
  return errorMessage ? `${header}\nUpstream error: ${errorMessage}` : header;
656
676
  };
657
677
  const printOrganizationEntries = (data) => [
658
- ["Enabled: ", String(data.enabled)],
659
- ["Org Limit: ", String(data.organization_limit)],
660
- ["Creator Role: ", data.creator_role]
678
+ ["Enabled:", String(data.enabled)],
679
+ ["Org Limit:", String(data.organization_limit)],
680
+ ["Creator Role:", data.creator_role]
661
681
  ];
662
682
  const organizationGet = async (props) => {
663
683
  const branchId = await resolveBranch(props);
@@ -691,9 +711,9 @@ const organizationUpdate = async (props) => {
691
711
  printKvBlock("Organization configuration updated", printOrganizationEntries(data));
692
712
  };
693
713
  const printWebhookEntries = (data) => [
694
- ["Enabled: ", String(data.enabled)],
695
- ["URL: ", data.webhook_url ?? ""],
696
- ["Events: ", (data.enabled_events ?? []).join(", ")],
714
+ ["Enabled:", String(data.enabled)],
715
+ ["URL:", data.webhook_url ?? ""],
716
+ ["Events:", (data.enabled_events ?? []).join(", ")],
697
717
  ["Timeout (sec): ", data.timeout_seconds != null ? String(data.timeout_seconds) : ""]
698
718
  ];
699
719
  const webhookGet = async (props) => {
@@ -746,7 +766,7 @@ const pluginsList = async (props) => {
746
766
  }
747
767
  return JSON.stringify(value);
748
768
  };
749
- const entries = Object.entries(data).map(([key, value]) => [key.padEnd(24), summarize(value)]);
769
+ const entries = Object.entries(data).map(([key, value]) => [key, summarize(value)]);
750
770
  printKvBlock("Neon Auth plugins", entries);
751
771
  };
752
772
  const pluginsGet = async (props) => {
@@ -763,12 +783,12 @@ const pluginsGet = async (props) => {
763
783
  return;
764
784
  }
765
785
  if (typeof plugin === "object" && !Array.isArray(plugin) && plugin != null) {
766
- const entries = Object.entries(plugin).map(([k, v]) => [`${k}:`.padEnd(18), formatValue(v)]);
786
+ const entries = Object.entries(plugin).map(([k, v]) => [`${k}:`, formatValue(v)]);
767
787
  printKvBlock(pluginTitle(props.pluginName), entries);
768
788
  } else if (Array.isArray(plugin)) {
769
- const entries = plugin.map((item, i) => [`[${i}]:`.padEnd(18), typeof item === "object" ? JSON.stringify(item) : String(item)]);
789
+ const entries = plugin.map((item, i) => [`[${i}]:`, typeof item === "object" ? JSON.stringify(item) : String(item)]);
770
790
  printKvBlock(pluginTitle(props.pluginName), entries);
771
- } else printKvBlock(pluginTitle(props.pluginName), [["Value:".padEnd(18), String(plugin)]]);
791
+ } else printKvBlock(pluginTitle(props.pluginName), [["Value:", String(plugin)]]);
772
792
  };
773
793
  const userCreate = async (props) => {
774
794
  const branchId = await resolveBranch(props);
@@ -779,9 +799,9 @@ const userCreate = async (props) => {
779
799
  const { data } = await props.apiClient.createBranchNeonAuthNewUser(props.projectId, branchId, requestBody);
780
800
  const displayName = requestBody.name !== props.email ? requestBody.name : void 0;
781
801
  printKvBlock("User created", [
782
- ["ID: ", data.id],
783
- ["Email: ", requestBody.email],
784
- ...displayName ? [["Name: ", displayName]] : []
802
+ ["ID:", data.id],
803
+ ["Email:", requestBody.email],
804
+ ...displayName ? [["Name:", displayName]] : []
785
805
  ]);
786
806
  };
787
807
  const userDelete = async (props) => {
@@ -792,7 +812,7 @@ const userDelete = async (props) => {
792
812
  const userSetRole = async (props) => {
793
813
  const branchId = await resolveBranch(props);
794
814
  const { data } = await props.apiClient.updateNeonAuthUserRole(props.projectId, branchId, props.userId, { roles: props.roles });
795
- printKvBlock("Roles updated", [["User ID: ", data.id], ["Roles: ", props.roles.join(", ")]]);
815
+ printKvBlock("Roles updated", [["User ID:", data.id], ["Roles:", props.roles.join(", ")]]);
796
816
  };
797
817
  //#endregion
798
818
  export { builder, command, describe, handler, neon_auth_exports as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neon",
3
- "version": "8.0.2",
3
+ "version": "8.0.3",
4
4
  "description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
5
5
  "keywords": [
6
6
  "neon",
@@ -64,9 +64,9 @@
64
64
  "yaml": "^2.9.0",
65
65
  "yargs": "17.7.2",
66
66
  "yoctocolors": "^2.1.2",
67
+ "@neon/config": "1.8.3",
67
68
  "@neon/config-runtime": "1.7.3",
68
- "@neon/sdk": "7.0.0",
69
- "@neon/config": "1.8.3"
69
+ "@neon/sdk": "7.0.0"
70
70
  },
71
71
  "optionalDependencies": {
72
72
  "@napi-rs/keyring": "1.3.0",