neon 2.47.0 → 3.1.0
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 +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +395 -0
- package/dist/_shared/env-core/reuse-secrets.js +179 -0
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -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 +575 -658
- 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 +642 -681
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -341
- 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 +614 -845
- 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 +313 -394
- package/dist/dev/functions.js +54 -64
- 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 +36 -38
- 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 +727 -983
- 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 +1293 -2082
- 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 +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -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 +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- 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 +626 -815
- 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 +1414 -1927
- 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 +2 -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 +133 -147
- 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 +37 -44
- 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 +9 -7
|
@@ -1,56 +1,52 @@
|
|
|
1
|
-
import { branchIdResolve } from "./enrichers.js";
|
|
2
1
|
import { looksLikeLSN, looksLikeTimestamp } from "./formats.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
2
|
+
import { branchIdResolve } from "./enrichers.js";
|
|
3
|
+
//#region src/utils/point_in_time.ts
|
|
4
|
+
var PointInTimeParseError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "PointInTimeParseError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const parsePITBranch = (input) => {
|
|
11
|
+
const splitIndex = input.lastIndexOf("@");
|
|
12
|
+
const sourceBranch = splitIndex === -1 ? input : input.slice(0, splitIndex);
|
|
13
|
+
const exactPIT = splitIndex === -1 ? null : input.slice(splitIndex + 1);
|
|
14
|
+
const result = {
|
|
15
|
+
branch: sourceBranch,
|
|
16
|
+
...exactPIT === null ? { tag: "head" } : looksLikeLSN(exactPIT) ? {
|
|
17
|
+
tag: "lsn",
|
|
18
|
+
lsn: exactPIT
|
|
19
|
+
} : {
|
|
20
|
+
tag: "timestamp",
|
|
21
|
+
timestamp: exactPIT
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
if (result.tag === "timestamp") {
|
|
25
|
+
const timestamp = result.timestamp;
|
|
26
|
+
if (!looksLikeTimestamp(timestamp)) throw new PointInTimeParseError(`Invalid source branch format - ${input}`);
|
|
27
|
+
if (Date.parse(timestamp) > Date.now()) throw new PointInTimeParseError(`Timestamp can not be in future - ${input}`);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
31
30
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
// @ts-expect-error extracting pit from parsedPIT
|
|
54
|
-
delete parsedPIT.branch;
|
|
55
|
-
return { ...parsedPIT, branchId };
|
|
31
|
+
const parsePointInTime = async ({ pointInTime, targetBranchId, projectId, api }) => {
|
|
32
|
+
const parsedPIT = parsePITBranch(pointInTime);
|
|
33
|
+
let branchId = "";
|
|
34
|
+
if (parsedPIT.branch === "^self") branchId = targetBranchId;
|
|
35
|
+
else if (parsedPIT.branch === "^parent") {
|
|
36
|
+
const { data } = await api.getProjectBranch(projectId, targetBranchId);
|
|
37
|
+
const { parent_id: parentId } = data.branch;
|
|
38
|
+
if (parentId == null) throw new PointInTimeParseError("Branch has no parent");
|
|
39
|
+
branchId = parentId;
|
|
40
|
+
} else branchId = await branchIdResolve({
|
|
41
|
+
branch: parsedPIT.branch,
|
|
42
|
+
projectId,
|
|
43
|
+
apiClient: api
|
|
44
|
+
});
|
|
45
|
+
delete parsedPIT.branch;
|
|
46
|
+
return {
|
|
47
|
+
...parsedPIT,
|
|
48
|
+
branchId
|
|
49
|
+
};
|
|
56
50
|
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { PointInTimeParseError, parsePITBranch, parsePointInTime };
|
package/dist/utils/psql.js
CHANGED
|
@@ -1,120 +1,103 @@
|
|
|
1
|
-
import { spawn } from "child_process";
|
|
2
|
-
import which from "which";
|
|
3
|
-
import { closeAnalytics, trackEvent } from "../analytics.js";
|
|
4
1
|
import { log } from "../log.js";
|
|
2
|
+
import { closeAnalytics, trackEvent } from "../analytics.js";
|
|
3
|
+
import which from "which";
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
//#region src/utils/psql.ts
|
|
5
6
|
const FALLBACK_ENV = "NEONCTL_PSQL_FALLBACK";
|
|
6
7
|
/** Max time we wait for the analytics flush before handing off to psql. */
|
|
7
|
-
const ANALYTICS_FLUSH_TIMEOUT_MS =
|
|
8
|
+
const ANALYTICS_FLUSH_TIMEOUT_MS = 3e3;
|
|
8
9
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
* Decide which psql implementation will run, and why. The PATH probe is
|
|
11
|
+
* skipped when TS is forced (flag or env) — we don't need it and it'd be a
|
|
12
|
+
* wasted lookup — so `nativeAvailable` is `null` ("not checked") in those
|
|
13
|
+
* cases rather than a misleading `false`.
|
|
14
|
+
*/
|
|
14
15
|
const planPsql = async (opts) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
nativeAvailable,
|
|
47
|
-
nativePath,
|
|
48
|
-
}
|
|
49
|
-
: {
|
|
50
|
-
implementation: "ts",
|
|
51
|
-
reason: "fallback_no_native",
|
|
52
|
-
nativeAvailable,
|
|
53
|
-
nativePath,
|
|
54
|
-
};
|
|
16
|
+
if (opts.mode === "ts") return {
|
|
17
|
+
implementation: "ts",
|
|
18
|
+
reason: "forced_flag",
|
|
19
|
+
nativeAvailable: null,
|
|
20
|
+
nativePath: null
|
|
21
|
+
};
|
|
22
|
+
if (process.env[FALLBACK_ENV] === "1") return {
|
|
23
|
+
implementation: "ts",
|
|
24
|
+
reason: "forced_env",
|
|
25
|
+
nativeAvailable: null,
|
|
26
|
+
nativePath: null
|
|
27
|
+
};
|
|
28
|
+
const nativePath = await which("psql", { nothrow: true });
|
|
29
|
+
const nativeAvailable = nativePath !== null;
|
|
30
|
+
if (opts.mode === "native") return {
|
|
31
|
+
implementation: "native",
|
|
32
|
+
reason: "forced_native",
|
|
33
|
+
nativeAvailable,
|
|
34
|
+
nativePath
|
|
35
|
+
};
|
|
36
|
+
return nativeAvailable ? {
|
|
37
|
+
implementation: "native",
|
|
38
|
+
reason: "native_available",
|
|
39
|
+
nativeAvailable,
|
|
40
|
+
nativePath
|
|
41
|
+
} : {
|
|
42
|
+
implementation: "ts",
|
|
43
|
+
reason: "fallback_no_native",
|
|
44
|
+
nativeAvailable,
|
|
45
|
+
nativePath
|
|
46
|
+
};
|
|
55
47
|
};
|
|
56
48
|
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
49
|
+
* Record which psql implementation is about to run, then flush analytics.
|
|
50
|
+
*
|
|
51
|
+
* Both exec paths below call `process.exit()`, which short-circuits the
|
|
52
|
+
* main loop's `closeAnalytics()` — so without flushing here the event (and
|
|
53
|
+
* any earlier queued events, e.g. `CLI Started`) would be dropped. The
|
|
54
|
+
* flush is bounded by {@link ANALYTICS_FLUSH_TIMEOUT_MS} so a slow or
|
|
55
|
+
* unreachable analytics endpoint can't stall the psql launch. No-ops when
|
|
56
|
+
* analytics is disabled (`--analytics false`), since the client is absent.
|
|
57
|
+
*/
|
|
66
58
|
const reportPsqlInvocation = async (plan) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
59
|
+
trackEvent("psql_invoked", {
|
|
60
|
+
implementation: plan.implementation,
|
|
61
|
+
reason: plan.reason,
|
|
62
|
+
nativeAvailable: plan.nativeAvailable
|
|
63
|
+
});
|
|
64
|
+
await closeAnalytics({ timeout: ANALYTICS_FLUSH_TIMEOUT_MS });
|
|
73
65
|
};
|
|
74
66
|
const execNative = async (binary, connection_uri, args) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return new Promise((_, reject) => {
|
|
87
|
-
child.on("exit", (code) => {
|
|
88
|
-
process.exit(code === null ? 1 : code);
|
|
89
|
-
});
|
|
90
|
-
child.on("error", reject);
|
|
91
|
-
});
|
|
67
|
+
log.info("Connecting to the database using psql...");
|
|
68
|
+
const child = spawn(binary, [connection_uri, ...args], { stdio: "inherit" });
|
|
69
|
+
for (const signame of ["SIGINT", "SIGTERM"]) process.on(signame, (code) => {
|
|
70
|
+
if (!child.killed && code !== null) child.kill(code);
|
|
71
|
+
});
|
|
72
|
+
return new Promise((_, reject) => {
|
|
73
|
+
child.on("exit", (code) => {
|
|
74
|
+
process.exit(code === null ? 1 : code);
|
|
75
|
+
});
|
|
76
|
+
child.on("error", reject);
|
|
77
|
+
});
|
|
92
78
|
};
|
|
93
79
|
const execTs = async (connection_uri, args) => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
80
|
+
log.info("Connecting to the database using embedded psql (TypeScript)...");
|
|
81
|
+
const { runPsql } = await import("../psql/index.js");
|
|
82
|
+
const code = await runPsql([connection_uri, ...args], {
|
|
83
|
+
stdin: process.stdin,
|
|
84
|
+
stdout: process.stdout,
|
|
85
|
+
stderr: process.stderr
|
|
86
|
+
});
|
|
87
|
+
process.exit(code);
|
|
102
88
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// but no binary is on PATH.
|
|
116
|
-
log.error(`psql is not available in the PATH`);
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
|
-
return execNative(plan.nativePath, connection_uri, args);
|
|
89
|
+
const psql = async (connection_uri, args = [], opts = {}) => {
|
|
90
|
+
const plan = await planPsql(opts);
|
|
91
|
+
await reportPsqlInvocation(plan);
|
|
92
|
+
if (plan.implementation === "ts") {
|
|
93
|
+
if (plan.reason === "fallback_no_native") log.info("psql binary not found on PATH; falling back to embedded TypeScript psql");
|
|
94
|
+
return execTs(connection_uri, args);
|
|
95
|
+
}
|
|
96
|
+
if (plan.nativePath === null) {
|
|
97
|
+
log.error(`psql is not available in the PATH`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
return execNative(plan.nativePath, connection_uri, args);
|
|
120
101
|
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { psql };
|
|
@@ -1,64 +1,61 @@
|
|
|
1
|
-
import prompts from "prompts";
|
|
2
1
|
import { CONFIG_INIT_SERVICES } from "../config_template.js";
|
|
2
|
+
import prompts from "prompts";
|
|
3
|
+
//#region src/utils/service_picker.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
* The picker's rows, in {@link CONFIG_INIT_SERVICES} order. Titles use the product names from
|
|
6
|
+
* the CLI's README ("Managed Better Auth", "Object Storage") rather than the `neon.ts` field
|
|
7
|
+
* names, since this is the list a user reads before they've seen a policy.
|
|
8
|
+
*/
|
|
8
9
|
const CHOICES = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
{
|
|
11
|
+
value: "auth",
|
|
12
|
+
title: "Managed Better Auth",
|
|
13
|
+
description: "Authentication with users and sessions stored in Postgres."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
value: "functions",
|
|
17
|
+
title: "Functions",
|
|
18
|
+
description: "Long-running, without timeouts, and closer to your database."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: "object-storage",
|
|
22
|
+
title: "Object Storage",
|
|
23
|
+
description: "S3-compatible blob storage that branches with your projects."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: "ai-gateway",
|
|
27
|
+
title: "AI Gateway",
|
|
28
|
+
description: "All models, one API, one bill. Powered by Databricks. Not available on the Neon free plan."
|
|
29
|
+
}
|
|
29
30
|
];
|
|
30
31
|
/**
|
|
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
|
-
if (!Array.isArray(services)) {
|
|
59
|
-
throw new Error("Aborted: no services selected.");
|
|
60
|
-
}
|
|
61
|
-
// Order canonically rather than by selection order so the rendered neon.ts is
|
|
62
|
-
// independent of the order the rows were toggled in.
|
|
63
|
-
return CONFIG_INIT_SERVICES.filter((service) => services.includes(service));
|
|
32
|
+
* Ask which services the scaffolded `neon.ts` should declare. Selecting nothing is a real
|
|
33
|
+
* answer — it yields the bare starter policy — so an empty list returns empty rather than
|
|
34
|
+
* re-prompting. Aborting (Ctrl-C) exits 1, matching the prompts in `link`.
|
|
35
|
+
*
|
|
36
|
+
* Callers guard the TTY themselves (see `initCmd`); this function assumes it may prompt.
|
|
37
|
+
*/
|
|
38
|
+
const pickServicesInteractively = async () => {
|
|
39
|
+
const { services } = await prompts({
|
|
40
|
+
onState: (state) => {
|
|
41
|
+
if (state.aborted) {
|
|
42
|
+
process.stdout.write("\x1B[?25h");
|
|
43
|
+
process.stdout.write("\n");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
type: "multiselect",
|
|
48
|
+
name: "services",
|
|
49
|
+
message: "Which Neon services should neon.ts declare? (space to toggle, enter to confirm)",
|
|
50
|
+
instructions: false,
|
|
51
|
+
choices: CHOICES.map((choice) => ({
|
|
52
|
+
value: choice.value,
|
|
53
|
+
title: choice.title,
|
|
54
|
+
description: choice.description
|
|
55
|
+
}))
|
|
56
|
+
});
|
|
57
|
+
if (!Array.isArray(services)) throw new Error("Aborted: no services selected.");
|
|
58
|
+
return CONFIG_INIT_SERVICES.filter((service) => services.includes(service));
|
|
64
59
|
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { pickServicesInteractively };
|
package/dist/utils/string.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
1
|
+
//#region src/utils/string.ts
|
|
2
|
+
const toSnakeCase = (str) => str.split(" ").map((word) => word.toLowerCase()).join("_");
|
|
3
|
+
const isObject = (value) => value != null && value === Object(value);
|
|
4
|
+
//#endregion
|
|
5
|
+
export { isObject, toSnakeCase };
|
package/dist/utils/ui.js
CHANGED
|
@@ -1,59 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (matcher.test(line)) {
|
|
11
|
-
return line;
|
|
12
|
-
}
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
return null;
|
|
1
|
+
//#region src/utils/ui.ts
|
|
2
|
+
const consumeNextMatching = (lines, matcher) => {
|
|
3
|
+
while (lines.length > 0) {
|
|
4
|
+
const line = lines.shift().trim();
|
|
5
|
+
if (line === "") continue;
|
|
6
|
+
if (matcher.test(line)) return line;
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
16
10
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
result.push(line);
|
|
34
|
-
while (lines.length > 0) {
|
|
35
|
-
line = lines.shift();
|
|
36
|
-
if (line.trim() === "") {
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
result.push(line);
|
|
40
|
-
}
|
|
41
|
-
return result;
|
|
11
|
+
const consumeBlockIfMatches = (lines, matcher) => {
|
|
12
|
+
const result = [];
|
|
13
|
+
if (lines.length === 0) return result;
|
|
14
|
+
let line = lines.shift();
|
|
15
|
+
while (line.trim() === "") line = lines.shift();
|
|
16
|
+
if (!matcher.test(line)) {
|
|
17
|
+
lines.unshift(line);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
result.push(line);
|
|
21
|
+
while (lines.length > 0) {
|
|
22
|
+
line = lines.shift();
|
|
23
|
+
if (line.trim() === "") break;
|
|
24
|
+
result.push(line);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
42
27
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
return result;
|
|
28
|
+
const splitColumns = (line) => {
|
|
29
|
+
const result = line.trim().split(/\s{2,}/);
|
|
30
|
+
result[1] = result[1] ?? "";
|
|
31
|
+
if (result.length > 2) result[1] = result.slice(1).join(" ");
|
|
32
|
+
return result;
|
|
50
33
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
result.push(">");
|
|
58
|
-
return result.join("");
|
|
34
|
+
const drawPointer = (width) => {
|
|
35
|
+
const result = [];
|
|
36
|
+
result.push("└");
|
|
37
|
+
for (let i = 0; i < width - 4; i++) result.push("─");
|
|
38
|
+
result.push(">");
|
|
39
|
+
return result.join("");
|
|
59
40
|
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { consumeBlockIfMatches, consumeNextMatching, drawPointer, splitColumns };
|
package/dist/utils/write_sync.js
CHANGED
|
@@ -1,39 +1,30 @@
|
|
|
1
1
|
import { writeSync } from "node:fs";
|
|
2
|
+
//#region src/utils/write_sync.ts
|
|
2
3
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5);
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
// The reader closed the pipe (`neon … | head`). There is nobody left to tell,
|
|
28
|
-
// and this is the last thing the process does, so stop rather than throw.
|
|
29
|
-
if (code === "EPIPE")
|
|
30
|
-
return;
|
|
31
|
-
// Anything else means the write did not happen and the caller is about to exit
|
|
32
|
-
// as though it had. Swallowing it turns a lost payload into an apparent success.
|
|
33
|
-
throw err;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
4
|
+
* Write `text` to a file descriptor and do not return until all of it is out.
|
|
5
|
+
*
|
|
6
|
+
* `process.stdout.write` is asynchronous when stdout is a pipe — which it is whenever the
|
|
7
|
+
* caller is an agent or a script capturing output — so a `process.exit()` on the next line
|
|
8
|
+
* discards whatever has not been flushed. The caller sees an exit code and empty stdout.
|
|
9
|
+
*
|
|
10
|
+
* Use this for any final message that is followed by `process.exit`.
|
|
11
|
+
*/
|
|
12
|
+
function writeAllSync(fd, text) {
|
|
13
|
+
let buffer = Buffer.from(text, "utf8");
|
|
14
|
+
while (buffer.length > 0) try {
|
|
15
|
+
buffer = buffer.subarray(writeSync(fd, buffer));
|
|
16
|
+
} catch (err) {
|
|
17
|
+
const code = err.code;
|
|
18
|
+
if (code === "EAGAIN") {
|
|
19
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (code === "EPIPE") return;
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
36
25
|
}
|
|
37
26
|
/** File descriptors, named so call sites read as the stream they mean. */
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
const STDOUT_FD = 1;
|
|
28
|
+
const STDERR_FD = 2;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { STDERR_FD, STDOUT_FD, writeAllSync };
|
package/dist/utils/zip.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { zipSync } from "fflate";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
//#region src/utils/zip.ts
|
|
3
|
+
const zipBundle = (entries) => zipSync(entries, { level: 6 });
|
|
4
|
+
//#endregion
|
|
5
|
+
export { zipBundle };
|