neonctl 2.28.0 → 2.29.1

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.
Files changed (135) hide show
  1. package/README.md +71 -71
  2. package/dist/analytics.js +35 -33
  3. package/dist/api.js +34 -34
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +2 -2
  6. package/dist/commands/auth.js +58 -52
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +154 -147
  9. package/dist/commands/bucket.js +124 -118
  10. package/dist/commands/checkout.js +49 -49
  11. package/dist/commands/config.js +212 -88
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +96 -96
  14. package/dist/commands/databases.js +23 -23
  15. package/dist/commands/deploy.js +12 -12
  16. package/dist/commands/dev.js +114 -114
  17. package/dist/commands/env.js +43 -43
  18. package/dist/commands/functions.js +97 -98
  19. package/dist/commands/index.js +26 -26
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +223 -166
  23. package/dist/commands/neon_auth.js +381 -363
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +101 -99
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +21 -21
  29. package/dist/commands/schema_diff.js +23 -23
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +17 -17
  32. package/dist/commands/user.js +5 -5
  33. package/dist/commands/vpc_endpoints.js +50 -50
  34. package/dist/config.js +7 -7
  35. package/dist/config_format.js +5 -5
  36. package/dist/context.js +23 -16
  37. package/dist/current_branch_fast_path.js +6 -6
  38. package/dist/dev/env.js +34 -34
  39. package/dist/dev/functions.js +4 -4
  40. package/dist/dev/inputs.js +6 -6
  41. package/dist/dev/runtime.js +25 -25
  42. package/dist/env.js +14 -14
  43. package/dist/env_file.js +13 -13
  44. package/dist/errors.js +19 -19
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +94 -92
  48. package/dist/log.js +2 -2
  49. package/dist/pkg.js +5 -5
  50. package/dist/psql/cli.js +4 -2
  51. package/dist/psql/command/cmd_cond.js +61 -61
  52. package/dist/psql/command/cmd_connect.js +159 -154
  53. package/dist/psql/command/cmd_copy.js +107 -97
  54. package/dist/psql/command/cmd_describe.js +368 -363
  55. package/dist/psql/command/cmd_format.js +276 -263
  56. package/dist/psql/command/cmd_io.js +269 -263
  57. package/dist/psql/command/cmd_lo.js +74 -66
  58. package/dist/psql/command/cmd_meta.js +148 -148
  59. package/dist/psql/command/cmd_misc.js +17 -17
  60. package/dist/psql/command/cmd_pipeline.js +142 -135
  61. package/dist/psql/command/cmd_restrict.js +25 -25
  62. package/dist/psql/command/cmd_show.js +183 -168
  63. package/dist/psql/command/dispatch.js +26 -26
  64. package/dist/psql/command/shared.js +14 -14
  65. package/dist/psql/complete/filenames.js +16 -16
  66. package/dist/psql/complete/index.js +4 -4
  67. package/dist/psql/complete/matcher.js +33 -32
  68. package/dist/psql/complete/psqlVars.js +173 -173
  69. package/dist/psql/complete/queries.js +5 -3
  70. package/dist/psql/complete/rules.js +900 -863
  71. package/dist/psql/core/common.js +136 -133
  72. package/dist/psql/core/help.js +343 -343
  73. package/dist/psql/core/mainloop.js +160 -153
  74. package/dist/psql/core/prompt.js +126 -123
  75. package/dist/psql/core/settings.js +111 -111
  76. package/dist/psql/core/sqlHelp.js +150 -150
  77. package/dist/psql/core/startup.js +211 -205
  78. package/dist/psql/core/syncVars.js +14 -14
  79. package/dist/psql/core/variables.js +24 -24
  80. package/dist/psql/describe/formatters.js +302 -289
  81. package/dist/psql/describe/processNamePattern.js +28 -28
  82. package/dist/psql/describe/queries.js +656 -651
  83. package/dist/psql/index.js +436 -411
  84. package/dist/psql/io/history.js +36 -36
  85. package/dist/psql/io/input.js +15 -15
  86. package/dist/psql/io/lineEditor/buffer.js +27 -25
  87. package/dist/psql/io/lineEditor/complete.js +15 -15
  88. package/dist/psql/io/lineEditor/filename.js +22 -22
  89. package/dist/psql/io/lineEditor/index.js +65 -62
  90. package/dist/psql/io/lineEditor/keymap.js +325 -318
  91. package/dist/psql/io/lineEditor/vt100.js +60 -60
  92. package/dist/psql/io/pgpass.js +18 -18
  93. package/dist/psql/io/pgservice.js +14 -14
  94. package/dist/psql/io/psqlrc.js +46 -46
  95. package/dist/psql/print/aligned.js +175 -166
  96. package/dist/psql/print/asciidoc.js +51 -51
  97. package/dist/psql/print/crosstab.js +34 -31
  98. package/dist/psql/print/csv.js +25 -22
  99. package/dist/psql/print/html.js +54 -54
  100. package/dist/psql/print/json.js +12 -12
  101. package/dist/psql/print/latex.js +118 -118
  102. package/dist/psql/print/pager.js +28 -26
  103. package/dist/psql/print/troff.js +48 -48
  104. package/dist/psql/print/unaligned.js +15 -14
  105. package/dist/psql/print/units.js +17 -17
  106. package/dist/psql/scanner/slash.js +48 -46
  107. package/dist/psql/scanner/sql.js +88 -84
  108. package/dist/psql/scanner/stringutils.js +21 -17
  109. package/dist/psql/types/index.js +7 -7
  110. package/dist/psql/types/scanner.js +8 -8
  111. package/dist/psql/wire/connection.js +341 -327
  112. package/dist/psql/wire/copy.js +7 -7
  113. package/dist/psql/wire/pipeline.js +26 -24
  114. package/dist/psql/wire/protocol.js +102 -102
  115. package/dist/psql/wire/sasl.js +62 -62
  116. package/dist/psql/wire/tls.js +79 -73
  117. package/dist/storage_api.js +15 -15
  118. package/dist/test_utils/fixtures.js +34 -31
  119. package/dist/test_utils/oauth_server.js +5 -5
  120. package/dist/utils/api_enums.js +13 -13
  121. package/dist/utils/branch_notice.js +5 -5
  122. package/dist/utils/branch_picker.js +26 -26
  123. package/dist/utils/compute_units.js +4 -4
  124. package/dist/utils/enrichers.js +20 -15
  125. package/dist/utils/esbuild.js +28 -28
  126. package/dist/utils/formats.js +1 -1
  127. package/dist/utils/middlewares.js +3 -3
  128. package/dist/utils/package_manager.js +68 -0
  129. package/dist/utils/point_in_time.js +12 -12
  130. package/dist/utils/psql.js +30 -30
  131. package/dist/utils/string.js +2 -2
  132. package/dist/utils/ui.js +9 -9
  133. package/dist/utils/zip.js +1 -1
  134. package/dist/writer.js +17 -17
  135. package/package.json +6 -7
@@ -1,154 +1,154 @@
1
- import { NeonAuthSupportedAuthProvider, NeonAuthOauthProviderId, NeonAuthOauthProviderType, NeonAuthEmailVerificationMethod, } from '../utils/api_enums.js';
2
- import chalk from 'chalk';
3
- import { codeFromBody, isNeonApiError, retryOnLock } from '../api.js';
4
- import { branchIdFromProps, fillSingleProject } from '../utils/enrichers.js';
5
- import { writer } from '../writer.js';
1
+ import chalk from "chalk";
2
+ import { codeFromBody, isNeonApiError, retryOnLock } from "../api.js";
3
+ import { NeonAuthEmailVerificationMethod, NeonAuthOauthProviderId, NeonAuthOauthProviderType, NeonAuthSupportedAuthProvider, } from "../utils/api_enums.js";
4
+ import { branchIdFromProps, fillSingleProject } from "../utils/enrichers.js";
5
+ import { writer } from "../writer.js";
6
6
  // Shared styled output helpers
7
7
  const printKvBlock = (title, entries) => {
8
8
  process.stdout.write(`\n${chalk.green(title)}\n`);
9
9
  for (const [key, value] of entries) {
10
- process.stdout.write(` ${chalk.green(key)} ${value ?? ''}\n`);
10
+ process.stdout.write(` ${chalk.green(key)} ${value ?? ""}\n`);
11
11
  }
12
- process.stdout.write('\n');
12
+ process.stdout.write("\n");
13
13
  };
