neon 3.0.0 → 3.1.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/README.md +70 -5
- package/dist/_chunks/auth_selection-DGgq6ifc.js +83 -0
- package/dist/_chunks/cmd_pipeline-CUbBO9U_.js +2818 -0
- package/dist/_chunks/credentials-MYdHdKah.js +188 -0
- package/dist/_chunks/env-NbA61JR3.js +585 -0
- package/dist/_chunks/env_services-Tz9G4JeT.js +531 -0
- package/dist/_chunks/paths-DMq0Lt7a.js +151 -0
- package/dist/_chunks/profiles-Ir29rqns.js +217 -0
- package/dist/_chunks/psql-DWH-kc69.js +2169 -0
- package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/_chunks/secure_file-BucZj4yQ.js +39 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +573 -690
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +639 -719
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +255 -305
- package/dist/commands/functions.js +275 -355
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +615 -846
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +2 -446
- package/dist/dev/functions.js +54 -68
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +2 -51
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +728 -984
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +2 -2193
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +2 -1148
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +260 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +2 -1253
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1303
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +2 -846
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +2 -2030
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +8 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +130 -189
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +39 -45
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +11 -6
- package/dist/_shared/auth_selection.js +0 -86
- package/dist/_shared/credentials.js +0 -209
- package/dist/_shared/env-core/env.js +0 -558
- package/dist/_shared/env-core/reuse-secrets.js +0 -223
- package/dist/_shared/paths.js +0 -148
- package/dist/_shared/profiles.js +0 -276
- package/dist/_shared/secure_file.js +0 -43
package/dist/storage_api.js
CHANGED
|
@@ -1,147 +1,133 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
// These endpoints are part of the Neon object-storage surface (the "Buckets"
|
|
4
|
-
// tag in the public API). They are not yet exposed as typed methods on
|
|
5
|
-
// `@neon/sdk`, so the request/response types and the thin call helpers live
|
|
6
|
-
// here. They are implemented on top of the API client's low-level `request()`
|
|
7
|
-
// method, which reuses the exact same authentication, base URL, headers and
|
|
8
|
-
// retry behaviour as every other neonctl command. When the SDK gains these
|
|
9
|
-
// methods, the call sites in `src/commands/bucket.ts` can switch over with no
|
|
10
|
-
// behavioural change.
|
|
1
|
+
//#region src/storage_api.ts
|
|
11
2
|
const bucketsPath = (projectId, branchId) => `/projects/${encodeURIComponent(projectId)}/branches/${encodeURIComponent(branchId)}/buckets`;
|
|
12
3
|
const bucketPath = (projectId, branchId, bucketName) => `${bucketsPath(projectId, branchId)}/${encodeURIComponent(bucketName)}`;
|
|
13
4
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
format: "json",
|
|
29
|
-
secure: true,
|
|
30
|
-
});
|
|
5
|
+
* Create a bucket on a branch.
|
|
6
|
+
*
|
|
7
|
+
* @request POST /projects/{project_id}/branches/{branch_id}/buckets
|
|
8
|
+
*/
|
|
9
|
+
const createProjectBranchBucket = (apiClient, { projectId, branchId, name, accessLevel }) => {
|
|
10
|
+
const body = { name };
|
|
11
|
+
if (accessLevel !== void 0) body.access_level = accessLevel;
|
|
12
|
+
return apiClient.request({
|
|
13
|
+
path: bucketsPath(projectId, branchId),
|
|
14
|
+
method: "POST",
|
|
15
|
+
body,
|
|
16
|
+
format: "json",
|
|
17
|
+
secure: true
|
|
18
|
+
});
|
|
31
19
|
};
|
|
32
20
|
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
21
|
+
* List the buckets on a branch.
|
|
22
|
+
*
|
|
23
|
+
* @request GET /projects/{project_id}/branches/{branch_id}/buckets
|
|
24
|
+
*/
|
|
25
|
+
const listProjectBranchBuckets = (apiClient, { projectId, branchId }) => apiClient.request({
|
|
26
|
+
path: bucketsPath(projectId, branchId),
|
|
27
|
+
method: "GET",
|
|
28
|
+
format: "json",
|
|
29
|
+
secure: true
|
|
42
30
|
});
|
|
43
31
|
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
* Delete a bucket from a branch.
|
|
33
|
+
*
|
|
34
|
+
* @request DELETE /projects/{project_id}/branches/{branch_id}/buckets/{bucket_name}
|
|
35
|
+
*/
|
|
36
|
+
const deleteProjectBranchBucket = (apiClient, { projectId, branchId, bucketName }) => apiClient.request({
|
|
37
|
+
path: bucketPath(projectId, branchId, bucketName),
|
|
38
|
+
method: "DELETE",
|
|
39
|
+
secure: true
|
|
52
40
|
});
|
|
53
41
|
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
42
|
+
* List objects (and collapsed folders) in a bucket on a branch.
|
|
43
|
+
*
|
|
44
|
+
* @request GET /projects/{project_id}/branches/{branch_id}/buckets/{bucket_name}/objects
|
|
45
|
+
*/
|
|
46
|
+
const listProjectBranchBucketObjects = (apiClient, { projectId, branchId, bucketName, ...query }) => apiClient.request({
|
|
47
|
+
path: `${bucketPath(projectId, branchId, bucketName)}/objects`,
|
|
48
|
+
method: "GET",
|
|
49
|
+
query,
|
|
50
|
+
format: "json",
|
|
51
|
+
secure: true
|
|
64
52
|
});
|
|
65
53
|
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
54
|
+
* Download an object's raw bytes from a bucket on a branch.
|
|
55
|
+
*
|
|
56
|
+
* The server returns the body as `application/octet-stream` with a
|
|
57
|
+
* `Content-Disposition: attachment` header; the helper requests the body as a
|
|
58
|
+
* stream (`responseType: 'stream'`), so `.data` is a Node `Readable` the caller
|
|
59
|
+
* can pipe straight to disk without buffering the whole object in memory. The
|
|
60
|
+
* response headers are returned alongside so the caller can derive a filename
|
|
61
|
+
* from `Content-Disposition`.
|
|
62
|
+
*
|
|
63
|
+
* The object key may contain `/`; it is percent-encoded into a single path
|
|
64
|
+
* segment so nested keys are routed to the `{object_key}` parameter.
|
|
65
|
+
*
|
|
66
|
+
* @request GET /projects/{project_id}/branches/{branch_id}/buckets/{bucket_name}/objects/{object_key}/download
|
|
67
|
+
*/
|
|
68
|
+
const getProjectBranchBucketObject = (apiClient, { projectId, branchId, bucketName, objectKey }) => apiClient.request({
|
|
69
|
+
path: `${bucketPath(projectId, branchId, bucketName)}/objects/${encodeURIComponent(objectKey)}/download`,
|
|
70
|
+
method: "GET",
|
|
71
|
+
format: "stream",
|
|
72
|
+
secure: true
|
|
85
73
|
});
|
|
86
74
|
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
75
|
+
* Delete an object from a bucket on a branch.
|
|
76
|
+
*
|
|
77
|
+
* The object key may contain `/`; it is percent-encoded into a single path
|
|
78
|
+
* segment so nested keys are routed to the `{object_key}` parameter.
|
|
79
|
+
*
|
|
80
|
+
* @request DELETE /projects/{project_id}/branches/{branch_id}/buckets/{bucket_name}/objects/{object_key}
|
|
81
|
+
*/
|
|
82
|
+
const deleteProjectBranchBucketObject = (apiClient, { projectId, branchId, bucketName, objectKey }) => apiClient.request({
|
|
83
|
+
path: `${bucketPath(projectId, branchId, bucketName)}/objects/${encodeURIComponent(objectKey)}`,
|
|
84
|
+
method: "DELETE",
|
|
85
|
+
secure: true
|
|
98
86
|
});
|
|
99
87
|
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
88
|
+
* Delete every object under a key prefix (folder) in a bucket on a branch.
|
|
89
|
+
*
|
|
90
|
+
* `prefix` must be non-empty and end with `/`; every object on this branch
|
|
91
|
+
* whose key starts with the prefix is soft-deleted in a single call.
|
|
92
|
+
*
|
|
93
|
+
* @request DELETE /projects/{project_id}/branches/{branch_id}/buckets/{bucket_name}/objects-by-prefix
|
|
94
|
+
*/
|
|
95
|
+
const deleteProjectBranchBucketObjectsByPrefix = (apiClient, { projectId, branchId, bucketName, prefix }) => apiClient.request({
|
|
96
|
+
path: `${bucketPath(projectId, branchId, bucketName)}/objects-by-prefix`,
|
|
97
|
+
method: "DELETE",
|
|
98
|
+
query: { prefix },
|
|
99
|
+
format: "json",
|
|
100
|
+
secure: true
|
|
113
101
|
});
|
|
114
102
|
/**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
body,
|
|
144
|
-
format: "json",
|
|
145
|
-
secure: true,
|
|
146
|
-
});
|
|
103
|
+
* Request a presigned PUT URL for uploading an object to a bucket on a branch.
|
|
104
|
+
*
|
|
105
|
+
* Returns the URL, the headers that must accompany the PUT for the signature to
|
|
106
|
+
* verify, and the expiry. The actual upload (a `PUT` to the returned `url` with
|
|
107
|
+
* the returned `headers` and the file stream) is performed by the caller, NOT
|
|
108
|
+
* through this api-client, since it targets the branch S3 data-plane endpoint
|
|
109
|
+
* rather than the console API. No SigV4 or credential handling happens here.
|
|
110
|
+
*
|
|
111
|
+
* The object key may contain `/`; it is percent-encoded into a single path
|
|
112
|
+
* segment so nested keys are routed to the `{object_key}` parameter.
|
|
113
|
+
*
|
|
114
|
+
* This targets the unified presign endpoint, passing `operation: "upload"` to
|
|
115
|
+
* request a presigned PUT. (The same endpoint also serves `download`, but that
|
|
116
|
+
* path is API-only and has no neonctl command.)
|
|
117
|
+
*
|
|
118
|
+
* @request POST /projects/{project_id}/branches/{branch_id}/buckets/{bucket_name}/objects/{object_key}/presign
|
|
119
|
+
*/
|
|
120
|
+
const presignUpload = (apiClient, { projectId, branchId, bucketName, objectKey, contentType, expiresInSeconds }) => {
|
|
121
|
+
const body = { operation: "upload" };
|
|
122
|
+
if (contentType !== void 0) body.content_type = contentType;
|
|
123
|
+
if (expiresInSeconds !== void 0) body.expires_in_seconds = expiresInSeconds;
|
|
124
|
+
return apiClient.request({
|
|
125
|
+
path: `${bucketPath(projectId, branchId, bucketName)}/objects/${encodeURIComponent(objectKey)}/presign`,
|
|
126
|
+
method: "POST",
|
|
127
|
+
body,
|
|
128
|
+
format: "json",
|
|
129
|
+
secure: true
|
|
130
|
+
});
|
|
147
131
|
};
|
|
132
|
+
//#endregion
|
|
133
|
+
export { createProjectBranchBucket, deleteProjectBranchBucket, deleteProjectBranchBucketObject, deleteProjectBranchBucketObjectsByPrefix, getProjectBranchBucketObject, listProjectBranchBucketObjects, listProjectBranchBuckets, presignUpload };
|
|
@@ -1,121 +1,102 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createServer } from "node:http";
|
|
1
|
+
import { log } from "../log.js";
|
|
3
2
|
import { join } from "node:path";
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { fork } from "node:child_process";
|
|
4
5
|
import emocks from "emocks";
|
|
5
6
|
import express from "express";
|
|
6
7
|
import strip from "strip-ansi";
|
|
7
|
-
import { expect, test as
|
|
8
|
-
|
|
8
|
+
import { expect, test as test$1 } from "vitest";
|
|
9
|
+
//#region src/test_utils/fixtures.ts
|
|
9
10
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
* Reserve a localhost port and close its listener, returning a URL that is guaranteed to
|
|
12
|
+
* refuse connections right now. Lets a test drive the CLI into a real `ECONNREFUSED`
|
|
13
|
+
* (the same shape a network blip produces) deterministically and fast.
|
|
14
|
+
*/
|
|
14
15
|
const reserveClosedPort = () => new Promise((resolve, reject) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
resolve(`http://127.0.0.1:${port}`);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
16
|
+
const probe = createServer();
|
|
17
|
+
probe.on("error", reject);
|
|
18
|
+
probe.listen(0, "127.0.0.1", () => {
|
|
19
|
+
const { port } = probe.address();
|
|
20
|
+
probe.close((err) => {
|
|
21
|
+
if (err) reject(err);
|
|
22
|
+
else resolve(`http://127.0.0.1:${port}`);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
28
25
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
expect(strip(error).replace(/\s+/g, " ").trim()).toEqual(typeof options.stderr === "string"
|
|
104
|
-
? options.stderr
|
|
105
|
-
.toString()
|
|
106
|
-
.replace(/\s+/g, " ")
|
|
107
|
-
: options.stderr);
|
|
108
|
-
}
|
|
109
|
-
resolve();
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
reject(err instanceof Error ? err : new Error(String(err)));
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
}).catch((err) => {
|
|
116
|
-
log.error(err);
|
|
117
|
-
throw err;
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
},
|
|
26
|
+
const test = test$1.extend({
|
|
27
|
+
runMockServer: async ({}, use) => {
|
|
28
|
+
let startedServer;
|
|
29
|
+
await use(async (mockDir) => {
|
|
30
|
+
const app = express();
|
|
31
|
+
app.use(express.json());
|
|
32
|
+
app.use("/", emocks(join(process.cwd(), "mocks", mockDir), { "404": (_req, res) => res.status(404).send({ message: "Not Found" }) }));
|
|
33
|
+
const server = await new Promise((resolve) => {
|
|
34
|
+
const s = app.listen(0, () => {
|
|
35
|
+
log.debug("Mock server listening at %d", s.address().port);
|
|
36
|
+
resolve(s);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
startedServer = server;
|
|
40
|
+
return server;
|
|
41
|
+
});
|
|
42
|
+
const server = startedServer;
|
|
43
|
+
if (server) await new Promise((resolve, reject) => {
|
|
44
|
+
server.close((err) => {
|
|
45
|
+
if (err) reject(err instanceof Error ? err : new Error(String(err)));
|
|
46
|
+
else resolve();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
testCliCommand: async ({ runMockServer }, use) => {
|
|
51
|
+
await use(async (args, options = {}) => {
|
|
52
|
+
const apiHost = options.unreachableHost ? await reserveClosedPort() : `http://localhost:${(await runMockServer(options.mockDir || "main")).address().port}`;
|
|
53
|
+
let output = "";
|
|
54
|
+
let error = "";
|
|
55
|
+
const cp = fork(join(process.cwd(), "./dist/index.js"), [
|
|
56
|
+
"--api-host",
|
|
57
|
+
apiHost,
|
|
58
|
+
"--output",
|
|
59
|
+
options.output ?? (options.outputTable ? "table" : "yaml"),
|
|
60
|
+
"--api-key",
|
|
61
|
+
"test-key",
|
|
62
|
+
"--no-analytics",
|
|
63
|
+
...args
|
|
64
|
+
], {
|
|
65
|
+
stdio: "pipe",
|
|
66
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
67
|
+
env: {
|
|
68
|
+
PATH: `${join(process.cwd(), "mocks/bin")}:${process.env.PATH}`,
|
|
69
|
+
...options.env ?? {}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
cp.stdout?.on("data", (data) => {
|
|
74
|
+
output += data.toString();
|
|
75
|
+
});
|
|
76
|
+
cp.stderr?.on("data", (data) => {
|
|
77
|
+
error += data.toString();
|
|
78
|
+
log.error(data.toString());
|
|
79
|
+
});
|
|
80
|
+
cp.on("error", (err) => {
|
|
81
|
+
log.error(err);
|
|
82
|
+
throw err;
|
|
83
|
+
});
|
|
84
|
+
cp.on("close", (code) => {
|
|
85
|
+
try {
|
|
86
|
+
expect(code).toBe(options?.code ?? 0);
|
|
87
|
+
expect(output).toMatchSnapshot();
|
|
88
|
+
if (options.stderr !== void 0) expect(strip(error).replace(/\s+/g, " ").trim()).toEqual(typeof options.stderr === "string" ? options.stderr.toString().replace(/\s+/g, " ") : options.stderr);
|
|
89
|
+
resolve();
|
|
90
|
+
} catch (err) {
|
|
91
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}).catch((err) => {
|
|
95
|
+
log.error(err);
|
|
96
|
+
throw err;
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
121
100
|
});
|
|
101
|
+
//#endregion
|
|
102
|
+
export { test };
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { log } from "../log.js";
|
|
1
2
|
import { OAuth2Server } from "oauth2-mock-server";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
//#region src/test_utils/oauth_server.ts
|
|
4
|
+
const startOauthServer = async () => {
|
|
5
|
+
const server = new OAuth2Server();
|
|
6
|
+
await server.issuer.keys.generate("RS256");
|
|
7
|
+
await server.start(0, "localhost");
|
|
8
|
+
log.debug("Started OAuth server on port %d", server.address().port);
|
|
9
|
+
return server;
|
|
9
10
|
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { startOauthServer };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
//#region src/test_utils/project_dir.ts
|
|
5
|
+
/** The lockfile each package manager is recognised by. */
|
|
6
|
+
const LOCKFILE = {
|
|
7
|
+
npm: "package-lock.json",
|
|
8
|
+
pnpm: "pnpm-lock.yaml",
|
|
9
|
+
yarn: "yarn.lock",
|
|
10
|
+
bun: "bun.lock"
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A throwaway project directory that `resolvePackageManager` will read as `pm`.
|
|
14
|
+
*
|
|
15
|
+
* The `.git` marker models a repository root, which is what a real project has
|
|
16
|
+
* and what the lockfile walk uses as its boundary. Tests that need the
|
|
17
|
+
* no-repository case should build the directory themselves rather than reach for
|
|
18
|
+
* this.
|
|
19
|
+
*/
|
|
20
|
+
const makeProjectDir = (pm) => {
|
|
21
|
+
const dir = mkdtempSync(join(tmpdir(), "neon-project-"));
|
|
22
|
+
mkdirSync(join(dir, ".git"));
|
|
23
|
+
writeFileSync(join(dir, LOCKFILE[pm]), "");
|
|
24
|
+
return {
|
|
25
|
+
dir,
|
|
26
|
+
cleanup: () => rmSync(dir, {
|
|
27
|
+
recursive: true,
|
|
28
|
+
force: true
|
|
29
|
+
})
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { makeProjectDir };
|