neonctl 1.28.0 → 1.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 (184) hide show
  1. package/.bump +1 -0
  2. package/.editorconfig +7 -0
  3. package/.eslintrc.cjs +15 -0
  4. package/.github/workflows/commitlint.yml +46 -0
  5. package/.github/workflows/pr.yml +25 -0
  6. package/.github/workflows/release.yml +30 -0
  7. package/.husky/commit-msg +4 -0
  8. package/.husky/pre-commit +4 -0
  9. package/.nvmrc +1 -0
  10. package/.prettierignore +3 -0
  11. package/.prettierrc.json +3 -0
  12. package/.releaserc.json +47 -0
  13. package/LICENSE +202 -0
  14. package/commitlint.config.cjs +7 -0
  15. package/generateOptionsFromSpec.ts +68 -0
  16. package/jest/setup.js +5 -0
  17. package/jest.config.ts +199 -0
  18. package/mocks/bin/psql.cjs +9 -0
  19. package/mocks/main/projects/GET.js +27 -0
  20. package/mocks/main/projects/POST.js +22 -0
  21. package/mocks/main/projects/shared/GET.js +16 -0
  22. package/mocks/main/projects/test/DELETE.json +7 -0
  23. package/mocks/main/projects/test/GET.json +13 -0
  24. package/mocks/main/projects/test/PATCH.js +18 -0
  25. package/mocks/main/projects/test/branches/GET.json +25 -0
  26. package/mocks/main/projects/test/branches/POST.js +83 -0
  27. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/DELETE.json +7 -0
  28. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/GET.json +9 -0
  29. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/PATCH.js +14 -0
  30. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/GET.json +6 -0
  31. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/POST.js +13 -0
  32. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/test_db/DELETE.json +6 -0
  33. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/endpoints/GET.json +26 -0
  34. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/endpoints/POST.json +6 -0
  35. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/GET.json +3 -0
  36. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/POST.js +14 -0
  37. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/test_role/DELETE.json +6 -0
  38. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/test_role/reveal_password/GET.json +3 -0
  39. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/set_as_primary/POST.json +9 -0
  40. package/mocks/main/projects/test/branches/br-numbered-branch-123456/GET.json +10 -0
  41. package/mocks/main/projects/test/branches/br-sunny-branch-123456/DELETE.json +7 -0
  42. package/mocks/main/projects/test/branches/br-sunny-branch-123456/GET.json +10 -0
  43. package/mocks/main/projects/test/branches/br-sunny-branch-123456/PATCH.js +14 -0
  44. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/GET.json +6 -0
  45. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/POST.js +13 -0
  46. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/test_db/DELETE.json +6 -0
  47. package/mocks/main/projects/test/branches/br-sunny-branch-123456/endpoints/GET.json +26 -0
  48. package/mocks/main/projects/test/branches/br-sunny-branch-123456/endpoints/POST.json +6 -0
  49. package/mocks/main/projects/test/branches/br-sunny-branch-123456/restore/POST.js +16 -0
  50. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/GET.json +3 -0
  51. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/POST.js +14 -0
  52. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/test_role/DELETE.json +6 -0
  53. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/test_role/reveal_password/GET.json +3 -0
  54. package/mocks/main/projects/test/branches/br-sunny-branch-123456/set_as_primary/POST.json +9 -0
  55. package/mocks/main/projects/test/endpoints/GET.json +9 -0
  56. package/mocks/main/projects/test/endpoints/POST.js +32 -0
  57. package/mocks/main/projects/test/endpoints/test_endpoint_id/DELETE.json +7 -0
  58. package/mocks/main/projects/test/endpoints/test_endpoint_id/GET.json +9 -0
  59. package/mocks/main/projects/test/endpoints/test_endpoint_id/PATCH.js +17 -0
  60. package/mocks/main/projects/test/operations/GET.json +22 -0
  61. package/mocks/main/users/me/GET.json +5 -0
  62. package/mocks/restore/projects/test/branches/GET.json +21 -0
  63. package/mocks/restore/projects/test/branches/br-another-branch-123456/GET.json +6 -0
  64. package/mocks/restore/projects/test/branches/br-another-branch-123456/restore/POST.js +13 -0
  65. package/mocks/restore/projects/test/branches/br-any-branch-123456/GET.json +6 -0
  66. package/mocks/restore/projects/test/branches/br-parent-tots-123456/GET.json +7 -0
  67. package/mocks/restore/projects/test/branches/br-parent-tots-123456/restore/POST.js +14 -0
  68. package/mocks/restore/projects/test/branches/br-self-tolsn-123456/GET.json +6 -0
  69. package/mocks/restore/projects/test/branches/br-self-tolsn-123456/restore/POST.js +15 -0
  70. package/mocks/single_project/projects/GET.json +10 -0
  71. package/mocks/single_project/projects/test-project-123456/GET.json +14 -0
  72. package/mocks/single_project/projects/test-project-123456/branches/GET.json +11 -0
  73. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/databases/GET.json +3 -0
  74. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/endpoints/GET.json +10 -0
  75. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/roles/GET.json +3 -0
  76. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/roles/test_role/reveal_password/GET.json +3 -0
  77. package/package.json +6 -5
  78. package/pkg.js +45 -3
  79. package/rollup.config.js +20 -0
  80. package/snapshots/commands/branches.test.snap +221 -0
  81. package/snapshots/commands/connection_string.test.snap +70 -0
  82. package/snapshots/commands/databases.test.snap +20 -0
  83. package/snapshots/commands/ip_allow.test.snap +55 -0
  84. package/snapshots/commands/operations.test.snap +17 -0
  85. package/snapshots/commands/projects.test.snap +141 -0
  86. package/snapshots/commands/roles.test.snap +19 -0
  87. package/snapshots/commands/set_context.test.snap +30 -0
  88. package/snapshots/writer.test.snap +60 -0
  89. package/snapshotsResolver.cjs +32 -0
  90. package/src/analytics.ts +95 -0
  91. package/src/api.ts +44 -0
  92. package/src/auth.ts +137 -0
  93. package/{cli.js → src/cli.ts} +1 -0
  94. package/src/commands/auth.test.ts +62 -0
  95. package/src/commands/auth.ts +148 -0
  96. package/src/commands/branches.test.ts +354 -0
  97. package/src/commands/branches.ts +451 -0
  98. package/src/commands/connection_string.test.ts +250 -0
  99. package/src/commands/connection_string.ts +210 -0
  100. package/src/commands/databases.test.ts +55 -0
  101. package/src/commands/databases.ts +129 -0
  102. package/src/commands/help.test.ts +13 -0
  103. package/{commands/index.js → src/commands/index.ts} +11 -10
  104. package/src/commands/ip_allow.test.ts +86 -0
  105. package/src/commands/ip_allow.ts +202 -0
  106. package/src/commands/operations.test.ts +13 -0
  107. package/src/commands/operations.ts +41 -0
  108. package/src/commands/projects.test.ts +147 -0
  109. package/src/commands/projects.ts +275 -0
  110. package/src/commands/roles.test.ts +46 -0
  111. package/src/commands/roles.ts +100 -0
  112. package/src/commands/set_context.test.ts +64 -0
  113. package/src/commands/set_context.ts +27 -0
  114. package/src/commands/user.ts +21 -0
  115. package/src/config.ts +22 -0
  116. package/src/context.ts +61 -0
  117. package/src/env.ts +7 -0
  118. package/src/errors.ts +24 -0
  119. package/src/help.ts +185 -0
  120. package/src/index.ts +180 -0
  121. package/src/log.ts +16 -0
  122. package/src/parameters.gen.ts +332 -0
  123. package/src/pkg.ts +9 -0
  124. package/src/test_utils/mock_server.ts +27 -0
  125. package/src/test_utils/oauth_server.ts +10 -0
  126. package/src/test_utils/test_cli_command.ts +117 -0
  127. package/src/types.ts +25 -0
  128. package/src/utils/enrichers.ts +73 -0
  129. package/src/utils/formats.test.ts +41 -0
  130. package/src/utils/formats.ts +11 -0
  131. package/src/utils/middlewares.ts +23 -0
  132. package/src/utils/point_in_time.ts +86 -0
  133. package/src/utils/psql.ts +29 -0
  134. package/src/utils/string.ts +8 -0
  135. package/src/utils/ui.ts +64 -0
  136. package/src/writer.test.ts +98 -0
  137. package/src/writer.ts +131 -0
  138. package/tsconfig.json +17 -0
  139. package/analytics.js +0 -78
  140. package/api.js +0 -35
  141. package/auth.js +0 -101
  142. package/commands/auth.js +0 -102
  143. package/commands/auth.test.js +0 -42
  144. package/commands/branches.js +0 -303
  145. package/commands/branches.test.js +0 -321
  146. package/commands/connection_string.js +0 -137
  147. package/commands/connection_string.test.js +0 -204
  148. package/commands/databases.js +0 -79
  149. package/commands/databases.test.js +0 -51
  150. package/commands/help.test.js +0 -11
  151. package/commands/ip_allow.js +0 -135
  152. package/commands/ip_allow.test.js +0 -78
  153. package/commands/operations.js +0 -28
  154. package/commands/operations.test.js +0 -11
  155. package/commands/projects.js +0 -170
  156. package/commands/projects.test.js +0 -132
  157. package/commands/roles.js +0 -57
  158. package/commands/roles.test.js +0 -42
  159. package/commands/set_context.js +0 -22
  160. package/commands/set_context.test.js +0 -53
  161. package/commands/user.js +0 -15
  162. package/config.js +0 -11
  163. package/context.js +0 -48
  164. package/env.js +0 -6
  165. package/errors.js +0 -16
  166. package/help.js +0 -146
  167. package/index.js +0 -168
  168. package/log.js +0 -15
  169. package/parameters.gen.js +0 -322
  170. package/test_utils/mock_server.js +0 -16
  171. package/test_utils/oauth_server.js +0 -9
  172. package/test_utils/test_cli_command.js +0 -80
  173. package/types.js +0 -1
  174. package/utils/enrichers.js +0 -49
  175. package/utils/formats.js +0 -5
  176. package/utils/formats.test.js +0 -32
  177. package/utils/middlewares.js +0 -20
  178. package/utils/point_in_time.js +0 -44
  179. package/utils/psql.js +0 -24
  180. package/utils/string.js +0 -5
  181. package/utils/ui.js +0 -59
  182. package/writer.js +0 -87
  183. package/writer.test.js +0 -86
  184. /package/{callback.html → src/callback.html} +0 -0