14
14
  const printMessage = (message) => {
15
15
  process.stdout.write(`\n${chalk.green(message)}\n\n`);
16
16
  };
17
17
  const INTEGRATION_RESPONSE_FIELDS = [
18
- 'auth_provider',
19
- 'db_name',
20
- 'base_url',
21
- 'schema_name',
22
- 'table_name',
23
- 'jwks_url',
18
+ "auth_provider",
19
+ "db_name",
20
+ "base_url",
21
+ "schema_name",
22
+ "table_name",
23
+ "jwks_url",
24
24
  ];
25
25
  const INTEGRATION_STATUS_FIELDS = [
26
- 'auth_provider',
27
- 'branch_id',
28
- 'db_name',
29
- 'base_url',
30
- 'created_at',
31
- 'jwks_url',
26
+ "auth_provider",
27
+ "branch_id",
28
+ "db_name",
29
+ "base_url",
30
+ "created_at",
31
+ "jwks_url",
32
32
  ];
33
- const OAUTH_PROVIDER_FIELDS = ['id', 'type', 'client_id'];
34
- const ALLOW_LOCALHOST_FIELDS = ['allow_localhost'];
33
+ const OAUTH_PROVIDER_FIELDS = ["id", "type", "client_id"];
34
+ const ALLOW_LOCALHOST_FIELDS = ["allow_localhost"];
35
35
  const SUPPORTED_OAUTH_PROVIDERS = [
36
36
  NeonAuthOauthProviderId.Google,
37
37
  NeonAuthOauthProviderId.Github,
38
38
  NeonAuthOauthProviderId.Vercel,
39
39
  ];
40
- const DOMAIN_FIELDS = ['domain'];
40
+ const DOMAIN_FIELDS = ["domain"];
41
41
  const EMAIL_PASSWORD_FIELDS = [
42
- 'enabled',
43
- 'email_verification_method',
44
- 'require_email_verification',
45
- 'auto_sign_in_after_verification',
46
- 'send_verification_email_on_sign_up',
47
- 'send_verification_email_on_sign_in',
48
- 'disable_sign_up',
42
+ "enabled",
43
+ "email_verification_method",
44
+ "require_email_verification",
45
+ "auto_sign_in_after_verification",
46
+ "send_verification_email_on_sign_up",
47
+ "send_verification_email_on_sign_in",
48
+ "disable_sign_up",
49
49
  ];
50
50
  const EMAIL_PROVIDER_FIELDS = [
51
- 'type',
52
- 'host',
53
- 'port',
54
- 'username',
55
- 'sender_email',
56
- 'sender_name',
51
+ "type",
52
+ "host",
53
+ "port",
54
+ "username",
55
+ "sender_email",
56
+ "sender_name",
57
57
  ];
58
58
  const ORGANIZATION_FIELDS = [
59
- 'enabled',
60
- 'organization_limit',
61
- 'creator_role',
59
+ "enabled",
60
+ "organization_limit",
61
+ "creator_role",
62
62
  ];
63
63
  const WEBHOOK_FIELDS = [
64
- 'enabled',
65
- 'webhook_url',
66
- 'enabled_events',
67
- 'timeout_seconds',
64
+ "enabled",
65
+ "webhook_url",
66
+ "enabled_events",
67
+ "timeout_seconds",
68
68
  ];
