neon 4.16.0 → 4.17.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 +7 -6
- package/dist/_chunks/{env-DsakkOVZ.js → env-B75xufe_.js} +57 -64
- package/dist/_chunks/{env_services-CAWrZTWa.js → env_services-CbARRnq9.js} +66 -11
- package/dist/auth_recovery.js +61 -0
- package/dist/commands/bootstrap.js +30 -17
- package/dist/commands/branches.js +3 -3
- package/dist/commands/checkout.js +1 -1
- package/dist/commands/claim.js +3 -3
- package/dist/commands/config.js +2 -2
- package/dist/commands/connection_string.js +1 -1
- package/dist/commands/dev.js +9 -11
- package/dist/commands/env.js +8 -8
- package/dist/commands/index.js +3 -3
- package/dist/commands/init.js +47 -26
- package/dist/commands/ip_allow.js +1 -1
- package/dist/commands/link.js +20 -17
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/plugins.js +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/dev/env.js +1 -1
- package/dist/env_services.js +1 -1
- package/dist/help.js +121 -66
- package/dist/index.js +4 -60
- package/dist/init/link.js +38 -0
- package/dist/init/wizard.js +13 -1
- package/dist/test_utils/fixtures.js +1 -0
- package/dist/utils/help_text.js +32 -4
- package/dist/writer.js +2 -1
- package/package.json +5 -5
package/dist/help.js
CHANGED
|
@@ -1,8 +1,75 @@
|
|
|
1
|
+
import { globalOptionsTrailer, helpWidth, wrapHelpText } from "./utils/help_text.js";
|
|
1
2
|
import { consumeBlockIfMatches, consumeNextMatching, drawPointer, splitColumns } from "./utils/ui.js";
|
|
2
3
|
import chalk from "chalk";
|
|
3
4
|
import cliui from "cliui";
|
|
4
5
|
//#region src/help.ts
|
|
5
6
|
const SPACE_WIDTH = 20;
|
|
7
|
+
const DESCRIPTION_GUTTER = 4;
|
|
8
|
+
const wrapDescription = (text) => wrapHelpText(text, Math.max(1, helpWidth() - SPACE_WIDTH - DESCRIPTION_GUTTER));
|
|
9
|
+
const isGlobalOptionsHeader = (header) => /global options:/i.test(header);
|
|
10
|
+
const isTopLevelUsage = (usage) => /^\S+ <command>/.test(usage);
|
|
11
|
+
const renderOptionBlock = (optionsBlock) => {
|
|
12
|
+
const result = [];
|
|
13
|
+
const [header, ...body] = optionsBlock;
|
|
14
|
+
if (header === void 0) return result;
|
|
15
|
+
result.push(header);
|
|
16
|
+
body.forEach((line) => {
|
|
17
|
+
const [option, description] = splitColumns(line);
|
|
18
|
+
const ui = cliui({
|
|
19
|
+
width: helpWidth(),
|
|
20
|
+
wrap: false
|
|
21
|
+
});
|
|
22
|
+
if (option.startsWith("-")) {
|
|
23
|
+
ui.div({
|
|
24
|
+
text: chalk.green(option),
|
|
25
|
+
padding: [
|
|
26
|
+
0,
|
|
27
|
+
0,
|
|
28
|
+
0,
|
|
29
|
+
0
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
ui.div({
|
|
33
|
+
text: chalk.gray(drawPointer(SPACE_WIDTH)),
|
|
34
|
+
width: SPACE_WIDTH,
|
|
35
|
+
padding: [
|
|
36
|
+
0,
|
|
37
|
+
2,
|
|
38
|
+
0,
|
|
39
|
+
0
|
|
40
|
+
]
|
|
41
|
+
}, {
|
|
42
|
+
text: chalk.rgb(210, 210, 210)(wrapDescription(description ?? "")),
|
|
43
|
+
padding: [
|
|
44
|
+
0,
|
|
45
|
+
0,
|
|
46
|
+
0,
|
|
47
|
+
0
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
} else ui.div({
|
|
51
|
+
padding: [
|
|
52
|
+
0,
|
|
53
|
+
0,
|
|
54
|
+
0,
|
|
55
|
+
0
|
|
56
|
+
],
|
|
57
|
+
text: "",
|
|
58
|
+
width: SPACE_WIDTH
|
|
59
|
+
}, {
|
|
60
|
+
text: chalk.rgb(210, 210, 210)(wrapDescription(option)),
|
|
61
|
+
padding: [
|
|
62
|
+
0,
|
|
63
|
+
0,
|
|
64
|
+
0,
|
|
65
|
+
0
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
|
+
result.push(ui.toString());
|
|
69
|
+
});
|
|
70
|
+
result.push("");
|
|
71
|
+
return result;
|
|
72
|
+
};
|
|
6
73
|
const formatHelp = (help) => {
|
|
7
74
|
const lines = help.split("\n");
|
|
8
75
|
const result = [];
|
|
@@ -11,11 +78,16 @@ const formatHelp = (help) => {
|
|
|
11
78
|
result.push(chalk.bold(topLevelCommand.replace("[options]", chalk.reset.green("[options]"))));
|
|
12
79
|
result.push("");
|
|
13
80
|
}
|
|
14
|
-
const
|
|
15
|
-
|
|
81
|
+
const consumeCommands = () => {
|
|
82
|
+
const commandsBlock = consumeBlockIfMatches(lines, /^Commands:/);
|
|
83
|
+
if (commandsBlock.length === 0) return;
|
|
16
84
|
const header = commandsBlock.shift();
|
|
85
|
+
if (header === void 0) return;
|
|
17
86
|
result.push(header);
|
|
18
|
-
const ui = cliui({
|
|
87
|
+
const ui = cliui({
|
|
88
|
+
width: helpWidth(),
|
|
89
|
+
wrap: false
|
|
90
|
+
});
|
|
19
91
|
commandsBlock.forEach((line) => {
|
|
20
92
|
if (/^\s{3,}/.exec(line)) {
|
|
21
93
|
ui.div({
|
|
@@ -28,7 +100,7 @@ const formatHelp = (help) => {
|
|
|
28
100
|
0
|
|
29
101
|
]
|
|
30
102
|
}, {
|
|
31
|
-
text: line.trim(),
|
|
103
|
+
text: wrapDescription(line.trim()),
|
|
32
104
|
padding: [
|
|
33
105
|
0,
|
|
34
106
|
0,
|
|
@@ -54,7 +126,7 @@ const formatHelp = (help) => {
|
|
|
54
126
|
0
|
|
55
127
|
]
|
|
56
128
|
}, {
|
|
57
|
-
text: description,
|
|
129
|
+
text: wrapDescription(description),
|
|
58
130
|
padding: [
|
|
59
131
|
0,
|
|
60
132
|
0,
|
|
@@ -65,12 +137,17 @@ const formatHelp = (help) => {
|
|
|
65
137
|
});
|
|
66
138
|
result.push(ui.toString());
|
|
67
139
|
result.push("");
|
|
68
|
-
}
|
|
69
|
-
const
|
|
70
|
-
|
|
140
|
+
};
|
|
141
|
+
const consumePositionals = () => {
|
|
142
|
+
const positionalsBlock = consumeBlockIfMatches(lines, /Positionals:/);
|
|
143
|
+
if (positionalsBlock.length === 0) return;
|
|
71
144
|
const header = positionalsBlock.shift();
|
|
145
|
+
if (header === void 0) return;
|
|
72
146
|
result.push(header);
|
|
73
|
-
const ui = cliui({
|
|
147
|
+
const ui = cliui({
|
|
148
|
+
width: helpWidth(),
|
|
149
|
+
wrap: false
|
|
150
|
+
});
|
|
74
151
|
positionalsBlock.forEach((line) => {
|
|
75
152
|
const [positional, description] = splitColumns(line);
|
|
76
153
|
ui.div({
|
|
@@ -83,7 +160,7 @@ const formatHelp = (help) => {
|
|
|
83
160
|
0
|
|
84
161
|
]
|
|
85
162
|
}, {
|
|
86
|
-
text: description,
|
|
163
|
+
text: wrapDescription(description),
|
|
87
164
|
padding: [
|
|
88
165
|
0,
|
|
89
166
|
0,
|
|
@@ -94,73 +171,42 @@ const formatHelp = (help) => {
|
|
|
94
171
|
});
|
|
95
172
|
result.push(ui.toString());
|
|
96
173
|
result.push("");
|
|
97
|
-
}
|
|
174
|
+
};
|
|
175
|
+
consumeCommands();
|
|
176
|
+
consumePositionals();
|
|
98
177
|
const descriptionBlock = consumeBlockIfMatches(lines, /^(?!.*options:)/i);
|
|
99
178
|
if (descriptionBlock.length > 0) {
|
|
100
179
|
result.push(...descriptionBlock);
|
|
101
180
|
result.push("");
|
|
102
181
|
}
|
|
182
|
+
consumeCommands();
|
|
183
|
+
consumePositionals();
|
|
184
|
+
const optionBlocks = [];
|
|
103
185
|
while (true) {
|
|
104
186
|
const optionsBlock = consumeBlockIfMatches(lines, /.*options:/i);
|
|
105
187
|
if (optionsBlock.length === 0) break;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
});
|
|
120
|
-
ui.div({
|
|
121
|
-
text: chalk.gray(drawPointer(SPACE_WIDTH)),
|
|
122
|
-
width: SPACE_WIDTH,
|
|
123
|
-
padding: [
|
|
124
|
-
0,
|
|
125
|
-
2,
|
|
126
|
-
0,
|
|
127
|
-
0
|
|
128
|
-
]
|
|
129
|
-
}, {
|
|
130
|
-
text: chalk.rgb(210, 210, 210)(description ?? ""),
|
|
131
|
-
padding: [
|
|
132
|
-
0,
|
|
133
|
-
0,
|
|
134
|
-
0,
|
|
135
|
-
0
|
|
136
|
-
]
|
|
137
|
-
});
|
|
138
|
-
} else ui.div({
|
|
139
|
-
padding: [
|
|
140
|
-
0,
|
|
141
|
-
0,
|
|
142
|
-
0,
|
|
143
|
-
0
|
|
144
|
-
],
|
|
145
|
-
text: "",
|
|
146
|
-
width: SPACE_WIDTH
|
|
147
|
-
}, {
|
|
148
|
-
text: chalk.rgb(210, 210, 210)(option),
|
|
149
|
-
padding: [
|
|
150
|
-
0,
|
|
151
|
-
0,
|
|
152
|
-
0,
|
|
153
|
-
0
|
|
154
|
-
]
|
|
155
|
-
});
|
|
156
|
-
result.push(ui.toString());
|
|
157
|
-
});
|
|
188
|
+
optionBlocks.push(optionsBlock);
|
|
189
|
+
}
|
|
190
|
+
for (const block of optionBlocks) {
|
|
191
|
+
const header = block[0];
|
|
192
|
+
if (header !== void 0 && !isGlobalOptionsHeader(header)) result.push(...renderOptionBlock(block));
|
|
193
|
+
}
|
|
194
|
+
const globalBlocks = optionBlocks.filter((block) => {
|
|
195
|
+
const header = block[0];
|
|
196
|
+
return header !== void 0 && isGlobalOptionsHeader(header);
|
|
197
|
+
});
|
|
198
|
+
if (topLevelCommand !== null && isTopLevelUsage(topLevelCommand)) for (const block of globalBlocks) result.push(...renderOptionBlock(block));
|
|
199
|
+
else if (globalBlocks.length > 0 && topLevelCommand !== null) {
|
|
200
|
+
result.push(globalOptionsTrailer(topLevelCommand));
|
|
158
201
|
result.push("");
|
|
159
202
|
}
|
|
160
203
|
const exampleBlock = consumeBlockIfMatches(lines, /Examples:/);
|
|
161
204
|
if (exampleBlock.length > 0) {
|
|
162
205
|
result.push(exampleBlock.shift());
|
|
163
|
-
const ui = cliui({
|
|
206
|
+
const ui = cliui({
|
|
207
|
+
width: helpWidth(),
|
|
208
|
+
wrap: false
|
|
209
|
+
});
|
|
164
210
|
for (const line of exampleBlock) {
|
|
165
211
|
const [command, description] = splitColumns(line);
|
|
166
212
|
ui.div({
|
|
@@ -173,7 +219,7 @@ const formatHelp = (help) => {
|
|
|
173
219
|
]
|
|
174
220
|
});
|
|
175
221
|
ui.div({
|
|
176
|
-
text: chalk.reset(description),
|
|
222
|
+
text: chalk.reset(wrapDescription(description)),
|
|
177
223
|
padding: [
|
|
178
224
|
0,
|
|
179
225
|
0,
|
|
@@ -188,7 +234,16 @@ const formatHelp = (help) => {
|
|
|
188
234
|
};
|
|
189
235
|
const showHelp = async (argv) => {
|
|
190
236
|
const help = await argv.getHelp();
|
|
191
|
-
|
|
237
|
+
const text = `${formatHelp(help).join("\n")}\n`;
|
|
238
|
+
await new Promise((resolve, reject) => {
|
|
239
|
+
process.stdout.write(text, (err) => {
|
|
240
|
+
if (err) {
|
|
241
|
+
reject(err);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
resolve();
|
|
245
|
+
});
|
|
246
|
+
});
|
|
192
247
|
process.exit(0);
|
|
193
248
|
};
|
|
194
249
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { t as storeFor } from "./_chunks/credential_io-D8AR-jvB.js";
|
|
2
1
|
import { log } from "./log.js";
|
|
3
2
|
import pkg_default from "./pkg.js";
|
|
4
3
|
import { isNeonApiError, messageFromBody } from "./api.js";
|
|
5
|
-
import {
|
|
4
|
+
import { getAuthContext } from "./auth_context.js";
|
|
6
5
|
import { r as defaultDir } from "./_chunks/paths-DMq0Lt7a.js";
|
|
7
6
|
import { ensureConfigDir } from "./config.js";
|
|
8
7
|
import { currentContextFile, enrichFromContext } from "./context.js";
|
|
9
8
|
import { analyticsMiddleware, closeAnalytics, getAnalyticsEventProperties, initAnalyticsClientMiddleware, sendError, trackEvent } from "./analytics.js";
|
|
10
9
|
import { NETWORK_ERROR_MESSAGE, isNetworkError, matchErrorCode } from "./errors.js";
|
|
11
10
|
import { AuthRefreshError, defaultClientID } from "./auth.js";
|
|
11
|
+
import { ensureAuth } from "./commands/auth.js";
|
|
12
|
+
import { recoverFrom401 } from "./auth_recovery.js";
|
|
12
13
|
import { getCliName } from "./utils/cli_name.js";
|
|
13
14
|
import { showHelp } from "./help.js";
|
|
14
|
-
import { ensureAuth, isAccessTokenUsable, refreshStoredCredentials } from "./commands/auth.js";
|
|
15
15
|
import { rewriteUnknownAgentArg } from "./init/plan.js";
|
|
16
16
|
import commands_default from "./commands/index.js";
|
|
17
17
|
import { fillInArgs, resolveApiKeyFromEnv } from "./utils/middlewares.js";
|
|
@@ -100,6 +100,7 @@ builder = builder.scriptName(pkg_default.name).locale("en").usage("$0 <command>
|
|
|
100
100
|
},
|
|
101
101
|
"context-file": {
|
|
102
102
|
describe: "Context file",
|
|
103
|
+
group: "Global options:",
|
|
103
104
|
type: "string",
|
|
104
105
|
default: currentContextFile
|
|
105
106
|
},
|
|
@@ -124,63 +125,6 @@ builder = builder.scriptName(pkg_default.name).locale("en").usage("$0 <command>
|
|
|
124
125
|
}).alias("help", "h").middleware(async (args) => {
|
|
125
126
|
if (args.help || args._.length === 1 && !NO_SUBCOMMANDS_VERBS.includes(args._[0])) await showHelp(builder);
|
|
126
127
|
}).middleware(ensureAuth).middleware(enrichFromContext).middleware(analyticsMiddleware).command(commands_default).strictCommands().version(pkg_default.version).group("version", "Global options:").alias("version", "v").completion().scriptName(getCliName()).epilog("For more information, visit https://neon.com/docs/reference/neon-cli").wrap(null).fail(false);
|
|
127
|
-
function supersededOnDisk(rejectedToken) {
|
|
128
|
-
if (rejectedToken === void 0) return false;
|
|
129
|
-
const context = getAuthContext();
|
|
130
|
-
if (context === null) return false;
|
|
131
|
-
const at = locationFromContext(context);
|
|
132
|
-
if (at === null) return false;
|
|
133
|
-
try {
|
|
134
|
-
const loaded = storeFor(context.configDir).read(at);
|
|
135
|
-
return loaded !== null && loaded.credentials.access_token !== rejectedToken && isAccessTokenUsable(loaded.credentials, Date.now());
|
|
136
|
-
} catch {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
async function recoverFrom401(canRetry) {
|
|
141
|
-
const context = getAuthContext();
|
|
142
|
-
if (context === null || context.source !== "stored-credentials") {
|
|
143
|
-
log.error(authFailureMessage(context));
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
if (context.refreshed === true) {
|
|
147
|
-
log.error(authFailureMessage(context));
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
if (!canRetry) {
|
|
151
|
-
log.error(authFailureMessage(context));
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
if (supersededOnDisk(context.accessToken)) {
|
|
155
|
-
log.debug("The rejected token has already been replaced on disk; retrying with the current one");
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
const at = locationFromContext(context);
|
|
159
|
-
if (at === null || context.oauthHost === void 0 || context.clientId === void 0) {
|
|
160
|
-
log.error(authFailureMessage(context));
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
try {
|
|
164
|
-
if (await refreshStoredCredentials(at, {
|
|
165
|
-
apiHost: "",
|
|
166
|
-
oauthHost: context.oauthHost,
|
|
167
|
-
clientId: context.clientId,
|
|
168
|
-
configDir: context.configDir
|
|
169
|
-
})) {
|
|
170
|
-
log.debug("Refreshed the stored session after a 401; retrying");
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
} catch (err) {
|
|
174
|
-
if (err instanceof AuthRefreshError) {
|
|
175
|
-
log.error(err.message);
|
|
176
|
-
if (err.terminal) log.error(`Run \`neon auth --profile ${context.profile ?? "DEFAULT"}\` to sign in again.`);
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
log.debug("Refresh after 401 failed: %s", err instanceof Error ? err.message : "unknown error");
|
|
180
|
-
}
|
|
181
|
-
log.error(authFailureMessage(context));
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
128
|
async function handleError(msg, err, canRetry) {
|
|
185
129
|
if (process.argv.some((arg) => arg === "--help" || arg === "-h")) {
|
|
186
130
|
await showHelp(builder);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isNeonApiError } from "../api.js";
|
|
2
|
+
import { r as defaultDir } from "../_chunks/paths-DMq0Lt7a.js";
|
|
3
|
+
import "../config.js";
|
|
4
|
+
import "../auth.js";
|
|
5
|
+
import { ensureAuth } from "../commands/auth.js";
|
|
6
|
+
import { recoverFrom401 } from "../auth_recovery.js";
|
|
7
|
+
import { runLink } from "../commands/link.js";
|
|
8
|
+
//#region src/init/link.ts
|
|
9
|
+
const isUnauthorized = (error) => isNeonApiError(error) && error.status === 401;
|
|
10
|
+
const authenticationFailed = () => /* @__PURE__ */ new Error("Authentication failed.");
|
|
11
|
+
const runAuthenticatedLink = async (props) => {
|
|
12
|
+
const authenticated = {
|
|
13
|
+
...props,
|
|
14
|
+
_: ["link"],
|
|
15
|
+
configDir: props.configDir ?? defaultDir,
|
|
16
|
+
oauthHost: props.oauthHost ?? process.env.NEON_OAUTH_HOST ?? "https://oauth2.neon.tech",
|
|
17
|
+
clientId: props.clientId ?? "neonctl",
|
|
18
|
+
help: false
|
|
19
|
+
};
|
|
20
|
+
await ensureAuth(authenticated);
|
|
21
|
+
try {
|
|
22
|
+
await runLink(authenticated);
|
|
23
|
+
return;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (!isUnauthorized(error)) throw error;
|
|
26
|
+
if (!await recoverFrom401(true)) throw authenticationFailed();
|
|
27
|
+
}
|
|
28
|
+
await ensureAuth(authenticated);
|
|
29
|
+
try {
|
|
30
|
+
await runLink(authenticated);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (!isUnauthorized(error)) throw error;
|
|
33
|
+
await recoverFrom401(false);
|
|
34
|
+
throw authenticationFailed();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { runAuthenticatedLink };
|
package/dist/init/wizard.js
CHANGED
|
@@ -91,5 +91,17 @@ const pickInitConfigInteractively = async () => {
|
|
|
91
91
|
if (value === void 0) throw new Error("Aborted.");
|
|
92
92
|
return value === true;
|
|
93
93
|
};
|
|
94
|
+
const pickInitLinkInteractively = async () => {
|
|
95
|
+
requireInteractive();
|
|
96
|
+
const { value } = await prompts({
|
|
97
|
+
onState: restoreCursorOnAbort,
|
|
98
|
+
type: "confirm",
|
|
99
|
+
name: "value",
|
|
100
|
+
message: "Link this project to a Neon project now?",
|
|
101
|
+
initial: true
|
|
102
|
+
});
|
|
103
|
+
if (value === void 0) throw new Error("Aborted.");
|
|
104
|
+
return value === true;
|
|
105
|
+
};
|
|
94
106
|
//#endregion
|
|
95
|
-
export { INIT_TEMPLATE_PICKER_INITIAL, initTemplatePickerChoices, pickAgentSetupInteractively, pickInitConfigInteractively, pickInitTemplateInteractively };
|
|
107
|
+
export { INIT_TEMPLATE_PICKER_INITIAL, initTemplatePickerChoices, pickAgentSetupInteractively, pickInitConfigInteractively, pickInitLinkInteractively, pickInitTemplateInteractively };
|
|
@@ -85,6 +85,7 @@ const test = test$1.extend({
|
|
|
85
85
|
expect(code).toBe(options?.code ?? 0);
|
|
86
86
|
if (options.snapshot !== false) expect(output).toMatchSnapshot();
|
|
87
87
|
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);
|
|
88
|
+
if (options.stdout !== void 0) expect(strip(output).replace(/\s+/g, " ").trim()).toEqual(typeof options.stdout === "string" ? options.stdout.toString().replace(/\s+/g, " ") : options.stdout);
|
|
88
89
|
resolve({
|
|
89
90
|
stdout: output,
|
|
90
91
|
stderr: error,
|
package/dist/utils/help_text.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { parseColumns } from "../human_table.js";
|
|
1
2
|
//#region src/utils/help_text.ts
|
|
2
3
|
const HELP_WRAP = 78;
|
|
3
4
|
const WRAP_INDENT = " ";
|
|
4
5
|
const helpWidth = () => {
|
|
5
|
-
const
|
|
6
|
-
if (typeof
|
|
7
|
-
|
|
6
|
+
const fromStdout = process.stdout.columns;
|
|
7
|
+
if (typeof fromStdout === "number" && Number.isFinite(fromStdout) && fromStdout >= 1) return Math.max(24, fromStdout - 1);
|
|
8
|
+
const fromEnv = parseColumns(process.env.COLUMNS);
|
|
9
|
+
if (fromEnv !== void 0) return Math.max(24, fromEnv - 1);
|
|
10
|
+
return 78;
|
|
8
11
|
};
|
|
9
12
|
const helpCsv = (label, items, width = helpWidth()) => {
|
|
10
13
|
if (items.length === 0) return "";
|
|
@@ -24,6 +27,31 @@ const helpCsv = (label, items, width = helpWidth()) => {
|
|
|
24
27
|
lines.push(line);
|
|
25
28
|
return lines.join("\n");
|
|
26
29
|
};
|
|
30
|
+
const wrapHelpText = (text, width) => {
|
|
31
|
+
if (width < 1) return text;
|
|
32
|
+
const words = text.trim().split(/\s+/).filter((word) => word !== "");
|
|
33
|
+
if (words.length === 0) return text;
|
|
34
|
+
const lines = [];
|
|
35
|
+
let line = "";
|
|
36
|
+
for (const word of words) {
|
|
37
|
+
if (line === "") {
|
|
38
|
+
line = word;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (line.length + 1 + word.length <= width) {
|
|
42
|
+
line = `${line} ${word}`;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
lines.push(line);
|
|
46
|
+
line = word;
|
|
47
|
+
}
|
|
48
|
+
if (line !== "") lines.push(line);
|
|
49
|
+
return lines.join("\n");
|
|
50
|
+
};
|
|
27
51
|
const helpEpilogue = (...blocks) => ["", ...blocks.filter((block) => block !== "")].join("\n");
|
|
52
|
+
const globalOptionsTrailer = (usage) => {
|
|
53
|
+
const cli = usage.trim().split(/\s+/)[0];
|
|
54
|
+
return `Global options: see ${cli === "" ? "neon" : cli} --help`;
|
|
55
|
+
};
|
|
28
56
|
//#endregion
|
|
29
|
-
export { HELP_WRAP, helpCsv, helpEpilogue, helpWidth };
|
|
57
|
+
export { HELP_WRAP, globalOptionsTrailer, helpCsv, helpEpilogue, helpWidth, wrapHelpText };
|
package/dist/writer.js
CHANGED
|
@@ -7,7 +7,8 @@ const writeYaml = (chunks) => {
|
|
|
7
7
|
return YAML.stringify(chunks.length === 1 ? chunks[0].data : Object.fromEntries(chunks.map(({ config, data }, idx) => [config.title ? toSnakeCase(config.title) : idx, data])), null, 2);
|
|
8
8
|
};
|
|
9
9
|
const writeJson = (chunks) => {
|
|
10
|
-
|
|
10
|
+
const json = JSON.stringify(chunks.length === 1 ? chunks[0].data : Object.fromEntries(chunks.map(({ config, data }, idx) => [config.title ? toSnakeCase(config.title) : idx, data])), null, 2);
|
|
11
|
+
return json === void 0 ? json : `${json}\n`;
|
|
11
12
|
};
|
|
12
13
|
const writeTable = (chunks, out, width) => {
|
|
13
14
|
chunks.forEach(({ data, config }, i) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neon",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.1",
|
|
4
4
|
"description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
"yaml": "^2.9.0",
|
|
64
64
|
"yargs": "17.7.2",
|
|
65
65
|
"yoctocolors": "^2.1.2",
|
|
66
|
-
"@neon/config": "1.
|
|
67
|
-
"@neon/
|
|
68
|
-
"@neon/
|
|
66
|
+
"@neon/config": "1.4.0",
|
|
67
|
+
"@neon/sdk": "4.1.0",
|
|
68
|
+
"@neon/config-runtime": "1.3.0"
|
|
69
69
|
},
|
|
70
70
|
"optionalDependencies": {
|
|
71
71
|
"@napi-rs/keyring": "1.3.0",
|
|
@@ -98,8 +98,8 @@
|
|
|
98
98
|
"typescript": "^5.9.0",
|
|
99
99
|
"vitest": "^3.0.9",
|
|
100
100
|
"@neon-internals/cli-core": "0.0.0",
|
|
101
|
-
"@neon-internals/env-core": "0.0.11",
|
|
102
101
|
"@neon/e2e-harness": "0.0.0",
|
|
102
|
+
"@neon-internals/env-core": "0.0.12",
|
|
103
103
|
"@neon/functions": "0.9.0"
|
|
104
104
|
},
|
|
105
105
|
"publishConfig": {
|