@@ -1,137 +0,0 @@
1
- import { EndpointType } from '@neondatabase/api-client';
2
- import { branchIdFromProps, fillSingleProject } from '../utils/enrichers.js';
3
- import { writer } from '../writer.js';
4
- import { psql } from '../utils/psql.js';
5
- const SSL_MODES = ['require', 'verify-ca', 'verify-full', 'omit'];
6
- export const command = 'connection-string [branch]';
7
- export const aliases = ['cs'];
8
- export const describe = 'Get connection string';
9
- export const builder = (argv) => {
10
- return argv
11
- .usage('$0 connection-string [branch] [options]')
12
- .positional('branch', {
13
- describe: 'Branch name or id. If ommited will use the primary branch',
14
- type: 'string',
15
- })
16
- .options({
17
- 'project-id': {
18
- type: 'string',
19
- describe: 'Project ID',
20
- },
21
- 'role-name': {
22
- type: 'string',
23
- describe: 'Role name',
24
- },
25
- 'database-name': {
26
- type: 'string',
27
- describe: 'Database name',
28
- },
29
- pooled: {
30
- type: 'boolean',
31
- describe: 'Use pooled connection',
32
- default: false,
33
- },
34
- prisma: {
35
- type: 'boolean',
36
- describe: 'Use connection string for Prisma setup',
37
- default: false,
38
- },
39
- 'endpoint-type': {
40
- type: 'string',
41
- choices: Object.values(EndpointType),
42
- describe: 'Endpoint type',
43
- },
44
- extended: {
45
- type: 'boolean',
46
- describe: 'Show extended information',
47
- },
48
- psql: {
49
- type: 'boolean',
50
- describe: 'Connect to a database via psql using connection string',
51
- default: false,
52
- },
53
- ssl: {
54
- type: 'string',
55
- choices: SSL_MODES,
56
- default: 'require',
57
- describe: 'SSL mode',
58
- },
59
- })
60
- .middleware(fillSingleProject);
61
- };
62
- export const handler = async (props) => {
63
- const projectId = props.projectId;
64
- const branchId = await branchIdFromProps(props);
65
- const { data: { endpoints }, } = await props.apiClient.listProjectBranchEndpoints(projectId, branchId);
66
- const matchEndpointType = props.endpointType ?? EndpointType.ReadWrite;
67
- let endpoint = endpoints.find((e) => e.type === matchEndpointType);
68
- if (!endpoint && props.endpointType == null) {
69
- endpoint = endpoints[0];
70
- }
71
- if (!endpoint) {
72
- throw new Error(`No ${props.endpointType ?? ''} endpoint found for the branch: ${branchId}`);
73
- }
74
- const role = props.roleName ||
75
- (await props.apiClient
76
- .listProjectBranchRoles(projectId, branchId)
77
- .then(({ data }) => {
78
- if (data.roles.length === 0) {
79
- throw new Error(`No roles found for the branch: ${branchId}`);
80
- }
81
- if (data.roles.length === 1) {
82
- return data.roles[0].name;
83
- }
84
- throw new Error(`Multiple roles found for the branch, please provide one with the --role-name option: ${data.roles
85
- .map((r) => r.name)
86
- .join(', ')}`);
87
- }));
88
- const database = props.databaseName ||
89
- (await props.apiClient
90
- .listProjectBranchDatabases(projectId, branchId)
91
- .then(({ data }) => {
92
- if (data.databases.length === 0) {
93
- throw new Error(`No databases found for the branch: ${branchId}`);
94
- }
95
- if (data.databases.length === 1) {
96
- return data.databases[0].name;
97
- }
98
- throw new Error(`Multiple databases found for the branch, please provide one with the --database-name option: ${data.databases
99
- .map((d) => d.name)
100
- .join(', ')}`);
101
- }));
102
- const { data: { password }, } = await props.apiClient.getProjectBranchRolePassword(props.projectId, endpoint.branch_id, role);
103
- const host = props.pooled
104
- ? endpoint.host.replace(endpoint.id, `${endpoint.id}-pooler`)
105
- : endpoint.host;
106
- const connectionString = new URL(`postgres://${host}`);
107
- connectionString.pathname = database;
108
- connectionString.username = role;
109
- connectionString.password = password;
110
- if (props.prisma) {
111
- connectionString.searchParams.set('connect_timeout', '30');
112
- if (props.pooled) {
113
- connectionString.searchParams.set('pool_timeout', '30');
114
- connectionString.searchParams.set('pgbouncer', 'true');
115
- }
116
- }
117
- if (props.ssl !== 'omit') {
118
- connectionString.searchParams.set('sslmode', props.ssl);
119
- }
120
- if (props.psql) {
121
- const psqlArgs = props['--'];
122
- await psql(connectionString.toString(), psqlArgs);
123
- }
124
- else if (props.extended) {
125
- writer(props).end({
126
- connection_string: connectionString.toString(),
127
- host,
128
- role,
129
- password,
130
- database,
131
- options: connectionString.searchParams.toString(),
132
- }, { fields: ['host', 'role', 'password', 'database'] });
133
- }
134
- else {
135
- process.stdout.write(connectionString.toString() + '\n');
136
- }
137
- };
@@ -1,204 +0,0 @@
1
- import { describe } from '@jest/globals';
2
- import { testCliCommand } from '../test_utils/test_cli_command';
3
- describe('connection_string', () => {
4
- testCliCommand({
5
- name: 'connection_string',
6
- args: [
7
- 'connection-string',
8
- 'test_branch',
9
- '--project-id',
10
- 'test',
11
- '--database-name',
12
- 'test_db',
13
- '--role-name',
14
- 'test_role',
15
- ],
16
- expected: {
17
- snapshot: true,
18
- },
19
- });
20
- testCliCommand({
21
- name: 'connection_string branch id',
22
- args: [
23
- 'connection-string',
24
- 'br-sunny-branch-123456',
25
- '--project-id',
26
- 'test',
27
- '--database-name',
28
- 'test_db',
29
- '--role-name',
30
- 'test_role',
31
- ],
32
- expected: {
33
- snapshot: true,
34
- },
35
- });
36
- testCliCommand({
37
- name: 'connection_string branch id 8 digits',
38
- args: [
39
- 'connection-string',
40
- 'br-cloudy-branch-12345678',
41
- '--project-id',
42
- 'test',
43
- '--database-name',
44
- 'test_db',
45
- '--role-name',
46
- 'test_role',
47
- ],
48
- expected: {
49
- snapshot: true,
50
- },
51
- });
52
- testCliCommand({
53
- name: 'connection_string pooled',
54
- args: [
55
- 'connection-string',
56
- 'test_branch',
57
- '--project-id',
58
- 'test',
59
- '--database-name',
60
- 'test_db',
61
- '--role-name',
62
- 'test_role',
63
- '--pooled',
64
- ],
65
- expected: {
66
- snapshot: true,
67
- },
68
- });
69
- testCliCommand({
70
- name: 'connection_string prisma',
71
- args: [
72
- 'connection-string',
73
- 'test_branch',
74
- '--project-id',
75
- 'test',
76
- '--database-name',
77
- 'test_db',
78
- '--role-name',
79
- 'test_role',
80
- '--prisma',
81
- ],
82
- expected: {
83
- snapshot: true,
84
- },
85
- });
86
- testCliCommand({
87
- name: 'connection_string prisma pooled',
88
- args: [
89
- 'connection-string',
90
- 'test_branch',
91
- '--project-id',
92
- 'test',
93
- '--database-name',
94
- 'test_db',
95
- '--role-name',
96
- 'test_role',
97
- '--prisma',
98
- '--pooled',
99
- ],
100
- expected: {
101
- snapshot: true,
102
- },
103
- });
104
- testCliCommand({
105
- name: 'connection_string prisma pooled extended',
106
- args: [
107
- 'connection-string',
108
- 'test_branch',
109
- '--project-id',
110
- 'test',
111
- '--database-name',
112
- 'test_db',
113
- '--role-name',
114
- 'test_role',
115
- '--prisma',
116
- '--pooled',
117
- '--extended',
118
- ],
119
- expected: {
120
- snapshot: true,
121
- },
122
- });
123
- testCliCommand({
124
- name: 'connection_string without any args should pass',
125
- args: ['connection-string'],
126
- mockDir: 'single_project',
127
- expected: {
128
- snapshot: true,
129
- },
130
- });
131
- testCliCommand({
132
- name: 'connection_string with psql',
133
- args: [
134
- 'connection-string',
135
- 'test_branch',
136
- '--project-id',
137
- 'test',
138
- '--database-name',
139
- 'test_db',
140
- '--role-name',
141
- 'test_role',
142
- '--psql',
143
- ],
144
- expected: {
145
- snapshot: true,
146
- },
147
- });
148
- testCliCommand({
149
- name: 'connection_string with psql and psql args',
150
- args: [
151
- 'connection-string',
152
- 'test_branch',
153
- '--project-id',
154
- 'test',
155
- '--database-name',
156
- 'test_db',
157
- '--role-name',
158
- 'test_role',
159
- '--psql',
160
- '--',
161
- '-c',
162
- 'SELECT 1',
163
- ],
164
- expected: {
165
- snapshot: true,
166
- },
167
- });
168
- testCliCommand({
169
- name: 'connection_string without ssl',
170
- args: [
171
- 'connection-string',
172
- 'test_branch',
173
- '--project-id',
174
- 'test',
175
- '--database-name',
176
- 'test_db',
177
- '--role-name',
178
- 'test_role',
179
- '--ssl',
180
- 'omit',
181
- ],
182
- expected: {
183
- snapshot: true,
184
- },
185
- });
186
- testCliCommand({
187
- name: 'connection_string with ssl verify full',
188
- args: [
189
- 'connection-string',
190
- 'test_branch',
191
- '--project-id',
192
- 'test',
193
- '--database-name',
194
- 'test_db',
195
- '--role-name',
196
- 'test_role',
197
- '--ssl',
198
- 'verify-full',
199
- ],
200
- expected: {
201
- snapshot: true,
202
- },
203
- });
204
- });
@@ -1,79 +0,0 @@
1
- import { retryOnLock } from '../api.js';
2
- import { branchIdFromProps, fillSingleProject } from '../utils/enrichers.js';
3
- import { writer } from '../writer.js';
4
- const DATABASE_FIELDS = ['name', 'owner_name', 'created_at'];
5
- export const command = 'databases';
6
- export const describe = 'Manage databases';
7
- export const aliases = ['database', 'db'];
8
- export const builder = (argv) => argv
9
- .usage('$0 databases <sub-command> [options]')
10
- .options({
11
- 'project-id': {
12
- describe: 'Project ID',
13
- type: 'string',
14
- },
15
- branch: {
16
- describe: 'Branch ID or name',
17
- type: 'string',
18
- },
19
- })
20
- .middleware(fillSingleProject)
21
- .command('list', 'List databases', (yargs) => yargs, async (args) => await list(args))
22
- .command('create', 'Create a database', (yargs) => yargs.options({
23
- name: {
24
- describe: 'Database name',
25
- type: 'string',
26
- demandOption: true,
27
- },
28
- 'owner-name': {
29
- describe: 'Owner name',
30
- type: 'string',
31
- },
32
- }), async (args) => await create(args))
33
- .command('delete <database>', 'Delete a database', (yargs) => yargs, async (args) => await deleteDb(args));
34
- export const handler = (args) => {
35
- return args;
36
- };
37
- export const list = async (props) => {
38
- const branchId = await branchIdFromProps(props);
39
- const { data } = await props.apiClient.listProjectBranchDatabases(props.projectId, branchId);
40
- writer(props).end(data.databases, {
41
- fields: DATABASE_FIELDS,
42
- });
43
- };
44
- export const create = async (props) => {
45
- const branchId = await branchIdFromProps(props);
46
- const owner = props.ownerName ??
47
- (await props.apiClient
48
- .listProjectBranchRoles(props.projectId, branchId)
49
- .then(({ data }) => {
50
- if (data.roles.length === 0) {
51
- throw new Error(`No roles found in branch ${branchId}`);
52
- }
53
- if (data.roles.length > 1) {
54
- throw new Error(`More than one role found in branch ${branchId}. Please specify the owner name. Roles: ${data.roles
55
- .map((r) => r.name)
56
- .join(', ')}`);
57
- }
58
- return data.roles[0].name;
59
- }));
60
- if (!owner) {
61
- throw new Error('No owner found');
62
- }
63
- const { data } = await retryOnLock(() => props.apiClient.createProjectBranchDatabase(props.projectId, branchId, {
64
- database: {
65
- name: props.name,
66
- owner_name: owner,
67
- },
68
- }));
69
- writer(props).end(data.database, {
70
- fields: DATABASE_FIELDS,
71
- });
72
- };
73
- export const deleteDb = async (props) => {
74
- const branchId = await branchIdFromProps(props);
75
- const { data } = await retryOnLock(() => props.apiClient.deleteProjectBranchDatabase(props.projectId, branchId, props.database));
76
- writer(props).end(data.database, {
77
- fields: DATABASE_FIELDS,
78
- });
79
- };
@@ -1,51 +0,0 @@
1
- import { describe } from '@jest/globals';
2
- import { testCliCommand } from '../test_utils/test_cli_command.js';
3
- describe('databases', () => {
4
- testCliCommand({
5
- name: 'list',
6
- args: [
7
- 'databases',
8
- 'list',
9
- '--project-id',
10
- 'test',
11
- '--branch',
12
- 'test_branch',
13
- ],
14
- expected: {
15
- snapshot: true,
16
- },
17
- });
18
- testCliCommand({
19
- name: 'create',
20
- args: [
21
- 'databases',
22
- 'create',
23
- '--project-id',
24
- 'test',
25
- '--branch',
26
- 'test_branch',
27
- '--name',
28
- 'test_db',
29
- '--owner-name',
30
- 'test_owner',
31
- ],
32
- expected: {
33
- snapshot: true,
34
- },
35
- });
36
- testCliCommand({
37
- name: 'delete',
38
- args: [
39
- 'databases',
40
- 'delete',
41
- 'test_db',
42
- '--project-id',
43
- 'test',
44
- '--branch',
45
- 'test_branch',
46
- ],
47
- expected: {
48
- snapshot: true,
49
- },
50
- });
51
- });
@@ -1,11 +0,0 @@
1
- import { describe, expect } from '@jest/globals';
2
- import { testCliCommand } from '../test_utils/test_cli_command.js';
3
- describe('help', () => {
4
- testCliCommand({
5
- name: 'without args',
6
- args: [],
7
- expected: {
8
- stderr: expect.stringContaining(`neonctl <command> [options]`),
9
- },
10
- });
11
- });
@@ -1,135 +0,0 @@
1
- import { writer } from '../writer.js';
2
- import { fillSingleProject } from '../utils/enrichers.js';
3
- import { projectUpdateRequest } from '../parameters.gen.js';
4
- import { log } from '../log.js';
5
- const IP_ALLOW_FIELDS = [
6
- 'id',
7
- 'name',
8
- 'IP_addresses',
9
- 'primary_branch_only',
10
- ];
11
- export const command = 'ip-allow';
12
- export const describe = 'Manage IP Allow';
13
- export const builder = (argv) => {
14
- return argv
15
- .usage('$0 ip-allow <sub-command> [options]')
16
- .options({
17
- 'project-id': {
18
- describe: 'Project ID',
19
- type: 'string',
20
- },
21
- })
22
- .middleware(fillSingleProject)
23
- .command('list', 'List the IP allowlist', (yargs) => yargs, async (args) => {
24
- await list(args);
25
- })
26
- .command('add [ips...]', 'Add IP addresses to the IP allowlist', (yargs) => yargs
27
- .usage('$0 ip-allow add [ips...]')
28
- .positional('ips', {
29
- describe: 'The list of IP addresses to add',
30
- type: 'string',
31
- default: [],
32
- array: true,
33
- })
34
- .options({
35
- 'primary-only': {
36
- describe: projectUpdateRequest['project.settings.allowed_ips.primary_branch_only'].description,
37
- type: 'boolean',
38
- },
39
- }), async (args) => {
40
- await add(args);
41
- })
42
- .command('remove [ips...]', 'Remove IP addresses from the IP allowlist', (yargs) => yargs.usage('$0 ip-allow remove [ips...]').positional('ips', {
43
- describe: 'The list of IP addresses to remove',
44
- type: 'string',
45
- default: [],
46
- array: true,
47
- }), async (args) => {
48
- await remove(args);
49
- })
50
- .command('reset [ips...]', 'Reset the IP allowlist', (yargs) => yargs.usage('$0 ip-allow reset [ips...]').positional('ips', {
51
- describe: 'The list of IP addresses to reset',
52
- type: 'string',
53
- default: [],
54
- array: true,
55
- }), async (args) => {
56
- await reset(args);
57
- });
58
- };
59
- export const handler = (args) => {
60
- return args;
61
- };
62
- const list = async (props) => {
63
- const { data } = await props.apiClient.getProject(props.projectId);
64
- writer(props).end(parse(data.project), {
65
- fields: IP_ALLOW_FIELDS,
66
- });
67
- };
68
- const add = async (props) => {
69
- if (props.ips.length <= 0) {
70
- throw new Error(`Enter individual IP addresses, define ranges with a dash, or use CIDR notation for more flexibility.
71
- Example: neonctl ip-allow add 192.168.1.1, 192.168.1.20-192.168.1.50, 192.168.1.0/24 --project-id <id>`);
72
- }
73
- const project = {};
74
- const { data } = await props.apiClient.getProject(props.projectId);
75
- const existingAllowedIps = data.project.settings?.allowed_ips;
76
- project.settings = {
77
- allowed_ips: {
78
- ips: [...new Set(props.ips.concat(existingAllowedIps?.ips ?? []))],
79
- primary_branch_only: props.primaryOnly ?? existingAllowedIps?.primary_branch_only ?? false,
80
- },
81
- };
82
- const { data: response } = await props.apiClient.updateProject(props.projectId, {
83
- project,
84
- });
85
- writer(props).end(parse(response.project), {
86
- fields: IP_ALLOW_FIELDS,
87
- });
88
- };
89
- const remove = async (props) => {
90
- if (props.ips.length <= 0) {
91
- throw new Error(`Remove individual IP addresses and ranges. Example: neonctl ip-allow remove 192.168.1.1 --project-id <id>`);
92
- }
93
- const project = {};
94
- const { data } = await props.apiClient.getProject(props.projectId);
95
- const existingAllowedIps = data.project.settings?.allowed_ips;
96
- project.settings = {
97
- allowed_ips: {
98
- ips: existingAllowedIps?.ips?.filter((ip) => !props.ips.includes(ip)) ?? [],
99
- primary_branch_only: existingAllowedIps?.primary_branch_only ?? false,
100
- },
101
- };
102
- const { data: response } = await props.apiClient.updateProject(props.projectId, {
103
- project,
104
- });
105
- writer(props).end(parse(response.project), {
106
- fields: IP_ALLOW_FIELDS,
107
- });
108
- };
109
- const reset = async (props) => {
110
- const project = {};
111
- project.settings = {
112
- allowed_ips: {
113
- ips: props.ips,
114
- primary_branch_only: false,
115
- },
116
- };
117
- const { data } = await props.apiClient.updateProject(props.projectId, {
118
- project,
119
- });
120
- writer(props).end(parse(data.project), {
121
- fields: IP_ALLOW_FIELDS,
122
- });
123
- if (props.ips.length <= 0) {
124
- log.info(`The IP allowlist has been reset. All databases on project "${data.project.name}" are now exposed to the internet`);
125
- }
126
- };
127
- const parse = (project) => {
128
- const ips = project.settings?.allowed_ips?.ips ?? [];
129
- return {
130
- id: project.id,
131
- name: project.name,
132
- IP_addresses: ips,
133
- primary_branch_only: project.settings?.allowed_ips?.primary_branch_only ?? false,
134
- };
135
- };
@@ -1,78 +0,0 @@
1
- import { describe } from '@jest/globals';
2
- import { testCliCommand } from '../test_utils/test_cli_command.js';
3
- describe('ip-allow', () => {
4
- testCliCommand({
5
- name: 'list IP allow',
6
- args: ['ip-allow', 'list', '--project-id', 'test'],
7
- expected: {
8
- snapshot: true,
9
- },
10
- });
11
- testCliCommand({
12
- name: 'list IP Allow with single-project',
13
- args: ['ip-allow', 'list'],
14
- mockDir: 'single_project',
15
- expected: {
16
- snapshot: true,
17
- },
18
- });
19
- testCliCommand({
20
- name: 'Add IP allow - Error',
21
- args: ['ip-allow', 'add', '--projectId', 'test'],
22
- expected: {
23
- code: 1,
24
- stderr: `ERROR: Enter individual IP addresses, define ranges with a dash, or use CIDR notation for more flexibility.
25
- Example: neonctl ip-allow add 192.168.1.1, 192.168.1.20-192.168.1.50, 192.168.1.0/24 --project-id <id>`,
26
- },
27
- });
28
- testCliCommand({
29
- name: 'Add IP allow',
30
- args: [
31
- 'ip-allow',
32
- 'add',
33
- '127.0.0.1',
34
- '192.168.10.1-192.168.10.15',
35
- '--primary-only',
36
- '--project-id',
37
- 'test',
38
- ],
39
- expected: {
40
- snapshot: true,
41
- },
42
- });
43
- testCliCommand({
44
- name: 'Remove IP allow - Error',
45
- args: ['ip-allow', 'remove', '--project-id', 'test'],
46
- expected: {
47
- code: 1,
48
- stderr: `ERROR: Remove individual IP addresses and ranges. Example: neonctl ip-allow remove 192.168.1.1 --project-id <id>`,
49
- },
50
- });
51
- testCliCommand({
52
- name: 'Remove IP allow',
53
- args: ['ip-allow', 'remove', '192.168.1.1', '--project-id', 'test'],
54
- expected: {
55
- snapshot: true,
56
- },
57
- });
58
- testCliCommand({
59
- name: 'Reset IP allow',
60
- args: ['ip-allow', 'reset', '--project-id', 'test'],
61
- expected: {
62
- snapshot: true,
63
- stdout: `id: test
64
- name: test_project
65
- IP_addresses: []
66
- primary_branch_only: false
67
- `,
68
- stderr: `INFO: The IP allowlist has been reset. All databases on project "test_project" are now exposed to the internet`,
69
- },
70
- });
71
- testCliCommand({
72
- name: 'Reset IP allow to new list',
73
- args: ['ip-allow', 'reset', '192.168.2.2', '--project-id', 'test'],
74
- expected: {
75
- snapshot: true,
76
- },
77
- });
78
- });