69
- const TEST_EMAIL_FIELDS = ['success', 'error_message'];
70
- export const command = 'neon-auth';
71
- export const describe = 'Manage Neon Auth';
69
+ const TEST_EMAIL_FIELDS = ["success", "error_message"];
70
+ export const command = "neon-auth";
71
+ export const describe = "Manage Neon Auth";
72
72
  export const builder = (argv) => {
73
73
  return argv
74
- .usage('$0 neon-auth <sub-command> [options]')
74
+ .usage("$0 neon-auth <sub-command> [options]")
75
75
  .options({
76
- 'project-id': {
77
- describe: 'Project ID',
78
- type: 'string',
76
+ "project-id": {
77
+ describe: "Project ID",
78
+ type: "string",
79
79
  },
80
80
  branch: {
81
- describe: 'Branch ID or name',
82
- type: 'string',
81
+ describe: "Branch ID or name",
82
+ type: "string",
83
83
  },
84
84
  })
85
85
  .middleware(fillSingleProject)
86
- .command('enable', 'Enable Neon Auth on a branch', (yargs) => yargs.options({
87
- 'database-name': {
88
- describe: 'Database name to use for auth data',
89
- type: 'string',
86
+ .command("enable", "Enable Neon Auth on a branch", (yargs) => yargs.options({
87
+ "database-name": {
88
+ describe: "Database name to use for auth data",
89
+ type: "string",
90
90
  },
91
91
  }), async (args) => {
92
92
  await enable(args);
93
93
  })
94
- .command('status', 'Get Neon Auth status for a branch', (yargs) => yargs, async (args) => {
94
+ .command("status", "Get Neon Auth status for a branch", (yargs) => yargs, async (args) => {
95
95
  await status(args);
96
96
  })
97
- .command('disable', 'Disable Neon Auth on a branch', (yargs) => yargs.options({
98
- 'delete-data': {
99
- describe: 'Permanently delete all Neon Auth data and schema from the database',
100
- type: 'boolean',
97
+ .command("disable", "Disable Neon Auth on a branch", (yargs) => yargs.options({
98
+ "delete-data": {
99
+ describe: "Permanently delete all Neon Auth data and schema from the database",
100
+ type: "boolean",
101
101
  default: false,
102
102
  },
103
103
  }), async (args) => {
104
104
  await disable(args);
105
105
  })
106
- .command('oauth-provider', 'Manage OAuth providers', (yargs) => {
106
+ .command("oauth-provider", "Manage OAuth providers", (yargs) => {
107
107
  return yargs
108
- .usage('$0 neon-auth oauth-provider <sub-command> [options]')
109
- .command('list', 'List OAuth providers', (yargs) => yargs, async (args) => {
108
+ .usage("$0 neon-auth oauth-provider <sub-command> [options]")
109
+ .command("list", "List OAuth providers", (yargs) => yargs, async (args) => {
110
110
  await oauthProviderList(args);
111
111
  })
112
- .command('add', 'Add an OAuth provider', (yargs) => yargs.options({
113
- 'provider-id': {
114
- describe: `OAuth provider ID. Supported values: ${SUPPORTED_OAUTH_PROVIDERS.join(', ')}`,
115
- type: 'string',
112
+ .command("add", "Add an OAuth provider", (yargs) => yargs.options({
113
+ "provider-id": {
114
+ describe: `OAuth provider ID. Supported values: ${SUPPORTED_OAUTH_PROVIDERS.join(", ")}`,
115
+ type: "string",
116
116
  choices: SUPPORTED_OAUTH_PROVIDERS,
117
117
  demandOption: true,
118
118
  },
119
- 'oauth-client-id': {
119
+ "oauth-client-id": {
120
120
  describe: "OAuth client ID from your provider app. Omit to use Neon's shared OAuth app.",
121
- type: 'string',
121
+ type: "string",
122
122
  },
123
- 'oauth-client-secret': {
123
+ "oauth-client-secret": {
124
124
  describe: "OAuth client secret from your provider app. Omit to use Neon's shared OAuth app.",
125
- type: 'string',
125
+ type: "string",
126
126
  },
127
127
  }), async (args) => {
128
128
  await oauthProviderAdd(args);
129
129
  })
130
- .command('update', 'Update an OAuth provider', (yargs) => yargs.options({
131
- 'provider-id': {
132
- describe: `OAuth provider ID. Supported values: ${SUPPORTED_OAUTH_PROVIDERS.join(', ')}`,
133
- type: 'string',
130
+ .command("update", "Update an OAuth provider", (yargs) => yargs.options({
131
+ "provider-id": {
132
+ describe: `OAuth provider ID. Supported values: ${SUPPORTED_OAUTH_PROVIDERS.join(", ")}`,
133
+ type: "string",
134
134
  choices: SUPPORTED_OAUTH_PROVIDERS,
135
135
  demandOption: true,
136
136
  },
137
- 'oauth-client-id': {
137
+ "oauth-client-id": {
138
138
  describe: "OAuth client ID from your provider app. Omit to use Neon's shared OAuth app.",
139
- type: 'string',
139
+ type: "string",
140
140
  },
141
- 'oauth-client-secret': {
141
+ "oauth-client-secret": {
142
142
  describe: "OAuth client secret from your provider app. Omit to use Neon's shared OAuth app.",
143
- type: 'string',
143
+ type: "string",
144
144
  },
145
145
  }), async (args) => {
146
146
  await oauthProviderUpdate(args);
147
147
  })
148
- .command('delete', 'Delete an OAuth provider', (yargs) => yargs.options({
149
- 'provider-id': {
150
- describe: `OAuth provider ID. Supported values: ${SUPPORTED_OAUTH_PROVIDERS.join(', ')}`,
151
- type: 'string',
148
+ .command("delete", "Delete an OAuth provider", (yargs) => yargs.options({
149
+ "provider-id": {
150
+ describe: `OAuth provider ID. Supported values: ${SUPPORTED_OAUTH_PROVIDERS.join(", ")}`,
151
+ type: "string",
152
152
  choices: SUPPORTED_OAUTH_PROVIDERS,
153
153
  demandOption: true,
154
154
  },
@@ -156,277 +156,283 @@ export const builder = (argv) => {
156
156
  await oauthProviderDelete(args);
157
157
  });
158
158
  })
159
- .command('domain', 'Manage redirect URI trusted domains', (yargs) => {
159
+ .command("domain", "Manage redirect URI trusted domains", (yargs) => {
160
160
  return yargs
161
- .usage('$0 neon-auth domain <sub-command> [options]')
162
- .command('list', 'List trusted domains', (yargs) => yargs, async (args) => {
161
+ .usage("$0 neon-auth domain <sub-command> [options]")
162
+ .command("list", "List trusted domains", (yargs) => yargs, async (args) => {
163
163
  await domainList(args);
164
164
  })
165
- .command('add <domain>', 'Add a trusted domain', (yargs) => yargs
166
- .usage('$0 neon-auth domain add <domain> [options]')
167
- .positional('domain', {
168
- describe: 'Domain to add',
169
- type: 'string',
165
+ .command("add <domain>", "Add a trusted domain", (yargs) => yargs
166
+ .usage("$0 neon-auth domain add <domain> [options]")
167
+ .positional("domain", {
168
+ describe: "Domain to add",
169
+ type: "string",
170
170
  demandOption: true,
171
171
  }), async (args) => {
172
172
  await domainAdd(args);
173
173
  })
174
- .command('delete <domain>', 'Delete a trusted domain', (yargs) => yargs
175
- .usage('$0 neon-auth domain delete <domain> [options]')
176
- .positional('domain', {
177
- describe: 'Domain to delete',
178
- type: 'string',
174
+ .command("delete <domain>", "Delete a trusted domain", (yargs) => yargs
175
+ .usage("$0 neon-auth domain delete <domain> [options]")
176
+ .positional("domain", {
177
+ describe: "Domain to delete",
178
+ type: "string",
179
179
  demandOption: true,
180
180
  }), async (args) => {
181
181
  await domainDelete(args);
182
182
  })
183
- .command('allow-localhost', 'Manage localhost connection settings', (yargs) => yargs
184
- .usage('$0 neon-auth domain allow-localhost <sub-command> [options]')
185
- .command('get', 'Get localhost connection setting', (yargs) => yargs, async (args) => {
183
+ .command("allow-localhost", "Manage localhost connection settings", (yargs) => yargs
184
+ .usage("$0 neon-auth domain allow-localhost <sub-command> [options]")
185
+ .command("get", "Get localhost connection setting", (yargs) => yargs, async (args) => {
186
186
  await allowLocalhostGet(args);
187
187
  })
188
- .command('enable', 'Allow localhost connections', (yargs) => yargs, async (args) => {
188
+ .command("enable", "Allow localhost connections", (yargs) => yargs, async (args) => {
189
189
  await allowLocalhostEnable(args);
190
190
  })
191
- .command('disable', 'Restrict localhost connections', (yargs) => yargs, async (args) => {
191
+ .command("disable", "Restrict localhost connections", (yargs) => yargs, async (args) => {
192
192
  await allowLocalhostDisable(args);
193
193
  }));
194
194
  })
195
- .command('config', 'Manage Neon Auth configuration', (yargs) => {
195
+ .command("config", "Manage Neon Auth configuration", (yargs) => {
196
196
  return yargs
197
- .usage('$0 neon-auth config <sub-command> [options]')
198
- .command('email-password', 'Manage email and password authentication settings', (yargs) => {
197
+ .usage("$0 neon-auth config <sub-command> [options]")
198
+ .command("email-password", "Manage email and password authentication settings", (yargs) => {
199
199
  return yargs
200
- .usage('$0 neon-auth config email-password <sub-command> [options]')
201
- .command('get', 'Get email and password config', (yargs) => yargs, async (args) => {
200
+ .usage("$0 neon-auth config email-password <sub-command> [options]")
201
+ .command("get", "Get email and password config", (yargs) => yargs, async (args) => {
202
202
  await emailPasswordGet(args);
203
203
  })
204
- .command('update', 'Update email and password config', (yargs) => yargs.options({
204
+ .command("update", "Update email and password config", (yargs) => yargs.options({
205
205
  enabled: {
206
- describe: 'Enable email and password authentication',
207
- type: 'boolean',
206
+ describe: "Enable email and password authentication",
207
+ type: "boolean",
208
208
  },
209
- 'email-verification-method': {
210
- describe: 'Email verification method',
211
- type: 'string',
209
+ "email-verification-method": {
210
+ describe: "Email verification method",
211
+ type: "string",
212
212
  choices: Object.values(NeonAuthEmailVerificationMethod),
213
213
  },
214
- 'require-email-verification': {
215
- describe: 'Require email verification before users can sign in',
216
- type: 'boolean',
214
+ "require-email-verification": {
215
+ describe: "Require email verification before users can sign in",
216
+ type: "boolean",
217
217
  },
218
- 'auto-sign-in-after-verification': {
219
- describe: 'Auto sign in users after verifying their email',
220
- type: 'boolean',
218
+ "auto-sign-in-after-verification": {
219
+ describe: "Auto sign in users after verifying their email",
220
+ type: "boolean",
221
221
  },
222
- 'send-verification-email-on-sign-up': {
223
- describe: 'Send verification email on sign up',
224
- type: 'boolean',
222
+ "send-verification-email-on-sign-up": {
223
+ describe: "Send verification email on sign up",
224
+ type: "boolean",
225
225
  },
226
- 'send-verification-email-on-sign-in': {
227
- describe: 'Send verification email on sign in',
228
- type: 'boolean',
226
+ "send-verification-email-on-sign-in": {
227
+ describe: "Send verification email on sign in",
228
+ type: "boolean",
229
229
  },
230
- 'disable-sign-up': {
231
- describe: 'Disable new user sign ups',
232
- type: 'boolean',
230
+ "disable-sign-up": {
231
+ describe: "Disable new user sign ups",
232
+ type: "boolean",
233
233
  },
234
234
  }), async (args) => {
235
235
  await emailPasswordUpdate(args);
236
236
  });
237
237
  })
238
- .command('email-provider', 'Manage email provider configuration', (yargs) => {
238
+ .command("email-provider", "Manage email provider configuration", (yargs) => {
239
239
  return yargs
240
- .usage('$0 neon-auth config email-provider <sub-command> [options]')
241
- .command('get', 'Get email provider config', (yargs) => yargs, async (args) => {
240
+ .usage("$0 neon-auth config email-provider <sub-command> [options]")
241
+ .command("get", "Get email provider config", (yargs) => yargs, async (args) => {
242
242
  await emailProviderGet(args);
243
243
  })
244
- .command('update', 'Update email provider config', (yargs) => yargs.options({
244
+ .command("update", "Update email provider config", (yargs) => yargs.options({
245
245
  type: {
246
- describe: 'Email provider type',
247
- type: 'string',
248
- choices: ['standard', 'shared'],
246
+ describe: "Email provider type",
247
+ type: "string",
248
+ choices: [
249
+ "standard",
250
+ "shared",
251
+ ],
249
252
  demandOption: true,
250
253
  },
251
254
  host: {
252
- describe: 'SMTP host (required for standard)',
253
- type: 'string',
255
+ describe: "SMTP host (required for standard)",
256
+ type: "string",
254
257
  },
255
258
  port: {
256
- describe: 'SMTP port (required for standard)',
257
- type: 'number',
259
+ describe: "SMTP port (required for standard)",
260
+ type: "number",
258
261
  },
259
262
  username: {
260
- describe: 'SMTP username (required for standard)',
261
- type: 'string',
263
+ describe: "SMTP username (required for standard)",
264
+ type: "string",
262
265
  },
263
266
  password: {
264
- describe: 'SMTP password (required for standard)',
265
- type: 'string',
267
+ describe: "SMTP password (required for standard)",
268
+ type: "string",
266
269
  },
267
- 'sender-email': {
268
- describe: 'Sender email address',
269
- type: 'string',
270
+ "sender-email": {
271
+ describe: "Sender email address",
272
+ type: "string",
270
273
  },
271
- 'sender-name': {
272
- describe: 'Sender display name',
273
- type: 'string',
274
+ "sender-name": {
275
+ describe: "Sender display name",
276
+ type: "string",
274
277
  },
275
278
  }), async (args) => {
276
279
  await emailProviderUpdate(args);
277
280
  })
278
- .command('test', 'Send a test email', (yargs) => yargs.options({
279
- 'recipient-email': {
280
- describe: 'Email address to send test email to',
281
- type: 'string',
281
+ .command("test", "Send a test email", (yargs) => yargs.options({
282
+ "recipient-email": {
283
+ describe: "Email address to send test email to",
284
+ type: "string",
282
285
  demandOption: true,
283
286
  },
284
287
  host: {
285
- describe: 'SMTP host',
286
- type: 'string',
288
+ describe: "SMTP host",
289
+ type: "string",
287
290
  demandOption: true,
288
291
  },
289
292
  port: {
290
- describe: 'SMTP port',
291
- type: 'number',
293
+ describe: "SMTP port",
294
+ type: "number",
292
295
  demandOption: true,
293
296
  },
294
297
  username: {
295
- describe: 'SMTP username',
296
- type: 'string',
298
+ describe: "SMTP username",
299
+ type: "string",
297
300
  demandOption: true,
298
301
  },
299
302
  password: {
300
- describe: 'SMTP password',
301
- type: 'string',
303
+ describe: "SMTP password",
304
+ type: "string",
302
305
  demandOption: true,
303
306
  },
304
- 'sender-email': {
305
- describe: 'Sender email address',
306
- type: 'string',
307
+ "sender-email": {
308
+ describe: "Sender email address",
309
+ type: "string",
307
310
  demandOption: true,
308
311
  },
309
- 'sender-name': {
310
- describe: 'Sender display name',
311
- type: 'string',
312
+ "sender-name": {
313
+ describe: "Sender display name",
314
+ type: "string",
312
315
  demandOption: true,
313
316
  },
314
317
  }), async (args) => {
315
318
  await emailProviderTest(args);
316
319
  });
317
320
  })
318
- .command('organization', 'Manage organization plugin settings', (yargs) => {
321
+ .command("organization", "Manage organization plugin settings", (yargs) => {
319
322
  return yargs
320
- .usage('$0 neon-auth config organization <sub-command> [options]')
321
- .command('get', 'Get organization plugin config', (yargs) => yargs, async (args) => {
323
+ .usage("$0 neon-auth config organization <sub-command> [options]")
324
+ .command("get", "Get organization plugin config", (yargs) => yargs, async (args) => {
322
325
  await organizationGet(args);
323
326
  })
324
- .command('update', 'Update organization plugin config', (yargs) => yargs.options({
327
+ .command("update", "Update organization plugin config", (yargs) => yargs.options({
325
328
  enabled: {
326
- describe: 'Enable the organization plugin',
327
- type: 'boolean',
329
+ describe: "Enable the organization plugin",
330
+ type: "boolean",
328
331
  },
329
332
  limit: {
330
- describe: 'Maximum number of organizations a user can create',
331
- type: 'number',
333
+ describe: "Maximum number of organizations a user can create",
334
+ type: "number",
332
335
  },
333
- 'creator-role': {
334
- describe: 'Role assigned to organization creator',
335
- type: 'string',
336
- choices: ['admin', 'owner'],
336
+ "creator-role": {
337
+ describe: "Role assigned to organization creator",
338
+ type: "string",
339
+ choices: [
340
+ "admin",
341
+ "owner",
342
+ ],
337
343
  },
338
344
  }), async (args) => {
339
345
  await organizationUpdate(args);
340
346
  });
341
347
  })
342
- .command('webhook', 'Manage webhook configuration', (yargs) => {
348
+ .command("webhook", "Manage webhook configuration", (yargs) => {
343
349
  return yargs
344
- .usage('$0 neon-auth config webhook <sub-command> [options]')
345
- .command('get', 'Get webhook config', (yargs) => yargs, async (args) => {
350
+ .usage("$0 neon-auth config webhook <sub-command> [options]")
351
+ .command("get", "Get webhook config", (yargs) => yargs, async (args) => {
346
352
  await webhookGet(args);
347
353
  })
348
- .command('update', 'Update webhook config', (yargs) => yargs.options({
354
+ .command("update", "Update webhook config", (yargs) => yargs.options({
349
355
  enabled: {
350
- describe: 'Enable webhooks',
351
- type: 'boolean',
356
+ describe: "Enable webhooks",
357
+ type: "boolean",
352
358
  demandOption: true,
353
359
  },
354
360
  url: {
355
- describe: 'Webhook endpoint URL',
356
- type: 'string',
361
+ describe: "Webhook endpoint URL",
362
+ type: "string",
357
363
  },
358
- 'enabled-events': {
359
- describe: 'Events to enable',
360
- type: 'string',
364
+ "enabled-events": {
365
+ describe: "Events to enable",
366
+ type: "string",
361
367
  choices: [
362
- 'user.before_create',
363
- 'user.created',
364
- 'send.otp',
365
- 'send.magic_link',
368
+ "user.before_create",
369
+ "user.created",
370
+ "send.otp",
371
+ "send.magic_link",
366
372
  ],
367
373
  array: true,
368
374
  },
369
375
  timeout: {
370
- describe: 'Webhook timeout in seconds (1-10)',
371
- type: 'number',
376
+ describe: "Webhook timeout in seconds (1-10)",
377
+ type: "number",
372
378
  },
373
379
  }), async (args) => {
374
380
  await webhookUpdate(args);
375
381
  });
376
382
  });
377
383
  })
378
- .command('plugins', 'View Neon Auth plugin configurations', (yargs) => {
384
+ .command("plugins", "View Neon Auth plugin configurations", (yargs) => {
379
385
  return yargs
380
- .usage('$0 neon-auth plugins <sub-command> [options]')
381
- .command('list', 'List all plugin configurations', (yargs) => yargs, async (args) => {
386
+ .usage("$0 neon-auth plugins <sub-command> [options]")
387
+ .command("list", "List all plugin configurations", (yargs) => yargs, async (args) => {
382
388
  await pluginsList(args);
383
389
  })
384
- .command('get <plugin-name>', 'Get a specific plugin configuration', (yargs) => yargs
385
- .usage('$0 neon-auth plugins get <plugin-name> [options]')
386
- .positional('plugin-name', {
387
- describe: 'Plugin name (e.g. organization, email_provider, email_and_password, oauth_providers, allow_localhost)',
388
- type: 'string',
390
+ .command("get <plugin-name>", "Get a specific plugin configuration", (yargs) => yargs
391
+ .usage("$0 neon-auth plugins get <plugin-name> [options]")
392
+ .positional("plugin-name", {
393
+ describe: "Plugin name (e.g. organization, email_provider, email_and_password, oauth_providers, allow_localhost)",
394
+ type: "string",
389
395
  demandOption: true,
390
396
  }), async (args) => {
391
397
  await pluginsGet(args);
392
398
  });
393
399
  })
394
- .command('user', 'Manage Neon Auth users', (yargs) => {
400
+ .command("user", "Manage Neon Auth users", (yargs) => {
395
401
  return yargs
396
- .usage('$0 neon-auth user <sub-command> [options]')
397
- .command('create', 'Create an auth user', (yargs) => yargs.options({
402
+ .usage("$0 neon-auth user <sub-command> [options]")
403
+ .command("create", "Create an auth user", (yargs) => yargs.options({
398
404
  email: {
399
- describe: 'User email address',
400
- type: 'string',
405
+ describe: "User email address",
406
+ type: "string",
401
407
  demandOption: true,
402
408
  },
403
409
  name: {
404
- describe: 'User display name (defaults to email if not provided)',
405
- type: 'string',
410
+ describe: "User display name (defaults to email if not provided)",
411
+ type: "string",
406
412
  },
407
413
  }), async (args) => {
408
414
  await userCreate(args);
409
415
  })
410
- .command('delete <user-id>', 'Delete an auth user', (yargs) => yargs
411
- .usage('$0 neon-auth user delete <user-id> [options]')
412
- .positional('user-id', {
413
- describe: 'ID of the user to delete',
414
- type: 'string',
416
+ .command("delete <user-id>", "Delete an auth user", (yargs) => yargs
417
+ .usage("$0 neon-auth user delete <user-id> [options]")
418
+ .positional("user-id", {
419
+ describe: "ID of the user to delete",
420
+ type: "string",
415
421
  demandOption: true,
416
422
  }), async (args) => {
417
423
  await userDelete(args);
418
424
  })
419
- .command('set-role <user-id>', 'Set roles for an auth user', (yargs) => yargs
420
- .usage('$0 neon-auth user set-role <user-id> [options]')
421
- .positional('user-id', {
422
- describe: 'ID of the user to update',
423
- type: 'string',
425
+ .command("set-role <user-id>", "Set roles for an auth user", (yargs) => yargs
426
+ .usage("$0 neon-auth user set-role <user-id> [options]")
427
+ .positional("user-id", {
428
+ describe: "ID of the user to update",
429
+ type: "string",
424
430
  demandOption: true,
425
431
  })
426
432
  .options({
427
433
  roles: {
428
- describe: 'Roles to assign',
429
- type: 'string',
434
+ describe: "Roles to assign",
435
+ type: "string",
430
436
  array: true,
431
437
  demandOption: true,
432
438
  },
@@ -460,27 +466,29 @@ const enable = async (props) => {
460
466
  throw err;
461
467
  }
462
468
  }
463
- if (props.output === 'json' || props.output === 'yaml') {
469
+ if (props.output === "json" || props.output === "yaml") {
464
470
  writer(props).end(data, { fields: INTEGRATION_RESPONSE_FIELDS });
465
471
  return;
466
472
  }
467
473
  // Access type-specific fields loosely — CREATE response has schema/table,
468
474
  // GET response (already-enabled path) has db_name instead.
469
475
  const d = data;
470
- printKvBlock(alreadyEnabled ? 'Neon Auth is already enabled' : 'Neon Auth enabled', [
471
- ['Auth Provider:', data.auth_provider],
472
- ...(d.db_name ? [['Database: ', d.db_name]] : []),
473
- ['Base URL: ', data.base_url],
476
+ printKvBlock(alreadyEnabled ? "Neon Auth is already enabled" : "Neon Auth enabled", [
477
+ ["Auth Provider:", data.auth_provider],
478
+ ...(d.db_name
479
+ ? [["Database: ", d.db_name]]
480
+ : []),
481
+ ["Base URL: ", data.base_url],
474
482
  ...(d.schema_name
475
- ? [['Schema Name: ', d.schema_name]]
483
+ ? [["Schema Name: ", d.schema_name]]
476
484
  : []),
477
485
  ...(d.table_name
478
- ? [['Table Name: ', d.table_name]]
486
+ ? [["Table Name: ", d.table_name]]
479
487
  : []),
480
- ['JWKS URL: ', data.jwks_url],
488
+ ["JWKS URL: ", data.jwks_url],
481
489
  ]);
482
490
  if (data.base_url) {
483
- process.stdout.write(` ${chalk.green('Set this environment variable in your application:')}\n`);
491
+ process.stdout.write(` ${chalk.green("Set this environment variable in your application:")}\n`);
484
492
  process.stdout.write(` NEON_AUTH_BASE_URL=${data.base_url}\n\n`);
485
493
  }
486
494
  };
@@ -492,22 +500,22 @@ const status = async (props) => {
492
500
  }
493
501
  catch (err) {
494
502
  if (isNeonApiError(err) && err.status === 404) {
495
- printMessage('Neon Auth is not configured for this branch');
503
+ printMessage("Neon Auth is not configured for this branch");
496
504
  return;
497
505
  }
498
506
  throw err;
499
507
  }
500
- if (props.output === 'json' || props.output === 'yaml') {
508
+ if (props.output === "json" || props.output === "yaml") {
501
509
  writer(props).end(data, { fields: INTEGRATION_STATUS_FIELDS });
502
510
  return;
503
511
  }
504
- printKvBlock('Neon Auth status', [
505
- ['Auth Provider:', data.auth_provider],
506
- ['Branch ID: ', data.branch_id],
507
- ['Database: ', data.db_name],
508
- ['Base URL: ', data.base_url],
509
- ['Created At: ', data.created_at],
510
- ['JWKS URL: ', data.jwks_url],
512
+ printKvBlock("Neon Auth status", [
513
+ ["Auth Provider:", data.auth_provider],
514
+ ["Branch ID: ", data.branch_id],
515
+ ["Database: ", data.db_name],
516
+ ["Base URL: ", data.base_url],
517
+ ["Created At: ", data.created_at],
518
+ ["JWKS URL: ", data.jwks_url],
511
519
  ]);
512
520
  };
513
521
  const disable = async (props) => {
@@ -515,23 +523,23 @@ const disable = async (props) => {
515
523
  await retryOnLock(() => props.apiClient.disableNeonAuth(props.projectId, branchId, {
516
524
  delete_data: props.deleteData,
517
525
  }));
518
- printMessage('Neon Auth has been disabled');
526
+ printMessage("Neon Auth has been disabled");
519
527
  };
520
528
  // --- OAuth provider ---
521
- const SHARED_PROVIDER_DISCLAIMER = 'Shared keys are created by the Neon team for development only ' +
522
- 'and should not be used for production apps. It helps you get started, ' +
523
- 'but will show Neon branding (logo and name) on the OAuth consent screen.';
529
+ const SHARED_PROVIDER_DISCLAIMER = "Shared keys are created by the Neon team for development only " +
530
+ "and should not be used for production apps. It helps you get started, " +
531
+ "but will show Neon branding (logo and name) on the OAuth consent screen.";
524
532
  const oauthProviderList = async (props) => {
525
533
  const branchId = await resolveBranch(props);
526
534
  const { data } = await props.apiClient.listBranchNeonAuthOauthProviders(props.projectId, branchId);
527
- if (data.providers.length === 0 && props.output === 'table') {
528
- printMessage('No OAuth providers are configured for this branch.');
535
+ if (data.providers.length === 0 && props.output === "table") {
536
+ printMessage("No OAuth providers are configured for this branch.");
529
537
  return;
530
538
  }
531
539
  writer(props).end(data.providers, { fields: OAUTH_PROVIDER_FIELDS });
532
540
  const hasShared = data.providers.some((p) => p.type === NeonAuthOauthProviderType.Shared);
533
- if (hasShared && props.output === 'table') {
534
- process.stdout.write(`\n${chalk.yellow('Caution:')} ${SHARED_PROVIDER_DISCLAIMER}\n\n`);
541
+ if (hasShared && props.output === "table") {
542
+ process.stdout.write(`\n${chalk.yellow("Caution:")} ${SHARED_PROVIDER_DISCLAIMER}\n\n`);
535
543
  }
536
544
  };
537
545
  const oauthProviderAdd = async (props) => {
@@ -546,22 +554,22 @@ const oauthProviderAdd = async (props) => {
546
554
  }
547
555
  catch (err) {
548
556
  if (isNeonApiError(err) &&
549
- codeFromBody(err.data) === 'INVALID_SHARED_OAUTH_PROVIDER') {
557
+ codeFromBody(err.data) === "INVALID_SHARED_OAUTH_PROVIDER") {
550
558
  throw new Error(`The "${props.providerId}" provider requires your own OAuth app credentials.\n` +
551
559
  `Re-run with --oauth-client-id and --oauth-client-secret to provide them.\n` +
552
560
  `Create an OAuth app at your provider and use those credentials.`);
553
561
  }
554
562
  throw err;
555
563
  }
556
- if (props.output === 'json' || props.output === 'yaml') {
564
+ if (props.output === "json" || props.output === "yaml") {
557
565
  writer(props).end(data, { fields: OAUTH_PROVIDER_FIELDS });
558
566
  }
559
567
  else {
560
- printKvBlock('OAuth provider added', [
561
- ['ID: ', data.id],
562
- ['Type: ', data.type],
568
+ printKvBlock("OAuth provider added", [
569
+ ["ID: ", data.id],
570
+ ["Type: ", data.type],
563
571
  ...(data.client_id
564
- ? [['Client ID: ', data.client_id]]
572
+ ? [["Client ID: ", data.client_id]]
565
573
  : []),
566
574
  ]);
567
575
  }
@@ -578,22 +586,22 @@ const oauthProviderUpdate = async (props) => {
578
586
  }
579
587
  catch (err) {
580
588
  if (isNeonApiError(err) &&
581
- codeFromBody(err.data) === 'INVALID_SHARED_OAUTH_PROVIDER') {
589
+ codeFromBody(err.data) === "INVALID_SHARED_OAUTH_PROVIDER") {
582
590
  throw new Error(`The "${props.providerId}" provider requires your own OAuth app credentials.\n` +
583
591
  `Re-run with --oauth-client-id and --oauth-client-secret to provide them.\n` +
584
592
  `Create an OAuth app at your provider and use those credentials.`);
585
593
  }
586
594
  throw err;
587
595
  }
588
- if (props.output === 'json' || props.output === 'yaml') {
596
+ if (props.output === "json" || props.output === "yaml") {
589
597
  writer(props).end(data, { fields: OAUTH_PROVIDER_FIELDS });
590
598
  }
591
599
  else {
592
- printKvBlock('OAuth provider updated', [
593
- ['ID: ', data.id],
594
- ['Type: ', data.type],
600
+ printKvBlock("OAuth provider updated", [
601
+ ["ID: ", data.id],
602
+ ["Type: ", data.type],
595
603
  ...(data.client_id
596
- ? [['Client ID: ', data.client_id]]
604
+ ? [["Client ID: ", data.client_id]]
597
605
  : []),
598
606
  ]);
599
607
  }
@@ -601,23 +609,23 @@ const oauthProviderUpdate = async (props) => {
601
609
  };
602
610
  const CALLBACK_INSTRUCTIONS = {
603
611
  github: {
604
- lead: 'Create an OAuth app in the GitHub Developer Portal and add the following authorization callback URL:',
605
- urlLabel: 'callback/github',
612
+ lead: "Create an OAuth app in the GitHub Developer Portal and add the following authorization callback URL:",
613
+ urlLabel: "callback/github",
606
614
  },
607
615
  vercel: {
608
- lead: 'Create a Vercel App in your Vercel Dashboard and add the following authorization callback URL:',
609
- urlLabel: 'callback/vercel',
616
+ lead: "Create a Vercel App in your Vercel Dashboard and add the following authorization callback URL:",
617
+ urlLabel: "callback/vercel",
610
618
  },
611
619
  google: {
612
- lead: 'Get Google credentials by creating an OAuth client in Google Cloud Console > Credentials, and add the following authorized redirect URL:',
613
- urlLabel: 'callback/google',
620
+ lead: "Get Google credentials by creating an OAuth client in Google Cloud Console > Credentials, and add the following authorized redirect URL:",
621
+ urlLabel: "callback/google",
614
622
  },
615
623
  };
616
624
  const printCallbackInstructions = async (props, branchId, providerId) => {
617
625
  const instructions = CALLBACK_INSTRUCTIONS[providerId];
618
626
  if (!instructions)
619
627
  return;
620
- if (props.output === 'json' || props.output === 'yaml')
628
+ if (props.output === "json" || props.output === "yaml")
621
629
  return;
622
630
  let baseUrl;
623
631
  try {
@@ -629,8 +637,8 @@ const printCallbackInstructions = async (props, branchId, providerId) => {
629
637
  }
630
638
  if (!baseUrl)
631
639
  return;
632
- const callbackUrl = `${baseUrl.replace(/\/$/, '')}/${instructions.urlLabel}`;
633
- printKvBlock(instructions.lead, [['URL: ', callbackUrl]]);
640
+ const callbackUrl = `${baseUrl.replace(/\/$/, "")}/${instructions.urlLabel}`;
641
+ printKvBlock(instructions.lead, [["URL: ", callbackUrl]]);
634
642
  };
635
643
  const oauthProviderDelete = async (props) => {
636
644
  const branchId = await resolveBranch(props);
@@ -641,8 +649,8 @@ const oauthProviderDelete = async (props) => {
641
649
  const domainList = async (props) => {
642
650
  const branchId = await resolveBranch(props);
643
651
  const { data } = await props.apiClient.listBranchNeonAuthTrustedDomains(props.projectId, branchId);
644
- if (data.domains.length === 0 && props.output === 'table') {
645
- printMessage('No trusted domains are configured for this branch.');
652
+ if (data.domains.length === 0 && props.output === "table") {
653
+ printMessage("No trusted domains are configured for this branch.");
646
654
  return;
647
655
  }
648
656
  writer(props).end(data.domains, { fields: DOMAIN_FIELDS });
@@ -655,7 +663,7 @@ const validateDomainUri = (domain) => {
655
663
  catch {
656
664
  throw new Error(`Invalid domain URI "${domain}". Must be a full URI including scheme, e.g. https://${domain}`);
657
665
  }
658
- if (!['http:', 'https:'].includes(url.protocol)) {
666
+ if (!["http:", "https:"].includes(url.protocol)) {
659
667
  throw new Error(`Invalid domain URI "${domain}". Must use http or https scheme, e.g. https://${url.host}`);
660
668
  }
661
669
  };
@@ -685,12 +693,12 @@ const domainDelete = async (props) => {
685
693
  const allowLocalhostGet = async (props) => {
686
694
  const branchId = await resolveBranch(props);
687
695
  const { data } = await props.apiClient.getNeonAuthAllowLocalhost(props.projectId, branchId);
688
- if (props.output === 'json' || props.output === 'yaml') {
696
+ if (props.output === "json" || props.output === "yaml") {
689
697
  writer(props).end(data, { fields: ALLOW_LOCALHOST_FIELDS });
690
698
  return;
691
699
  }
692
- printKvBlock('Localhost connection settings', [
693
- ['Allow localhost:', String(data.allow_localhost)],
700
+ printKvBlock("Localhost connection settings", [
701
+ ["Allow localhost:", String(data.allow_localhost)],
694
702
  ]);
695
703
  };
696
704
  const allowLocalhostEnable = async (props) => {
@@ -698,42 +706,42 @@ const allowLocalhostEnable = async (props) => {
698
706
  await props.apiClient.updateNeonAuthAllowLocalhost(props.projectId, branchId, {
699
707
  allow_localhost: true,
700
708
  });
701
- printMessage('Localhost connections allowed');
709
+ printMessage("Localhost connections allowed");
702
710
  };
703
711
  const allowLocalhostDisable = async (props) => {
704
712
  const branchId = await resolveBranch(props);
705
713
  await props.apiClient.updateNeonAuthAllowLocalhost(props.projectId, branchId, {
706
714
  allow_localhost: false,
707
715
  });
708
- printMessage('Localhost connections restricted');
716
+ printMessage("Localhost connections restricted");
709
717
  };
710
718
  // --- Email and password ---
711
719
  const printEmailPasswordEntries = (data) => [
712
- ['Enabled: ', String(data.enabled)],
713
- ['Verification Method: ', data.email_verification_method],
714
- ['Require Verification: ', String(data.require_email_verification)],
720
+ ["Enabled: ", String(data.enabled)],
721
+ ["Verification Method: ", data.email_verification_method],
722
+ ["Require Verification: ", String(data.require_email_verification)],
715
723
  [
716
- 'Auto Sign In After Verify: ',
724
+ "Auto Sign In After Verify: ",
717
725
  String(data.auto_sign_in_after_verification),
718
726
  ],
719
727
  [
720
- 'Send Email On Sign Up: ',
728
+ "Send Email On Sign Up: ",
721
729
  String(data.send_verification_email_on_sign_up),
722
730
  ],
723
731
  [
724
- 'Send Email On Sign In: ',
732
+ "Send Email On Sign In: ",
725
733
  String(data.send_verification_email_on_sign_in),
726
734
  ],
727
- ['Disable Sign Up: ', String(data.disable_sign_up)],
735
+ ["Disable Sign Up: ", String(data.disable_sign_up)],
728
736
  ];
729
737
  const emailPasswordGet = async (props) => {
730
738
  const branchId = await resolveBranch(props);
731
739
  const { data } = await props.apiClient.getNeonAuthEmailAndPasswordConfig(props.projectId, branchId);
732
- if (props.output === 'json' || props.output === 'yaml') {
740
+ if (props.output === "json" || props.output === "yaml") {
733
741
  writer(props).end(data, { fields: EMAIL_PASSWORD_FIELDS });
734
742
  return;
735
743
  }
736
- printKvBlock('Email & password auth configuration', printEmailPasswordEntries(data));
744
+ printKvBlock("Email & password auth configuration", printEmailPasswordEntries(data));
737
745
  };
738
746
  const emailPasswordUpdate = async (props) => {
739
747
  const branchId = await resolveBranch(props);
@@ -746,45 +754,50 @@ const emailPasswordUpdate = async (props) => {
746
754
  send_verification_email_on_sign_in: props.sendVerificationEmailOnSignIn,
747
755
  disable_sign_up: props.disableSignUp,
748
756
  });
749
- if (props.output === 'json' || props.output === 'yaml') {
757
+ if (props.output === "json" || props.output === "yaml") {
750
758
  writer(props).end(data, { fields: EMAIL_PASSWORD_FIELDS });
751
759
  return;
752
760
  }
753
- printKvBlock('Email & password auth configuration updated', printEmailPasswordEntries(data));
761
+ printKvBlock("Email & password auth configuration updated", printEmailPasswordEntries(data));
754
762
  };
755
763
  // --- Email provider ---
756
764
  const printEmailProviderEntries = (data) => [
757
- ['Type: ', data.type],
758
- ...(data.type === 'standard'
765
+ ["Type: ", data.type],
766
+ ...(data.type === "standard"
759
767
  ? [
760
- ['Host: ', data.host],
761
- ['Port: ', data.port != null ? String(data.port) : undefined],
762
- ['Username: ', data.username],
768
+ ["Host: ", data.host],
769
+ [
770
+ "Port: ",
771
+ data.port != null ? String(data.port) : undefined,
772
+ ],
773
+ ["Username: ", data.username],
763
774
  ]
764
775
  : []),
765
- ['Sender Email: ', data.sender_email],
766
- ['Sender Name: ', data.sender_name],
776
+ ["Sender Email: ", data.sender_email],
777
+ ["Sender Name: ", data.sender_name],
767
778
  ];
768
779
  const emailProviderGet = async (props) => {
769
780
  const branchId = await resolveBranch(props);
770
781
  const { data } = await props.apiClient.getNeonAuthEmailProvider(props.projectId, branchId);
771
- if (props.output === 'json' || props.output === 'yaml') {
772
- writer(props).end(data, { fields: EMAIL_PROVIDER_FIELDS });
782
+ if (props.output === "json" || props.output === "yaml") {
783
+ writer(props).end(data, {
784
+ fields: EMAIL_PROVIDER_FIELDS,
785
+ });
773
786
  return;
774
787
  }
775
- printKvBlock('Email provider configuration', printEmailProviderEntries(data));
788
+ printKvBlock("Email provider configuration", printEmailProviderEntries(data));
776
789
  };
777
790
  const emailProviderUpdate = async (props) => {
778
- if (props.type === 'standard' &&
791
+ if (props.type === "standard" &&
779
792
  (!props.host || !props.port || !props.username || !props.password)) {
780
- throw new Error('--host, --port, --username, and --password are required for standard email provider');
793
+ throw new Error("--host, --port, --username, and --password are required for standard email provider");
781
794
  }
782
- const warnSharedSender = props.type === 'shared' && (props.senderEmail || props.senderName);
795
+ const warnSharedSender = props.type === "shared" && (props.senderEmail || props.senderName);
783
796
  const branchId = await resolveBranch(props);
784
797
  let config;
785
- if (props.type === 'standard') {
798
+ if (props.type === "standard") {
786
799
  config = {
787
- type: 'standard',
800
+ type: "standard",
788
801
  host: props.host,
789
802
  port: props.port,
790
803
  username: props.username,
@@ -795,18 +808,20 @@ const emailProviderUpdate = async (props) => {
795
808
  }
796
809
  else {
797
810
  config = {
798
- type: 'shared',
811
+ type: "shared",
799
812
  };
800
813
  }
801
814
  const { data } = await props.apiClient.updateNeonAuthEmailProvider(props.projectId, branchId, config);
802
- if (props.output === 'json' || props.output === 'yaml') {
803
- writer(props).end(data, { fields: EMAIL_PROVIDER_FIELDS });
815
+ if (props.output === "json" || props.output === "yaml") {
816
+ writer(props).end(data, {
817
+ fields: EMAIL_PROVIDER_FIELDS,
818
+ });
804
819
  }
805
820
  else {
806
- printKvBlock('Email provider configuration updated', printEmailProviderEntries(data));
821
+ printKvBlock("Email provider configuration updated", printEmailProviderEntries(data));
807
822
  }
808
823
  if (warnSharedSender) {
809
- process.stderr.write(`${chalk.yellow('Warning:')} --sender-email and --sender-name are ignored for the shared email provider. ` +
824
+ process.stderr.write(`${chalk.yellow("Warning:")} --sender-email and --sender-name are ignored for the shared email provider. ` +
810
825
  `These values only take effect with --type standard.\n\n`);
811
826
  }
812
827
  };
@@ -821,39 +836,41 @@ const emailProviderTest = async (props) => {
821
836
  sender_email: props.senderEmail,
822
837
  sender_name: props.senderName,
823
838
  });
824
- if (props.output === 'json' || props.output === 'yaml') {
839
+ if (props.output === "json" || props.output === "yaml") {
825
840
  writer(props).end(data, { fields: TEST_EMAIL_FIELDS });
826
841
  }
827
842
  else if (data.success) {
828
- printMessage('Test email sent successfully');
843
+ printMessage("Test email sent successfully");
829
844
  }
830
845
  else {
831
- process.stdout.write(`\n${chalk.red('Test email failed')}\n ${data.error_message ?? 'Unknown error'}\n\n`);
846
+ process.stdout.write(`\n${chalk.red("Test email failed")}\n ${data.error_message ?? "Unknown error"}\n\n`);
832
847
  }
833
848
  };
834
849
  // --- Organization plugin ---
835
850
  const printOrganizationEntries = (data) => [
836
- ['Enabled: ', String(data.enabled)],
837
- ['Org Limit: ', String(data.organization_limit)],
838
- ['Creator Role: ', data.creator_role],
851
+ ["Enabled: ", String(data.enabled)],
852
+ ["Org Limit: ", String(data.organization_limit)],
853
+ ["Creator Role: ", data.creator_role],
839
854
  ];
840
855
  const organizationGet = async (props) => {
841
856
  const branchId = await resolveBranch(props);
842
857
  const { data } = await props.apiClient.getNeonAuthPluginConfigs(props.projectId, branchId);
843
858
  const org = data.organization;
844
859
  if (!org) {
845
- if (props.output === 'json' || props.output === 'yaml') {
846
- writer(props).end({}, { fields: ORGANIZATION_FIELDS });
860
+ if (props.output === "json" || props.output === "yaml") {
861
+ writer(props).end({}, {
862
+ fields: ORGANIZATION_FIELDS,
863
+ });
847
864
  return;
848
865
  }
849
- printMessage('No organization plugin config found.');
866
+ printMessage("No organization plugin config found.");
850
867
  return;
851
868
  }
852
- if (props.output === 'json' || props.output === 'yaml') {
869
+ if (props.output === "json" || props.output === "yaml") {
853
870
  writer(props).end(org, { fields: ORGANIZATION_FIELDS });
854
871
  return;
855
872
  }
856
- printKvBlock('Organization configuration', printOrganizationEntries(org));
873
+ printKvBlock("Organization configuration", printOrganizationEntries(org));
857
874
  };
858
875
  const organizationUpdate = async (props) => {
859
876
  const branchId = await resolveBranch(props);
@@ -862,30 +879,30 @@ const organizationUpdate = async (props) => {
862
879
  organization_limit: props.limit,
863
880
  creator_role: props.creatorRole,
864
881
  });
865
- if (props.output === 'json' || props.output === 'yaml') {
882
+ if (props.output === "json" || props.output === "yaml") {
866
883
  writer(props).end(data, { fields: ORGANIZATION_FIELDS });
867
884
  return;
868
885
  }
869
- printKvBlock('Organization configuration updated', printOrganizationEntries(data));
886
+ printKvBlock("Organization configuration updated", printOrganizationEntries(data));
870
887
  };
871
888
  // --- Webhook ---
872
889
  const printWebhookEntries = (data) => [
873
- ['Enabled: ', String(data.enabled)],
874
- ['URL: ', data.webhook_url ?? ''],
875
- ['Events: ', (data.enabled_events ?? []).join(', ')],
890
+ ["Enabled: ", String(data.enabled)],
891
+ ["URL: ", data.webhook_url ?? ""],
892
+ ["Events: ", (data.enabled_events ?? []).join(", ")],
876
893
  [
877
- 'Timeout (sec): ',
878
- data.timeout_seconds != null ? String(data.timeout_seconds) : '',
894
+ "Timeout (sec): ",
895
+ data.timeout_seconds != null ? String(data.timeout_seconds) : "",
879
896
  ],
880
897
  ];
881
898
  const webhookGet = async (props) => {
882
899
  const branchId = await resolveBranch(props);
883
900
  const { data } = await props.apiClient.getNeonAuthWebhookConfig(props.projectId, branchId);
884
- if (props.output === 'json' || props.output === 'yaml') {
901
+ if (props.output === "json" || props.output === "yaml") {
885
902
  writer(props).end(data, { fields: WEBHOOK_FIELDS });
886
903
  return;
887
904
  }
888
- printKvBlock('Webhook configuration', printWebhookEntries(data));
905
+ printKvBlock("Webhook configuration", printWebhookEntries(data));
889
906
  };
890
907
  const webhookUpdate = async (props) => {
891
908
  const branchId = await resolveBranch(props);
@@ -895,28 +912,28 @@ const webhookUpdate = async (props) => {
895
912
  enabled_events: props.enabledEvents,
896
913
  timeout_seconds: props.timeout,
897
914
  });
898
- if (props.output === 'json' || props.output === 'yaml') {
915
+ if (props.output === "json" || props.output === "yaml") {
899
916
  writer(props).end(data, { fields: WEBHOOK_FIELDS });
900
917
  return;
901
918
  }
902
- printKvBlock('Webhook configuration updated', printWebhookEntries(data));
919
+ printKvBlock("Webhook configuration updated", printWebhookEntries(data));
903
920
  };
904
921
  // --- Plugins ---
905
- const pluginTitle = (name) => name.replace(/_/g, ' ').replace(/^\w/, (c) => c.toUpperCase()) +
906
- ' configuration';
922
+ const pluginTitle = (name) => name.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase()) +
923
+ " configuration";
907
924
  const formatValue = (v) => {
908
925
  if (v == null)
909
- return '';
910
- if (typeof v === 'string')
926
+ return "";
927
+ if (typeof v === "string")
911
928
  return v;
912
- if (typeof v === 'number' || typeof v === 'boolean')
929
+ if (typeof v === "number" || typeof v === "boolean")
913
930
  return String(v);
914
931
  return JSON.stringify(v);
915
932
  };
916
933
  const pluginsList = async (props) => {
917
934
  const branchId = await resolveBranch(props);
918
935
  const { data } = await props.apiClient.getNeonAuthPluginConfigs(props.projectId, branchId);
919
- if (props.output === 'json' || props.output === 'yaml') {
936
+ if (props.output === "json" || props.output === "yaml") {
920
937
  writer(props).end(data, {
921
938
  fields: Object.keys(data),
922
939
  });
@@ -924,59 +941,60 @@ const pluginsList = async (props) => {
924
941
  }
925
942
  const summarize = (value) => {
926
943
  if (value == null)
927
- return 'not configured';
928
- if (typeof value === 'boolean')
944
+ return "not configured";
945
+ if (typeof value === "boolean")
929
946
  return String(value);
930
- if (typeof value === 'string')
947
+ if (typeof value === "string")
931
948
  return value;
932
- if (typeof value === 'number')
949
+ if (typeof value === "number")
933
950
  return String(value);
934
951
  if (Array.isArray(value))
935
- return value.length === 1 ? '1 item' : `${String(value.length)} items`;
936
- if (typeof value === 'object') {
952
+ return value.length === 1
953
+ ? "1 item"
954
+ : `${String(value.length)} items`;
955
+ if (typeof value === "object") {
937
956
  const obj = value;
938
- if ('enabled' in obj)
939
- return obj.enabled ? 'enabled' : 'disabled';
940
- if ('type' in obj)
957
+ if ("enabled" in obj)
958
+ return obj.enabled ? "enabled" : "disabled";
959
+ if ("type" in obj)
941
960
  return formatValue(obj.type);
942
961
  }
943
962
  return JSON.stringify(value);
944
963
  };
945
964
  const entries = Object.entries(data).map(([key, value]) => [key.padEnd(24), summarize(value)]);
946
- printKvBlock('Neon Auth plugins', entries);
965
+ printKvBlock("Neon Auth plugins", entries);
947
966
  };
948
967
  const pluginsGet = async (props) => {
949
968
  const branchId = await resolveBranch(props);
950
969
  const { data } = await props.apiClient.getNeonAuthPluginConfigs(props.projectId, branchId);
951
970
  const plugin = data[props.pluginName];
952
971
  if (plugin === undefined) {
953
- const available = Object.keys(data).join(', ');
972
+ const available = Object.keys(data).join(", ");
954
973
  throw new Error(`Unknown plugin "${props.pluginName}". Available plugins: ${available}`);
955
974
  }
956
- if (props.output === 'json' || props.output === 'yaml') {
957
- const fields = typeof plugin === 'object' && !Array.isArray(plugin)
975
+ if (props.output === "json" || props.output === "yaml") {
976
+ const fields = typeof plugin === "object" && !Array.isArray(plugin)
958
977
  ? Object.keys(plugin)
959
978
  : [];
960
979
  writer(props).end(plugin, { fields: fields });
961
980
  return;
962
981
  }
963
- if (typeof plugin === 'object' && !Array.isArray(plugin) && plugin != null) {
964
- const entries = Object.entries(plugin).map(([k, v]) => [
965
- `${k}:`.padEnd(18),
966
- formatValue(v),
967
- ]);
982
+ if (typeof plugin === "object" &&
983
+ !Array.isArray(plugin) &&
984
+ plugin != null) {
985
+ const entries = Object.entries(plugin).map(([k, v]) => [`${k}:`.padEnd(18), formatValue(v)]);
968
986
  printKvBlock(pluginTitle(props.pluginName), entries);
969
987
  }
970
988
  else if (Array.isArray(plugin)) {
971
989
  const entries = plugin.map((item, i) => [
972
990
  `[${i}]:`.padEnd(18),
973
- typeof item === 'object' ? JSON.stringify(item) : String(item),
991
+ typeof item === "object" ? JSON.stringify(item) : String(item),
974
992
  ]);
975
993
  printKvBlock(pluginTitle(props.pluginName), entries);
976
994
  }
977
995
  else {
978
996
  printKvBlock(pluginTitle(props.pluginName), [
979
- ['Value:'.padEnd(18), String(plugin)],
997
+ ["Value:".padEnd(18), String(plugin)],
980
998
  ]);
981
999
  }
982
1000
  };
@@ -989,10 +1007,10 @@ const userCreate = async (props) => {
989
1007
  };
990
1008
  const { data } = await props.apiClient.createBranchNeonAuthNewUser(props.projectId, branchId, requestBody);
991
1009
  const displayName = requestBody.name !== props.email ? requestBody.name : undefined;
992
- printKvBlock('User created', [
993
- ['ID: ', data.id],
994
- ['Email: ', requestBody.email],
995
- ...(displayName ? [['Name: ', displayName]] : []),
1010
+ printKvBlock("User created", [
1011
+ ["ID: ", data.id],
1012
+ ["Email: ", requestBody.email],
1013
+ ...(displayName ? [["Name: ", displayName]] : []),
996
1014
  ]);
997
1015
  };
998
1016
  const userDelete = async (props) => {
@@ -1003,8 +1021,8 @@ const userDelete = async (props) => {
1003
1021
  const userSetRole = async (props) => {
1004
1022
  const branchId = await resolveBranch(props);
1005
1023
  const { data } = await props.apiClient.updateNeonAuthUserRole(props.projectId, branchId, props.userId, { roles: props.roles });
1006
- printKvBlock('Roles updated', [
1007
- ['User ID: ', data.id],
1008
- ['Roles: ', props.roles.join(', ')],
1024
+ printKvBlock("Roles updated", [
1025
+ ["User ID: ", data.id],
1026
+ ["Roles: ", props.roles.join(", ")],
1009
1027
  ]);
1010
1028
  };