neon 2.1.2 → 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.
- package/LICENSE.md +178 -0
- package/README.md +601 -0
- package/dist/analytics.js +156 -0
- package/dist/api.js +665 -0
- package/dist/auth.js +127 -0
- package/dist/callback.html +51 -0
- package/dist/cli.js +9 -0
- package/dist/commands/auth.js +214 -0
- package/dist/commands/bootstrap.js +481 -0
- package/dist/commands/branches.js +481 -0
- package/dist/commands/bucket.js +543 -0
- package/dist/commands/checkout.js +289 -0
- package/dist/commands/config.js +544 -0
- package/dist/commands/connection_string.js +172 -0
- package/dist/commands/data_api.js +285 -0
- package/dist/commands/databases.js +82 -0
- package/dist/commands/deploy.js +26 -0
- package/dist/commands/dev.js +698 -0
- package/dist/commands/env.js +166 -0
- package/dist/commands/functions.js +373 -0
- package/dist/commands/index.js +54 -0
- package/dist/commands/init.js +73 -0
- package/dist/commands/ip_allow.js +137 -0
- package/dist/commands/link.js +1121 -0
- package/dist/commands/neon_auth.js +1028 -0
- package/dist/commands/operations.js +28 -0
- package/dist/commands/orgs.js +24 -0
- package/dist/commands/projects.js +372 -0
- package/dist/commands/psql.js +62 -0
- package/dist/commands/roles.js +65 -0
- package/dist/commands/schema_diff.js +151 -0
- package/dist/commands/set_context.js +29 -0
- package/dist/commands/status.js +40 -0
- package/dist/commands/user.js +15 -0
- package/dist/commands/vpc_endpoints.js +134 -0
- package/dist/config.js +11 -0
- package/dist/config_format.js +72 -0
- package/dist/context.js +177 -0
- package/dist/current_branch_fast_path.js +55 -0
- package/dist/dev/env.js +240 -0
- package/dist/dev/functions.js +70 -0
- package/dist/dev/inputs.js +63 -0
- package/dist/dev/runtime.js +146 -0
- package/dist/env.js +36 -0
- package/dist/env_file.js +159 -0
- package/dist/errors.js +80 -0
- package/dist/functions_api.js +44 -0
- package/dist/help.js +146 -0
- package/dist/index.js +234 -0
- package/dist/log.js +18 -0
- package/dist/parameters.gen.js +480 -0
- package/dist/pkg.js +25 -0
- package/dist/psql/cli.js +53 -0
- package/dist/psql/command/cmd_cond.js +437 -0
- package/dist/psql/command/cmd_connect.js +820 -0
- package/dist/psql/command/cmd_copy.js +1035 -0
- package/dist/psql/command/cmd_describe.js +1815 -0
- package/dist/psql/command/cmd_format.js +922 -0
- package/dist/psql/command/cmd_io.js +2193 -0
- package/dist/psql/command/cmd_lo.js +393 -0
- package/dist/psql/command/cmd_meta.js +970 -0
- package/dist/psql/command/cmd_misc.js +187 -0
- package/dist/psql/command/cmd_pipeline.js +1148 -0
- package/dist/psql/command/cmd_restrict.js +171 -0
- package/dist/psql/command/cmd_show.js +766 -0
- package/dist/psql/command/dispatch.js +343 -0
- package/dist/psql/command/inputQueue.js +42 -0
- package/dist/psql/command/shared.js +71 -0
- package/dist/psql/complete/filenames.js +139 -0
- package/dist/psql/complete/index.js +104 -0
- package/dist/psql/complete/matcher.js +315 -0
- package/dist/psql/complete/psqlVars.js +247 -0
- package/dist/psql/complete/queries.js +493 -0
- package/dist/psql/complete/rules.js +2424 -0
- package/dist/psql/core/common.js +1253 -0
- package/dist/psql/core/help.js +576 -0
- package/dist/psql/core/mainloop.js +1360 -0
- package/dist/psql/core/prompt.js +440 -0
- package/dist/psql/core/settings.js +684 -0
- package/dist/psql/core/sqlHelp.js +1066 -0
- package/dist/psql/core/startup.js +846 -0
- package/dist/psql/core/syncVars.js +116 -0
- package/dist/psql/core/variables.js +287 -0
- package/dist/psql/describe/formatters.js +1290 -0
- package/dist/psql/describe/processNamePattern.js +270 -0
- package/dist/psql/describe/queries.js +2378 -0
- package/dist/psql/describe/versionGate.js +43 -0
- package/dist/psql/index.js +2030 -0
- package/dist/psql/io/history.js +299 -0
- package/dist/psql/io/input.js +120 -0
- package/dist/psql/io/lineEditor/buffer.js +325 -0
- package/dist/psql/io/lineEditor/complete.js +227 -0
- package/dist/psql/io/lineEditor/filename.js +159 -0
- package/dist/psql/io/lineEditor/index.js +894 -0
- package/dist/psql/io/lineEditor/keymap.js +745 -0
- package/dist/psql/io/lineEditor/vt100.js +363 -0
- package/dist/psql/io/pgpass.js +202 -0
- package/dist/psql/io/pgservice.js +194 -0
- package/dist/psql/io/psqlrc.js +422 -0
- package/dist/psql/print/aligned.js +1765 -0
- package/dist/psql/print/asciidoc.js +248 -0
- package/dist/psql/print/crosstab.js +463 -0
- package/dist/psql/print/csv.js +95 -0
- package/dist/psql/print/html.js +258 -0
- package/dist/psql/print/json.js +96 -0
- package/dist/psql/print/latex.js +396 -0
- package/dist/psql/print/pager.js +267 -0
- package/dist/psql/print/troff.js +258 -0
- package/dist/psql/print/unaligned.js +119 -0
- package/dist/psql/print/units.js +135 -0
- package/dist/psql/scanner/slash.js +515 -0
- package/dist/psql/scanner/sql.js +914 -0
- package/dist/psql/scanner/stringutils.js +394 -0
- package/dist/psql/types/backslash.js +1 -0
- package/dist/psql/types/connection.js +1 -0
- package/dist/psql/types/index.js +7 -0
- package/dist/psql/types/printer.js +1 -0
- package/dist/psql/types/repl.js +1 -0
- package/dist/psql/types/scanner.js +24 -0
- package/dist/psql/types/settings.js +1 -0
- package/dist/psql/types/variables.js +1 -0
- package/dist/psql/wire/connection.js +2858 -0
- package/dist/psql/wire/copy.js +108 -0
- package/dist/psql/wire/notify.js +59 -0
- package/dist/psql/wire/pipeline.js +521 -0
- package/dist/psql/wire/protocol.js +466 -0
- package/dist/psql/wire/sasl.js +296 -0
- package/dist/psql/wire/tls.js +602 -0
- package/dist/storage_api.js +147 -0
- package/dist/test_utils/fixtures.js +122 -0
- package/dist/test_utils/oauth_server.js +9 -0
- package/dist/types.js +1 -0
- package/dist/utils/api_enums.js +33 -0
- package/dist/utils/auth.js +5 -0
- package/dist/utils/branch_notice.js +22 -0
- package/dist/utils/branch_picker.js +103 -0
- package/dist/utils/compute_units.js +28 -0
- package/dist/utils/enrichers.js +161 -0
- package/dist/utils/esbuild.js +158 -0
- package/dist/utils/formats.js +18 -0
- package/dist/utils/middlewares.js +20 -0
- package/dist/utils/package_manager.js +68 -0
- package/dist/utils/point_in_time.js +56 -0
- package/dist/utils/psql.js +120 -0
- package/dist/utils/string.js +5 -0
- package/dist/utils/ui.js +59 -0
- package/dist/utils/zip.js +4 -0
- package/dist/writer.js +97 -0
- package/package.json +117 -14
- package/.jshintrc +0 -3
- package/CHANGELOG.markdown +0 -22
- package/LICENSE +0 -21
- package/README.markdown +0 -76
- package/bower.json +0 -23
- package/license.txt +0 -9
- package/neon.js +0 -234
- package/stdlib/bubbling_support.js +0 -32
- package/stdlib/custom_event.js +0 -54
- package/stdlib/custom_event_support.js +0 -195
- package/stdlib/index.js +0 -7
- package/stdlib/node_support.js +0 -123
- package/stdlib/widget.js +0 -340
- package/test/neon_browser.html +0 -11
- package/test/neon_stdlib_browser.html +0 -15
- package/test/neon_stdlib_test.js +0 -84
- package/test/neon_test.js +0 -64
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { fillSingleProject } from "../utils/enrichers.js";
|
|
2
|
+
import { writer } from "../writer.js";
|
|
3
|
+
const OPERATIONS_FIELDS = ["id", "action", "status", "created_at"];
|
|
4
|
+
export const command = "operations";
|
|
5
|
+
export const describe = "Manage operations";
|
|
6
|
+
export const aliases = ["operation"];
|
|
7
|
+
export const builder = (argv) => argv
|
|
8
|
+
.usage("$0 operations <sub-command> [options]")
|
|
9
|
+
.options({
|
|
10
|
+
"project-id": {
|
|
11
|
+
describe: "Project ID",
|
|
12
|
+
type: "string",
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
.middleware(fillSingleProject)
|
|
16
|
+
.command("list", "List operations", (yargs) => yargs, (args) => list(args));
|
|
17
|
+
export const handler = (args) => {
|
|
18
|
+
return args;
|
|
19
|
+
};
|
|
20
|
+
export const list = async (props) => {
|
|
21
|
+
const { data } = await props.apiClient.listProjectOperations({
|
|
22
|
+
projectId: props.projectId,
|
|
23
|
+
limit: props.limit,
|
|
24
|
+
});
|
|
25
|
+
writer(props).end(data.operations, {
|
|
26
|
+
fields: OPERATIONS_FIELDS,
|
|
27
|
+
});
|
|
28
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { writer } from "../writer.js";
|
|
2
|
+
const ORG_FIELDS = ["id", "name"];
|
|
3
|
+
export const command = "orgs";
|
|
4
|
+
export const describe = "Manage organizations";
|
|
5
|
+
export const aliases = ["org"];
|
|
6
|
+
export const builder = (argv) => {
|
|
7
|
+
return argv.usage("$0 orgs <sub-command> [options]").command("list", "List organizations", (yargs) => yargs, async (args) => {
|
|
8
|
+
// @ts-expect-error: TODO - Assert `args` is `CommonProps`
|
|
9
|
+
await list(args);
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
export const handler = (args) => {
|
|
13
|
+
return args;
|
|
14
|
+
};
|
|
15
|
+
const list = async (props) => {
|
|
16
|
+
const out = writer(props);
|
|
17
|
+
const { data: { organizations }, } = await props.apiClient.getCurrentUserOrganizations();
|
|
18
|
+
out.write(organizations, {
|
|
19
|
+
fields: ORG_FIELDS,
|
|
20
|
+
title: "Organizations",
|
|
21
|
+
emptyMessage: "You are not a member of any organization.",
|
|
22
|
+
});
|
|
23
|
+
out.end();
|
|
24
|
+
};
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import { isNeonApiError, messageFromBody } from "../api.js";
|
|
3
|
+
import { updateContextFile } from "../context.js";
|
|
4
|
+
import { isCi } from "../env.js";
|
|
5
|
+
import { log } from "../log.js";
|
|
6
|
+
import { projectCreateRequest, projectUpdateRequest, } from "../parameters.gen.js";
|
|
7
|
+
import { getComputeUnits } from "../utils/compute_units.js";
|
|
8
|
+
import { psql } from "../utils/psql.js";
|
|
9
|
+
import { writer } from "../writer.js";
|
|
10
|
+
export const PROJECT_FIELDS = [
|
|
11
|
+
"id",
|
|
12
|
+
"name",
|
|
13
|
+
"region_id",
|
|
14
|
+
"created_at",
|
|
15
|
+
];
|
|
16
|
+
export const REGIONS = [
|
|
17
|
+
"aws-us-west-2",
|
|
18
|
+
"aws-ap-southeast-1",
|
|
19
|
+
"aws-ap-southeast-2",
|
|
20
|
+
"aws-eu-central-1",
|
|
21
|
+
"aws-us-east-2",
|
|
22
|
+
"aws-us-east-1",
|
|
23
|
+
"azure-eastus2",
|
|
24
|
+
];
|
|
25
|
+
const PROJECTS_LIST_LIMIT = 100;
|
|
26
|
+
export const command = "projects";
|
|
27
|
+
export const describe = "Manage projects";
|
|
28
|
+
export const aliases = ["project"];
|
|
29
|
+
export const builder = (argv) => {
|
|
30
|
+
return argv
|
|
31
|
+
.usage("$0 projects <sub-command> [options]")
|
|
32
|
+
.middleware((args) => {
|
|
33
|
+
// Provide alias for analytics
|
|
34
|
+
args.projectId = args.id;
|
|
35
|
+
})
|
|
36
|
+
.command("list", "List projects", (yargs) => yargs.options({
|
|
37
|
+
"org-id": {
|
|
38
|
+
describe: "List projects of a given organization",
|
|
39
|
+
type: "string",
|
|
40
|
+
},
|
|
41
|
+
"recoverable-only": {
|
|
42
|
+
describe: "List only deleted projects within their deletion grace period",
|
|
43
|
+
type: "boolean",
|
|
44
|
+
},
|
|
45
|
+
}), async (args) => {
|
|
46
|
+
await handleMissingOrgId(args, list);
|
|
47
|
+
})
|
|
48
|
+
.command("create", "Create a project", (yargs) => yargs.options({
|
|
49
|
+
"block-public-connections": {
|
|
50
|
+
describe: projectCreateRequest["project.settings.block_public_connections"].description,
|
|
51
|
+
type: "boolean",
|
|
52
|
+
},
|
|
53
|
+
"block-vpc-connections": {
|
|
54
|
+
describe: projectCreateRequest["project.settings.block_vpc_connections"].description,
|
|
55
|
+
type: "boolean",
|
|
56
|
+
},
|
|
57
|
+
hipaa: {
|
|
58
|
+
describe: projectCreateRequest["project.settings.hipaa"]
|
|
59
|
+
.description,
|
|
60
|
+
type: "boolean",
|
|
61
|
+
},
|
|
62
|
+
name: {
|
|
63
|
+
describe: projectCreateRequest["project.name"].description,
|
|
64
|
+
type: "string",
|
|
65
|
+
},
|
|
66
|
+
"region-id": {
|
|
67
|
+
describe: `The region ID. Possible values: ${REGIONS.join(", ")}`,
|
|
68
|
+
type: "string",
|
|
69
|
+
},
|
|
70
|
+
"org-id": {
|
|
71
|
+
describe: "The project's organization ID",
|
|
72
|
+
type: "string",
|
|
73
|
+
},
|
|
74
|
+
psql: {
|
|
75
|
+
type: "boolean",
|
|
76
|
+
describe: "Connect to a new project via psql",
|
|
77
|
+
default: false,
|
|
78
|
+
},
|
|
79
|
+
fallback: {
|
|
80
|
+
type: "boolean",
|
|
81
|
+
describe: "Force the embedded TypeScript psql fallback (for testing)",
|
|
82
|
+
default: false,
|
|
83
|
+
hidden: true,
|
|
84
|
+
},
|
|
85
|
+
database: {
|
|
86
|
+
describe: projectCreateRequest["project.branch.database_name"]
|
|
87
|
+
.description,
|
|
88
|
+
type: "string",
|
|
89
|
+
},
|
|
90
|
+
role: {
|
|
91
|
+
describe: projectCreateRequest["project.branch.role_name"]
|
|
92
|
+
.description,
|
|
93
|
+
type: "string",
|
|
94
|
+
},
|
|
95
|
+
"set-context": {
|
|
96
|
+
type: "boolean",
|
|
97
|
+
describe: "Set the current context to the new project",
|
|
98
|
+
default: false,
|
|
99
|
+
},
|
|
100
|
+
cu: {
|
|
101
|
+
describe: 'The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3").',
|
|
102
|
+
type: "string",
|
|
103
|
+
},
|
|
104
|
+
}), async (args) => {
|
|
105
|
+
await handleMissingOrgId(args, create);
|
|
106
|
+
})
|
|
107
|
+
.command("update <id>", "Update a project", (yargs) => yargs.options({
|
|
108
|
+
"block-vpc-connections": {
|
|
109
|
+
describe: projectUpdateRequest["project.settings.block_vpc_connections"].description +
|
|
110
|
+
" Use --block-vpc-connections=false to set the value to false.",
|
|
111
|
+
type: "boolean",
|
|
112
|
+
},
|
|
113
|
+
"block-public-connections": {
|
|
114
|
+
describe: projectUpdateRequest["project.settings.block_public_connections"].description +
|
|
115
|
+
" Use --block-public-connections=false to set the value to false.",
|
|
116
|
+
type: "boolean",
|
|
117
|
+
},
|
|
118
|
+
hipaa: {
|
|
119
|
+
describe: projectUpdateRequest["project.settings.hipaa"]
|
|
120
|
+
.description,
|
|
121
|
+
type: "boolean",
|
|
122
|
+
},
|
|
123
|
+
cu: {
|
|
124
|
+
describe: 'The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3").',
|
|
125
|
+
type: "string",
|
|
126
|
+
},
|
|
127
|
+
name: {
|
|
128
|
+
describe: projectUpdateRequest["project.name"].description,
|
|
129
|
+
type: "string",
|
|
130
|
+
},
|
|
131
|
+
}), async (args) => {
|
|
132
|
+
await update(args);
|
|
133
|
+
})
|
|
134
|
+
.command("delete <id>", "Delete a project", (yargs) => yargs, async (args) => {
|
|
135
|
+
await deleteProject(args);
|
|
136
|
+
})
|
|
137
|
+
.command("recover <id>", "Recovers a deleted project during the deletion grace period", (yargs) => yargs, async (args) => {
|
|
138
|
+
await recover(args);
|
|
139
|
+
})
|
|
140
|
+
.command("get <id>", "Get a project", (yargs) => yargs, async (args) => {
|
|
141
|
+
await get(args);
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
export const handler = (args) => {
|
|
145
|
+
return args;
|
|
146
|
+
};
|
|
147
|
+
const list = async (props) => {
|
|
148
|
+
const getList = async (fn) => {
|
|
149
|
+
const result = [];
|
|
150
|
+
let cursor;
|
|
151
|
+
let end = false;
|
|
152
|
+
while (!end) {
|
|
153
|
+
const { data } = await fn({
|
|
154
|
+
limit: PROJECTS_LIST_LIMIT,
|
|
155
|
+
org_id: props.orgId,
|
|
156
|
+
recoverable: props.recoverableOnly,
|
|
157
|
+
cursor,
|
|
158
|
+
});
|
|
159
|
+
result.push(...data.projects);
|
|
160
|
+
cursor = data.pagination?.cursor;
|
|
161
|
+
log.debug("Got %d projects, with cursor: %s", data.projects.length, cursor);
|
|
162
|
+
if (data.projects.length < PROJECTS_LIST_LIMIT) {
|
|
163
|
+
end = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
};
|
|
168
|
+
const ownedProjects = await getList(props.apiClient.listProjects);
|
|
169
|
+
const sharedProjects = props.orgId || props.recoverableOnly
|
|
170
|
+
? []
|
|
171
|
+
: await getList(props.apiClient.listSharedProjects);
|
|
172
|
+
const out = writer(props);
|
|
173
|
+
out.write(ownedProjects, {
|
|
174
|
+
fields: props.recoverableOnly
|
|
175
|
+
? [...PROJECT_FIELDS, "deleted_at", "recoverable_until"]
|
|
176
|
+
: PROJECT_FIELDS,
|
|
177
|
+
title: "Projects",
|
|
178
|
+
emptyMessage: props.recoverableOnly
|
|
179
|
+
? "You don't have any recoverable projects."
|
|
180
|
+
: "You don't have any projects yet. See how to create a new project:\n> neon projects create --help",
|
|
181
|
+
});
|
|
182
|
+
if (!props.orgId && !props.recoverableOnly) {
|
|
183
|
+
// We don't list shared projects when listing recoverable projects
|
|
184
|
+
out.write(sharedProjects, {
|
|
185
|
+
fields: PROJECT_FIELDS,
|
|
186
|
+
title: "Shared with you",
|
|
187
|
+
emptyMessage: "No projects have been shared with you",
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
out.end();
|
|
191
|
+
};
|
|
192
|
+
const create = async (props) => {
|
|
193
|
+
const project = {};
|
|
194
|
+
if (props.hipaa !== undefined) {
|
|
195
|
+
if (!project.settings) {
|
|
196
|
+
project.settings = {};
|
|
197
|
+
}
|
|
198
|
+
project.settings.hipaa = props.hipaa;
|
|
199
|
+
}
|
|
200
|
+
if (props.blockPublicConnections !== undefined) {
|
|
201
|
+
if (!project.settings) {
|
|
202
|
+
project.settings = {};
|
|
203
|
+
}
|
|
204
|
+
project.settings.block_public_connections =
|
|
205
|
+
props.blockPublicConnections;
|
|
206
|
+
}
|
|
207
|
+
if (props.blockVpcConnections !== undefined) {
|
|
208
|
+
if (!project.settings) {
|
|
209
|
+
project.settings = {};
|
|
210
|
+
}
|
|
211
|
+
project.settings.block_vpc_connections = props.blockVpcConnections;
|
|
212
|
+
}
|
|
213
|
+
if (props.name) {
|
|
214
|
+
project.name = props.name;
|
|
215
|
+
}
|
|
216
|
+
if (props.regionId) {
|
|
217
|
+
project.region_id = props.regionId;
|
|
218
|
+
}
|
|
219
|
+
if (props.orgId) {
|
|
220
|
+
project.org_id = props.orgId;
|
|
221
|
+
}
|
|
222
|
+
project.branch = {};
|
|
223
|
+
if (props.database) {
|
|
224
|
+
project.branch.database_name = props.database;
|
|
225
|
+
}
|
|
226
|
+
if (props.role) {
|
|
227
|
+
project.branch.role_name = props.role;
|
|
228
|
+
}
|
|
229
|
+
if (props.cu) {
|
|
230
|
+
project.default_endpoint_settings = props.cu
|
|
231
|
+
? getComputeUnits(props.cu)
|
|
232
|
+
: undefined;
|
|
233
|
+
}
|
|
234
|
+
const { data } = await props.apiClient.createProject({
|
|
235
|
+
project,
|
|
236
|
+
});
|
|
237
|
+
if (props.setContext) {
|
|
238
|
+
updateContextFile(props.contextFile, {
|
|
239
|
+
projectId: data.project.id,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const out = writer(props);
|
|
243
|
+
out.write(data.project, { fields: PROJECT_FIELDS, title: "Project" });
|
|
244
|
+
out.write(data.connection_uris, {
|
|
245
|
+
fields: ["connection_uri"],
|
|
246
|
+
title: "Connection URIs",
|
|
247
|
+
});
|
|
248
|
+
out.end();
|
|
249
|
+
if (props.psql) {
|
|
250
|
+
const connection_uri = data.connection_uris[0].connection_uri;
|
|
251
|
+
const psqlArgs = props["--"];
|
|
252
|
+
await psql(connection_uri, psqlArgs, {
|
|
253
|
+
mode: props.fallback ? "ts" : "auto",
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
const deleteProject = async (props) => {
|
|
258
|
+
const { data } = await props.apiClient.deleteProject(props.id);
|
|
259
|
+
writer(props).end(data.project, {
|
|
260
|
+
fields: PROJECT_FIELDS,
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
const update = async (props) => {
|
|
264
|
+
const project = {};
|
|
265
|
+
if (props.hipaa !== undefined) {
|
|
266
|
+
if (!project.settings) {
|
|
267
|
+
project.settings = {};
|
|
268
|
+
}
|
|
269
|
+
project.settings.hipaa = props.hipaa;
|
|
270
|
+
}
|
|
271
|
+
if (props.blockPublicConnections !== undefined) {
|
|
272
|
+
if (!project.settings) {
|
|
273
|
+
project.settings = {};
|
|
274
|
+
}
|
|
275
|
+
project.settings.block_public_connections =
|
|
276
|
+
props.blockPublicConnections;
|
|
277
|
+
}
|
|
278
|
+
if (props.blockVpcConnections !== undefined) {
|
|
279
|
+
if (!project.settings) {
|
|
280
|
+
project.settings = {};
|
|
281
|
+
}
|
|
282
|
+
project.settings.block_vpc_connections = props.blockVpcConnections;
|
|
283
|
+
}
|
|
284
|
+
if (props.name) {
|
|
285
|
+
project.name = props.name;
|
|
286
|
+
}
|
|
287
|
+
if (props.cu) {
|
|
288
|
+
project.default_endpoint_settings = props.cu
|
|
289
|
+
? getComputeUnits(props.cu)
|
|
290
|
+
: undefined;
|
|
291
|
+
}
|
|
292
|
+
const { data } = await props.apiClient.updateProject(props.id, {
|
|
293
|
+
project,
|
|
294
|
+
});
|
|
295
|
+
writer(props).end(data.project, { fields: PROJECT_FIELDS });
|
|
296
|
+
};
|
|
297
|
+
const recover = async (props) => {
|
|
298
|
+
const { data } = await props.apiClient.recoverProject(props.id);
|
|
299
|
+
writer(props).end(data.project, { fields: PROJECT_FIELDS });
|
|
300
|
+
};
|
|
301
|
+
const get = async (props) => {
|
|
302
|
+
const { data } = await props.apiClient.getProject(props.id);
|
|
303
|
+
writer(props).end(data.project, { fields: PROJECT_FIELDS });
|
|
304
|
+
};
|
|
305
|
+
const handleMissingOrgId = async (args, cmd) => {
|
|
306
|
+
try {
|
|
307
|
+
await cmd(args);
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
if (!isCi() && isOrgIdError(err)) {
|
|
311
|
+
const orgId = await selectOrg(args);
|
|
312
|
+
await cmd({ ...args, orgId });
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
throw err;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const isOrgIdError = (err) => {
|
|
320
|
+
return (isNeonApiError(err) &&
|
|
321
|
+
err.status === 400 &&
|
|
322
|
+
messageFromBody(err.data)?.includes("org_id is required"));
|
|
323
|
+
};
|
|
324
|
+
const selectOrg = async (props) => {
|
|
325
|
+
const { data: { organizations }, } = await props.apiClient.getCurrentUserOrganizations();
|
|
326
|
+
if (!organizations?.length) {
|
|
327
|
+
throw new Error(`You don't belong to any organizations. Please create an organization first.`);
|
|
328
|
+
}
|
|
329
|
+
const { orgId } = await prompts({
|
|
330
|
+
onState: onPromptState,
|
|
331
|
+
type: "select",
|
|
332
|
+
name: "orgId",
|
|
333
|
+
message: `What organization would you like to use?`,
|
|
334
|
+
choices: organizations.map((org) => ({
|
|
335
|
+
title: `${org.name} (${org.id})`,
|
|
336
|
+
value: org.id,
|
|
337
|
+
})),
|
|
338
|
+
initial: 0,
|
|
339
|
+
});
|
|
340
|
+
const { save } = await prompts({
|
|
341
|
+
onState: onPromptState,
|
|
342
|
+
type: "confirm",
|
|
343
|
+
name: "save",
|
|
344
|
+
message: `Would you like to use this organization by default?`,
|
|
345
|
+
initial: true,
|
|
346
|
+
});
|
|
347
|
+
if (save) {
|
|
348
|
+
updateContextFile(props.contextFile, { orgId });
|
|
349
|
+
writer(props).text(`
|
|
350
|
+
The organization ID has been saved in ${props.contextFile}
|
|
351
|
+
|
|
352
|
+
If you'd like to change the default organization later, use
|
|
353
|
+
|
|
354
|
+
neonctl link --org-id <org_id>
|
|
355
|
+
|
|
356
|
+
Or to clear the context file and forget the default organization
|
|
357
|
+
|
|
358
|
+
neonctl link --clear
|
|
359
|
+
|
|
360
|
+
`);
|
|
361
|
+
}
|
|
362
|
+
return orgId;
|
|
363
|
+
};
|
|
364
|
+
const onPromptState = (state) => {
|
|
365
|
+
if (state.aborted) {
|
|
366
|
+
// If we don't re-enable the terminal cursor before exiting
|
|
367
|
+
// the program, the cursor will remain hidden
|
|
368
|
+
process.stdout.write("\x1B[?25h");
|
|
369
|
+
process.stdout.write("\n");
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { EndpointType } from "../utils/api_enums.js";
|
|
2
|
+
import { fillSingleProject } from "../utils/enrichers.js";
|
|
3
|
+
import { handler as connectionStringHandler, SSL_MODES, } from "./connection_string.js";
|
|
4
|
+
export const command = "psql [branch]";
|
|
5
|
+
export const describe = "Connect to a database via psql";
|
|
6
|
+
export const builder = (argv) => {
|
|
7
|
+
return argv
|
|
8
|
+
.usage("$0 psql [branch] [options] [-- psql-args]")
|
|
9
|
+
.example("$0 psql", "Connect to the default branch via psql")
|
|
10
|
+
.example("$0 psql main", "Connect to the main branch via psql")
|
|
11
|
+
.example('$0 psql main -- -c "SELECT 1"', "Run a single query against the main branch")
|
|
12
|
+
.example("$0 psql main@2024-01-01T00:00:00Z", "Connect to the main branch at a specific point in time")
|
|
13
|
+
.positional("branch", {
|
|
14
|
+
describe: `Branch name or id. Defaults to the default branch if omitted. Can be written in the point-in-time format: "branch@timestamp" or "branch@lsn"`,
|
|
15
|
+
type: "string",
|
|
16
|
+
})
|
|
17
|
+
.options({
|
|
18
|
+
"project-id": {
|
|
19
|
+
type: "string",
|
|
20
|
+
describe: "Project ID",
|
|
21
|
+
},
|
|
22
|
+
"role-name": {
|
|
23
|
+
type: "string",
|
|
24
|
+
describe: "Role name",
|
|
25
|
+
},
|
|
26
|
+
"database-name": {
|
|
27
|
+
type: "string",
|
|
28
|
+
describe: "Database name",
|
|
29
|
+
},
|
|
30
|
+
pooled: {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
describe: "Use pooled connection",
|
|
33
|
+
default: false,
|
|
34
|
+
},
|
|
35
|
+
"endpoint-type": {
|
|
36
|
+
type: "string",
|
|
37
|
+
choices: Object.values(EndpointType),
|
|
38
|
+
describe: "Endpoint type",
|
|
39
|
+
},
|
|
40
|
+
ssl: {
|
|
41
|
+
type: "string",
|
|
42
|
+
choices: SSL_MODES,
|
|
43
|
+
default: "require",
|
|
44
|
+
describe: "SSL mode",
|
|
45
|
+
},
|
|
46
|
+
fallback: {
|
|
47
|
+
type: "boolean",
|
|
48
|
+
describe: "Force the embedded TypeScript psql fallback (for testing)",
|
|
49
|
+
default: false,
|
|
50
|
+
hidden: true,
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
.middleware(fillSingleProject);
|
|
54
|
+
};
|
|
55
|
+
export const handler = async (props) => {
|
|
56
|
+
await connectionStringHandler({
|
|
57
|
+
...props,
|
|
58
|
+
psql: true,
|
|
59
|
+
prisma: false,
|
|
60
|
+
extended: false,
|
|
61
|
+
});
|
|
62
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { retryOnLock } from "../api.js";
|
|
2
|
+
import { branchIdFromProps, fillSingleProject } from "../utils/enrichers.js";
|
|
3
|
+
import { writer } from "../writer.js";
|
|
4
|
+
const ROLES_FIELDS = ["name", "created_at"];
|
|
5
|
+
export const command = "roles";
|
|
6
|
+
export const describe = "Manage roles";
|
|
7
|
+
export const aliases = ["role"];
|
|
8
|
+
export const builder = (argv) => argv
|
|
9
|
+
.usage("$0 roles <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 roles", (yargs) => yargs, (args) => list(args))
|
|
22
|
+
.command("create", "Create a role", (yargs) => yargs.options({
|
|
23
|
+
name: {
|
|
24
|
+
describe: "Role name",
|
|
25
|
+
type: "string",
|
|
26
|
+
demandOption: true,
|
|
27
|
+
},
|
|
28
|
+
"no-login": {
|
|
29
|
+
describe: "Create a passwordless role that cannot login",
|
|
30
|
+
boolean: true,
|
|
31
|
+
},
|
|
32
|
+
}), (args) => create(args))
|
|
33
|
+
.command("delete <role>", "Delete a role", (yargs) => yargs, (args) => deleteRole(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.listProjectBranchRoles(props.projectId, branchId);
|
|
40
|
+
writer(props).end(data.roles, {
|
|
41
|
+
fields: ROLES_FIELDS,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
export const create = async (props) => {
|
|
45
|
+
const branchId = await branchIdFromProps(props);
|
|
46
|
+
const { data } = await retryOnLock(() => props.apiClient.createProjectBranchRole(props.projectId, branchId, {
|
|
47
|
+
role: {
|
|
48
|
+
name: props.name,
|
|
49
|
+
no_login: props["no-login"],
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
52
|
+
writer(props).end(data.role, {
|
|
53
|
+
fields: ROLES_FIELDS,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
export const deleteRole = async (props) => {
|
|
57
|
+
const branchId = await branchIdFromProps(props);
|
|
58
|
+
const { data } = await retryOnLock(() => props.apiClient.deleteProjectBranchRole(props.projectId, branchId, props.role));
|
|
59
|
+
// A 204 (role already gone) carries no body; only a 200 returns the role.
|
|
60
|
+
if (data) {
|
|
61
|
+
writer(props).end(data.role, {
|
|
62
|
+
fields: ROLES_FIELDS,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
};
|