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.
Files changed (207) hide show
  1. package/README.md +70 -5
  2. package/dist/_chunks/auth_selection-DGgq6ifc.js +83 -0
  3. package/dist/_chunks/cmd_pipeline-CUbBO9U_.js +2818 -0
  4. package/dist/_chunks/credentials-MYdHdKah.js +188 -0
  5. package/dist/_chunks/env-NbA61JR3.js +585 -0
  6. package/dist/_chunks/env_services-Tz9G4JeT.js +531 -0
  7. package/dist/_chunks/paths-DMq0Lt7a.js +151 -0
  8. package/dist/_chunks/profiles-Ir29rqns.js +217 -0
  9. package/dist/_chunks/psql-DWH-kc69.js +2169 -0
  10. package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  11. package/dist/_chunks/secure_file-BucZj4yQ.js +39 -0
  12. package/dist/analytics.js +163 -207
  13. package/dist/api.js +815 -758
  14. package/dist/auth.js +121 -141
  15. package/dist/auth_context.js +39 -53
  16. package/dist/cli.js +4 -7
  17. package/dist/commands/api.js +220 -250
  18. package/dist/commands/api_keys.js +251 -314
  19. package/dist/commands/auth.js +283 -328
  20. package/dist/commands/bootstrap.js +372 -437
  21. package/dist/commands/branches.js +304 -455
  22. package/dist/commands/bucket.js +374 -514
  23. package/dist/commands/checkout.js +213 -298
  24. package/dist/commands/config.js +573 -690
  25. package/dist/commands/connection_string.js +137 -165
  26. package/dist/commands/data_api.js +238 -260
  27. package/dist/commands/databases.js +67 -76
  28. package/dist/commands/deploy.js +31 -25
  29. package/dist/commands/dev.js +639 -719
  30. package/dist/commands/diff.js +156 -200
  31. package/dist/commands/env.js +255 -305
  32. package/dist/commands/functions.js +275 -355
  33. package/dist/commands/index.js +70 -65
  34. package/dist/commands/init.js +84 -119
  35. package/dist/commands/inspect.js +55 -55
  36. package/dist/commands/ip_allow.js +88 -120
  37. package/dist/commands/link.js +874 -1019
  38. package/dist/commands/logs.js +291 -0
  39. package/dist/commands/neon_auth.js +725 -933
  40. package/dist/commands/operations.js +34 -25
  41. package/dist/commands/orgs.js +28 -18
  42. package/dist/commands/profile.js +615 -846
  43. package/dist/commands/projects.js +313 -373
  44. package/dist/commands/psql.js +60 -58
  45. package/dist/commands/roles.js +55 -58
  46. package/dist/commands/schema_diff.js +87 -131
  47. package/dist/commands/set_context.js +34 -26
  48. package/dist/commands/snapshots.js +288 -413
  49. package/dist/commands/status.js +41 -37
  50. package/dist/commands/user.js +21 -10
  51. package/dist/commands/vpc_endpoints.js +85 -113
  52. package/dist/config.js +7 -6
  53. package/dist/config_format.js +50 -66
  54. package/dist/config_template.js +128 -157
  55. package/dist/context.js +183 -235
  56. package/dist/current_branch_fast_path.js +40 -49
  57. package/dist/dev/env.js +2 -446
  58. package/dist/dev/functions.js +54 -68
  59. package/dist/dev/inputs.js +46 -58
  60. package/dist/dev/runtime.js +135 -164
  61. package/dist/dev/websocket.js +766 -959
  62. package/dist/env.js +27 -33
  63. package/dist/env_file.js +118 -132
  64. package/dist/env_services.js +2 -51
  65. package/dist/errors.js +57 -68
  66. package/dist/functions_api.js +45 -43
  67. package/dist/help.js +189 -140
  68. package/dist/index.js +182 -257
  69. package/dist/init/agents.js +137 -118
  70. package/dist/init/auth.js +58 -68
  71. package/dist/init/bootstrap.js +325 -396
  72. package/dist/init/build_config.js +4 -2
  73. package/dist/init/detect_agent.js +56 -101
  74. package/dist/init/editors.js +35 -52
  75. package/dist/init/enrich_output.js +51 -66
  76. package/dist/init/extension.js +134 -171
  77. package/dist/init/inspect.js +179 -266
  78. package/dist/init/interactive.js +510 -622
  79. package/dist/init/neonctl.js +117 -168
  80. package/dist/init/orchestrate.js +157 -173
  81. package/dist/init/phases/auth.js +188 -202
  82. package/dist/init/phases/cleanup.js +23 -23
  83. package/dist/init/phases/db.js +251 -277
  84. package/dist/init/phases/getting_started.js +213 -223
  85. package/dist/init/phases/mcp.js +174 -224
  86. package/dist/init/phases/migrations.js +247 -248
  87. package/dist/init/phases/neon_auth.js +114 -133
  88. package/dist/init/phases/setup.js +546 -703
  89. package/dist/init/phases/skills.js +75 -86
  90. package/dist/init/phases/status.js +72 -67
  91. package/dist/init/resolve_context.js +102 -99
  92. package/dist/init/route_command.js +91 -98
  93. package/dist/init/skills.js +174 -218
  94. package/dist/init/vsix.js +77 -99
  95. package/dist/log.js +17 -16
  96. package/dist/neon_services.js +104 -129
  97. package/dist/parameters.gen.js +481 -471
  98. package/dist/pkg.js +17 -19
  99. package/dist/profile_keys.js +44 -47
  100. package/dist/psql/cli.js +44 -47
  101. package/dist/psql/command/cmd_cond.js +231 -406
  102. package/dist/psql/command/cmd_connect.js +557 -764
  103. package/dist/psql/command/cmd_copy.js +728 -984
  104. package/dist/psql/command/cmd_describe.js +1499 -1688
  105. package/dist/psql/command/cmd_format.js +733 -905
  106. package/dist/psql/command/cmd_io.js +2 -2193
  107. package/dist/psql/command/cmd_lo.js +297 -359
  108. package/dist/psql/command/cmd_meta.js +727 -878
  109. package/dist/psql/command/cmd_misc.js +138 -172
  110. package/dist/psql/command/cmd_pipeline.js +2 -1148
  111. package/dist/psql/command/cmd_restrict.js +119 -155
  112. package/dist/psql/command/cmd_show.js +529 -688
  113. package/dist/psql/command/dispatch.js +260 -325
  114. package/dist/psql/command/inputQueue.js +35 -33
  115. package/dist/psql/command/shared.js +49 -63
  116. package/dist/psql/complete/filenames.js +90 -133
  117. package/dist/psql/complete/index.js +59 -97
  118. package/dist/psql/complete/matcher.js +236 -300
  119. package/dist/psql/complete/psqlVars.js +218 -223
  120. package/dist/psql/complete/queries.js +159 -177
  121. package/dist/psql/complete/rules.js +1493 -2299
  122. package/dist/psql/core/common.js +2 -1253
  123. package/dist/psql/core/help.js +456 -546
  124. package/dist/psql/core/mainloop.js +692 -1303
  125. package/dist/psql/core/prompt.js +391 -408
  126. package/dist/psql/core/settings.js +429 -644
  127. package/dist/psql/core/sqlHelp.js +480 -554
  128. package/dist/psql/core/startup.js +2 -846
  129. package/dist/psql/core/syncVars.js +67 -110
  130. package/dist/psql/core/variables.js +156 -278
  131. package/dist/psql/describe/formatters.js +884 -1285
  132. package/dist/psql/describe/processNamePattern.js +173 -260
  133. package/dist/psql/describe/queries.js +1368 -2403
  134. package/dist/psql/describe/versionGate.js +32 -41
  135. package/dist/psql/index.js +2 -2030
  136. package/dist/psql/io/history.js +232 -271
  137. package/dist/psql/io/input.js +103 -108
  138. package/dist/psql/io/lineEditor/buffer.js +238 -319
  139. package/dist/psql/io/lineEditor/complete.js +135 -213
  140. package/dist/psql/io/lineEditor/filename.js +139 -148
  141. package/dist/psql/io/lineEditor/index.js +653 -870
  142. package/dist/psql/io/lineEditor/keymap.js +544 -702
  143. package/dist/psql/io/lineEditor/vt100.js +294 -341
  144. package/dist/psql/io/pgpass.js +158 -187
  145. package/dist/psql/io/pgservice.js +146 -183
  146. package/dist/psql/io/psqlrc.js +328 -403
  147. package/dist/psql/print/aligned.js +1020 -1683
  148. package/dist/psql/print/asciidoc.js +180 -214
  149. package/dist/psql/print/crosstab.js +281 -442
  150. package/dist/psql/print/csv.js +48 -70
  151. package/dist/psql/print/html.js +195 -226
  152. package/dist/psql/print/json.js +75 -88
  153. package/dist/psql/print/latex.js +291 -364
  154. package/dist/psql/print/pager.js +171 -242
  155. package/dist/psql/print/troff.js +194 -226
  156. package/dist/psql/print/unaligned.js +69 -95
  157. package/dist/psql/print/units.js +167 -169
  158. package/dist/psql/scanner/slash.js +428 -483
  159. package/dist/psql/scanner/sql.js +445 -889
  160. package/dist/psql/scanner/stringutils.js +309 -379
  161. package/dist/psql/types/index.js +8 -7
  162. package/dist/psql/types/scanner.js +25 -22
  163. package/dist/psql/wire/connection.js +2042 -2803
  164. package/dist/psql/wire/copy.js +84 -100
  165. package/dist/psql/wire/notify.js +39 -59
  166. package/dist/psql/wire/pipeline.js +305 -518
  167. package/dist/psql/wire/protocol.js +349 -417
  168. package/dist/psql/wire/sasl.js +180 -265
  169. package/dist/psql/wire/tls.js +400 -561
  170. package/dist/storage_api.js +115 -129
  171. package/dist/test_utils/fixtures.js +94 -113
  172. package/dist/test_utils/oauth_server.js +10 -7
  173. package/dist/test_utils/project_dir.js +33 -0
  174. package/dist/utils/ai_gateway_notice.js +131 -162
  175. package/dist/utils/api_enums.js +21 -28
  176. package/dist/utils/auth.js +10 -4
  177. package/dist/utils/branch_notice.js +20 -19
  178. package/dist/utils/branch_picker.js +83 -89
  179. package/dist/utils/cli_name.js +15 -12
  180. package/dist/utils/compute_units.js +20 -27
  181. package/dist/utils/config_diff.js +127 -158
  182. package/dist/utils/enrichers.js +95 -148
  183. package/dist/utils/esbuild.js +130 -189
  184. package/dist/utils/flags.js +35 -47
  185. package/dist/utils/formats.js +8 -15
  186. package/dist/utils/git_diff.js +69 -80
  187. package/dist/utils/inspect_db.js +101 -143
  188. package/dist/utils/inspect_queries.js +179 -142
  189. package/dist/utils/middlewares.js +39 -45
  190. package/dist/utils/openapi.js +87 -99
  191. package/dist/utils/package_manager.js +312 -110
  192. package/dist/utils/point_in_time.js +49 -53
  193. package/dist/utils/psql.js +89 -106
  194. package/dist/utils/service_picker.js +55 -58
  195. package/dist/utils/string.js +5 -5
  196. package/dist/utils/ui.js +38 -55
  197. package/dist/utils/write_sync.js +26 -35
  198. package/dist/utils/zip.js +4 -3
  199. package/dist/writer.js +67 -87
  200. package/package.json +11 -6
  201. package/dist/_shared/auth_selection.js +0 -86
  202. package/dist/_shared/credentials.js +0 -209
  203. package/dist/_shared/env-core/env.js +0 -558
  204. package/dist/_shared/env-core/reuse-secrets.js +0 -223
  205. package/dist/_shared/paths.js +0 -148
  206. package/dist/_shared/profiles.js +0 -276
  207. package/dist/_shared/secure_file.js +0 -43
@@ -1,422 +1,347 @@
1
- /**
2
- * `.psqlrc` autoload.
3
- *
4
- * TypeScript port of `process_psqlrc()` / `process_psqlrc_file()` in
5
- * `src/bin/psql/startup.c`. Two responsibilities:
6
- *
7
- * 1. `defaultPsqlrcPath(env?)` — pure function returning the path psql
8
- * *would* read in the absence of a `$PSQLRC` override. Resolves to
9
- * `$HOME/.psqlrc` on POSIX and `%APPDATA%/postgresql/psqlrc.conf` on
10
- * Windows (the upstream layout).
11
- *
12
- * 2. `loadPsqlrc(ctx)` — discover and execute the rc files in upstream
13
- * order:
14
- * a. `$PGSYSCONFDIR/psqlrc-VERSION` and `$PGSYSCONFDIR/psqlrc`
15
- * b. `$PSQLRC` if non-empty (overrides $HOME path)
16
- * c. else `$HOME/.psqlrc-VERSION` then `$HOME/.psqlrc`
17
- * Each existing file's contents are split into statements via the same
18
- * `scanSql` boundary detector the mainloop uses, then dispatched
19
- * through `connection.execSimple` (for SQL) or the backslash registry
20
- * (for `\…` commands).
21
- *
22
- * Duplication note: we deliberately re-implement a minimal scan-and-dispatch
23
- * loop here instead of routing through `core/mainloop.ts`. The mainloop is
24
- * locked-down in WP-12 and adding an `executeInputString` helper to it would
25
- * touch a file we can't modify in this WP. The two loops share `scanSql` and
26
- * `dispatchBackslash` so the divergence is structural, not behavioural.
27
- *
28
- * Follow-up issue: refactor `mainloop.ts` to expose an `executeInputString`
29
- * primitive and delete this duplication. Tracked TODO at the bottom of this
30
- * file.
31
- */
32
- import { promises as fs } from "node:fs";
33
- import * as path from "node:path";
34
- import { attachCondStack, COND_COMMAND_NAMES } from "../command/cmd_cond.js";
35
- import { dispatchBackslash } from "../command/dispatch.js";
36
- import { sendQuery } from "../core/common.js";
1
+ import { COND_COMMAND_NAMES, attachCondStack } from "../command/cmd_cond.js";
37
2
  import { scanSlashArgs } from "../scanner/slash.js";
38
- import { scanSql } from "../scanner/sql.js";
3
+ import { U as sendQuery } from "../../_chunks/cmd_pipeline-CUbBO9U_.js";
4
+ import { dispatchBackslash } from "../command/dispatch.js";
39
5
  import { initialScanState } from "../types/scanner.js";
40
- // ---------------------------------------------------------------------------
41
- // Path discovery.
42
- // ---------------------------------------------------------------------------
6
+ import { scanSql } from "../scanner/sql.js";
7
+ import { promises } from "node:fs";
8
+ import * as path from "node:path";
9
+ //#region src/psql/io/psqlrc.ts
10
+ /**
11
+ * `.psqlrc` autoload.
12
+ *
13
+ * TypeScript port of `process_psqlrc()` / `process_psqlrc_file()` in
14
+ * `src/bin/psql/startup.c`. Two responsibilities:
15
+ *
16
+ * 1. `defaultPsqlrcPath(env?)` — pure function returning the path psql
17
+ * *would* read in the absence of a `$PSQLRC` override. Resolves to
18
+ * `$HOME/.psqlrc` on POSIX and `%APPDATA%/postgresql/psqlrc.conf` on
19
+ * Windows (the upstream layout).
20
+ *
21
+ * 2. `loadPsqlrc(ctx)` — discover and execute the rc files in upstream
22
+ * order:
23
+ * a. `$PGSYSCONFDIR/psqlrc-VERSION` and `$PGSYSCONFDIR/psqlrc`
24
+ * b. `$PSQLRC` if non-empty (overrides $HOME path)
25
+ * c. else `$HOME/.psqlrc-VERSION` then `$HOME/.psqlrc`
26
+ * Each existing file's contents are split into statements via the same
27
+ * `scanSql` boundary detector the mainloop uses, then dispatched
28
+ * through `connection.execSimple` (for SQL) or the backslash registry
29
+ * (for `\…` commands).
30
+ *
31
+ * Duplication note: we deliberately re-implement a minimal scan-and-dispatch
32
+ * loop here instead of routing through `core/mainloop.ts`. The mainloop is
33
+ * locked-down in WP-12 and adding an `executeInputString` helper to it would
34
+ * touch a file we can't modify in this WP. The two loops share `scanSql` and
35
+ * `dispatchBackslash` so the divergence is structural, not behavioural.
36
+ *
37
+ * Follow-up issue: refactor `mainloop.ts` to expose an `executeInputString`
38
+ * primitive and delete this duplication. Tracked TODO at the bottom of this
39
+ * file.
40
+ */
43
41
  const isWindows = process.platform === "win32";
44
42
  const baseRcName = isWindows ? "psqlrc.conf" : ".psqlrc";
45
43
  /**
46
- * Return the default user-level psqlrc path. The path is *not* verified to
47
- * exist — callers stat it lazily. The Windows layout follows upstream:
48
- * `%APPDATA%/postgresql/psqlrc.conf`. On POSIX we use `$HOME/.psqlrc`.
49
- */
50
- export const defaultPsqlrcPath = (env = process.env) => {
51
- if (isWindows) {
52
- const appData = env.APPDATA;
53
- if (appData && appData.length > 0) {
54
- return path.join(appData, "postgresql", baseRcName);
55
- }
56
- return path.join(env.USERPROFILE ?? "", "postgresql", baseRcName);
57
- }
58
- const home = env.HOME ?? "";
59
- return path.join(home, baseRcName);
44
+ * Return the default user-level psqlrc path. The path is *not* verified to
45
+ * exist — callers stat it lazily. The Windows layout follows upstream:
46
+ * `%APPDATA%/postgresql/psqlrc.conf`. On POSIX we use `$HOME/.psqlrc`.
47
+ */
48
+ const defaultPsqlrcPath = (env = process.env) => {
49
+ if (isWindows) {
50
+ const appData = env.APPDATA;
51
+ if (appData && appData.length > 0) return path.join(appData, "postgresql", baseRcName);
52
+ return path.join(env.USERPROFILE ?? "", "postgresql", baseRcName);
53
+ }
54
+ const home = env.HOME ?? "";
55
+ return path.join(home, baseRcName);
60
56
  };
61
57
  const versionSuffix = (serverVersion) => {
62
- if (!serverVersion || serverVersion <= 0)
63
- return null;
64
- // PG numeric version is e.g. 170002 (17.2). Upstream uses both
65
- // `psqlrc-PG_VERSION` (major.minor) and `psqlrc-PG_MAJORVERSION`. We use
66
- // the major (e.g. 17) — the bigger of the two backwards-compat targets.
67
- const major = Math.floor(serverVersion / 10000);
68
- return String(major);
58
+ if (!serverVersion || serverVersion <= 0) return null;
59
+ const major = Math.floor(serverVersion / 1e4);
60
+ return String(major);
69
61
  };
70
- export const psqlrcCandidates = (env, serverVersion) => {
71
- const out = [];
72
- const suffix = versionSuffix(serverVersion);
73
- // System-wide.
74
- const sysDir = env.PGSYSCONFDIR;
75
- if (sysDir && sysDir.length > 0) {
76
- const sysBase = isWindows ? "psqlrc.conf" : "psqlrc";
77
- if (suffix) {
78
- out.push({
79
- path: path.join(sysDir, `${sysBase}-${suffix}`),
80
- description: "system psqlrc (versioned)",
81
- });
82
- }
83
- out.push({
84
- path: path.join(sysDir, sysBase),
85
- description: "system psqlrc",
86
- });
87
- }
88
- // PSQLRC override suppresses HOME-based discovery (matches upstream).
89
- const envRc = env.PSQLRC;
90
- if (envRc !== undefined && envRc !== "") {
91
- out.push({ path: expandTilde(envRc, env), description: "$PSQLRC" });
92
- return out;
93
- }
94
- // HOME-based.
95
- const home = env.HOME ?? "";
96
- if (isWindows) {
97
- const appData = env.APPDATA;
98
- const dir = appData && appData.length > 0
99
- ? path.join(appData, "postgresql")
100
- : path.join(env.USERPROFILE ?? "", "postgresql");
101
- if (suffix) {
102
- out.push({
103
- path: path.join(dir, `${baseRcName}-${suffix}`),
104
- description: "user psqlrc (versioned)",
105
- });
106
- }
107
- out.push({
108
- path: path.join(dir, baseRcName),
109
- description: "user psqlrc",
110
- });
111
- }
112
- else if (home.length > 0) {
113
- if (suffix) {
114
- out.push({
115
- path: path.join(home, `${baseRcName}-${suffix}`),
116
- description: "user psqlrc (versioned)",
117
- });
118
- }
119
- out.push({
120
- path: path.join(home, baseRcName),
121
- description: "user psqlrc",
122
- });
123
- }
124
- return out;
62
+ const psqlrcCandidates = (env, serverVersion) => {
63
+ const out = [];
64
+ const suffix = versionSuffix(serverVersion);
65
+ const sysDir = env.PGSYSCONFDIR;
66
+ if (sysDir && sysDir.length > 0) {
67
+ const sysBase = isWindows ? "psqlrc.conf" : "psqlrc";
68
+ if (suffix) out.push({
69
+ path: path.join(sysDir, `${sysBase}-${suffix}`),
70
+ description: "system psqlrc (versioned)"
71
+ });
72
+ out.push({
73
+ path: path.join(sysDir, sysBase),
74
+ description: "system psqlrc"
75
+ });
76
+ }
77
+ const envRc = env.PSQLRC;
78
+ if (envRc !== void 0 && envRc !== "") {
79
+ out.push({
80
+ path: expandTilde(envRc, env),
81
+ description: "$PSQLRC"
82
+ });
83
+ return out;
84
+ }
85
+ const home = env.HOME ?? "";
86
+ if (isWindows) {
87
+ const appData = env.APPDATA;
88
+ const dir = appData && appData.length > 0 ? path.join(appData, "postgresql") : path.join(env.USERPROFILE ?? "", "postgresql");
89
+ if (suffix) out.push({
90
+ path: path.join(dir, `${baseRcName}-${suffix}`),
91
+ description: "user psqlrc (versioned)"
92
+ });
93
+ out.push({
94
+ path: path.join(dir, baseRcName),
95
+ description: "user psqlrc"
96
+ });
97
+ } else if (home.length > 0) {
98
+ if (suffix) out.push({
99
+ path: path.join(home, `${baseRcName}-${suffix}`),
100
+ description: "user psqlrc (versioned)"
101
+ });
102
+ out.push({
103
+ path: path.join(home, baseRcName),
104
+ description: "user psqlrc"
105
+ });
106
+ }
107
+ return out;
125
108
  };
126
109
  const expandTilde = (p, env) => {
127
- if (p.startsWith("~/") && env.HOME) {
128
- return path.join(env.HOME, p.slice(2));
129
- }
130
- if (p === "~" && env.HOME) {
131
- return env.HOME;
132
- }
133
- return p;
110
+ if (p.startsWith("~/") && env.HOME) return path.join(env.HOME, p.slice(2));
111
+ if (p === "~" && env.HOME) return env.HOME;
112
+ return p;
134
113
  };
135
- // ---------------------------------------------------------------------------
136
- // File read + dispatch.
137
- // ---------------------------------------------------------------------------
138
114
  const readIfExists = async (file) => {
139
- try {
140
- return await fs.readFile(file, "utf8");
141
- }
142
- catch (err) {
143
- const code = err.code;
144
- if (code === "ENOENT" || code === "ENOTDIR")
145
- return null;
146
- // Permission / I/O errors propagate — they're worth surfacing because
147
- // they signal a likely misconfiguration. Mirror upstream which prints
148
- // a warning but doesn't abort the session; we use a noop for now.
149
- return null;
150
- }
115
+ try {
116
+ return await promises.readFile(file, "utf8");
117
+ } catch (err) {
118
+ const code = err.code;
119
+ if (code === "ENOENT" || code === "ENOTDIR") return null;
120
+ return null;
121
+ }
151
122
  };
152
123
  const makeBackslashContext = (ctx, cmdName, rawArgs, queryBuf) => {
153
- const varLookup = (name) => ctx.settings.vars.get(name);
154
- const buffered = new Map();
155
- const cursors = new Map();
156
- const argsFor = (mode) => {
157
- const cached = buffered.get(mode);
158
- if (cached)
159
- return cached;
160
- const parsed = scanSlashArgs(rawArgs, mode, varLookup);
161
- buffered.set(mode, parsed);
162
- return parsed;
163
- };
164
- const bctx = {
165
- settings: ctx.settings,
166
- cmdName,
167
- queryBuf,
168
- rawArgs,
169
- nextArg(mode = "normal") {
170
- const av = argsFor(mode);
171
- const idx = cursors.get(mode) ?? 0;
172
- if (idx >= av.length)
173
- return null;
174
- cursors.set(mode, idx + 1);
175
- return av[idx];
176
- },
177
- restOfLine() {
178
- return rawArgs;
179
- },
180
- };
181
- attachCondStack(bctx, ctx.cond);
182
- return bctx;
124
+ const varLookup = (name) => ctx.settings.vars.get(name);
125
+ const buffered = /* @__PURE__ */ new Map();
126
+ const cursors = /* @__PURE__ */ new Map();
127
+ const argsFor = (mode) => {
128
+ const cached = buffered.get(mode);
129
+ if (cached) return cached;
130
+ const parsed = scanSlashArgs(rawArgs, mode, varLookup);
131
+ buffered.set(mode, parsed);
132
+ return parsed;
133
+ };
134
+ const bctx = {
135
+ settings: ctx.settings,
136
+ cmdName,
137
+ queryBuf,
138
+ rawArgs,
139
+ nextArg(mode = "normal") {
140
+ const av = argsFor(mode);
141
+ const idx = cursors.get(mode) ?? 0;
142
+ if (idx >= av.length) return null;
143
+ cursors.set(mode, idx + 1);
144
+ return av[idx];
145
+ },
146
+ restOfLine() {
147
+ return rawArgs;
148
+ }
149
+ };
150
+ attachCondStack(bctx, ctx.cond);
151
+ return bctx;
183
152
  };
184
153
  /**
185
- * Execute the supplied input string against the running REPL context. Used
186
- * by `loadPsqlrc` (and exported for tests). This is a minimal cousin of
187
- * `runMainLoop`'s processChunk — see the module header for the duplication
188
- * rationale.
189
- *
190
- * Returns when EOF is reached; `\q` and other exit commands inside an rc
191
- * file are treated as "stop reading this file" (the REPL itself continues).
192
- *
193
- * The returned outcome lets `runPsql`'s `-c`/`-f` loop apply upstream's
194
- * per-switch exit-code semantics (see comment above).
195
- */
196
- export const executeInputString = async (input, ctx, opts = {}) => {
197
- let working = input;
198
- let queryBuf = "";
199
- let scanState = initialScanState();
200
- let hadError = false;
201
- let stoppedOnError = false;
202
- let connectionLost = false;
203
- const print = opts.print ?? false;
204
- const noteConnectionLost = () => {
205
- if (ctx.settings.db?.isClosed()) {
206
- ctx.stderr.write("psql: error: connection to server was lost\n");
207
- connectionLost = true;
208
- return true;
209
- }
210
- return false;
211
- };
212
- // Inline `:NAME` substitution wired through SQL bodies (handled by
213
- // scanSql). Slash-arg bodies are already substituted via
214
- // `makeBackslashContext` above. Mirror the mainloop's wiring so `-c`/`-f`
215
- // / .psqlrc inputs expand the same way as interactive input.
216
- const sqlVarLookup = (name) => ctx.settings.vars.get(name);
217
- while (working.length > 0) {
218
- const r = scanSql(working, scanState, sqlVarLookup);
219
- scanState = r.nextState;
220
- if (r.kind === "semicolon") {
221
- // Use the substituted text rather than the raw slice so `:NAME`
222
- // expansions land in the executed SQL.
223
- const sqlText = queryBuf + r.sql;
224
- queryBuf = "";
225
- working = working.slice(r.consumed);
226
- scanState = initialScanState();
227
- if (!ctx.cond.isActive())
228
- continue;
229
- const trimmed = sqlText.trim();
230
- if (trimmed.length === 0)
231
- continue;
232
- if (!ctx.settings.db)
233
- continue;
234
- if (print) {
235
- // `-c` / `-f`: route through the full SendQuery pipeline so SELECT
236
- // tuples, NOTICE messages and `\timing` land on the output streams.
237
- const stats = await sendQuery(ctx, sqlText);
238
- // LATCH: a multi-statement input must report an error if ANY statement
239
- // failed, not just the last one — otherwise `-c "SELECT 1; SELECT 1/0;
240
- // SELECT 2"` exits 0 and silently passes CI. The
241
- // -f/psqlrc callers ignore this aggregate (they only act on
242
- // stoppedOnError), so latching is safe across all callers.
243
- if (stats.hadError)
244
- hadError = true;
245
- if (noteConnectionLost()) {
246
- return { hadError, stoppedOnError, connectionLost };
247
- }
248
- if (stats.hadError && ctx.settings.onErrorStop) {
249
- stoppedOnError = true;
250
- return { hadError, stoppedOnError, connectionLost };
251
- }
252
- }
253
- else {
254
- try {
255
- await ctx.settings.db.execSimple(sqlText);
256
- }
257
- catch (err) {
258
- const msg = err instanceof Error ? err.message : String(err);
259
- ctx.stderr.write(`psql: ERROR: ${msg}\n`);
260
- hadError = true;
261
- if (noteConnectionLost()) {
262
- return { hadError, stoppedOnError, connectionLost };
263
- }
264
- if (ctx.settings.onErrorStop) {
265
- stoppedOnError = true;
266
- return { hadError, stoppedOnError, connectionLost };
267
- }
268
- }
269
- }
270
- continue;
271
- }
272
- if (r.kind === "backslash") {
273
- // Use `r.sql` — the scanner's substituted/processed text that
274
- // *preceded* the backslash boundary. The raw consumed slice would
275
- // also include the backslash command itself and any separators
276
- // (like the `\\` end-of-args marker), which we don't want in the
277
- // query buffer. `r.sql` excludes both. Mirrors the mainloop's
278
- // `queryBuf += result.sql` path.
279
- queryBuf += r.sql;
280
- working = working.slice(r.consumed);
281
- const cmdName = r.cmd;
282
- // Skip cond-commands inside rc — they require the full mainloop state
283
- // machine to be useful; we treat them as no-ops here. Other commands
284
- // run through the standard registry.
285
- if (COND_COMMAND_NAMES.has(cmdName))
286
- continue;
287
- if (!ctx.cond.isActive())
288
- continue;
289
- const bctx = makeBackslashContext(ctx, cmdName, r.rest, queryBuf);
290
- let res;
291
- try {
292
- res = await dispatchBackslash(ctx.registry, cmdName, bctx);
293
- }
294
- catch (err) {
295
- const msg = err instanceof Error ? err.message : String(err);
296
- ctx.stderr.write(`psql: ERROR: ${msg}\n`);
297
- hadError = true;
298
- if (ctx.settings.onErrorStop) {
299
- stoppedOnError = true;
300
- return { hadError, stoppedOnError, connectionLost };
301
- }
302
- continue;
303
- }
304
- if (res.status === "exit")
305
- return { hadError, stoppedOnError, connectionLost };
306
- if (res.status === "reset-buf") {
307
- queryBuf = res.newBuf ?? "";
308
- scanState = initialScanState();
309
- }
310
- // Mirror upstream `mainloop.c`: a backslash command that errored
311
- // drops the query buffer and resets the scanner. Without this the
312
- // residue would re-execute via the tail-dispatch at EOF (or get
313
- // glued onto the next dispatched statement), masking the failure.
314
- if (res.status === "error") {
315
- queryBuf = "";
316
- scanState = initialScanState();
317
- }
318
- if (res.status === "error")
319
- hadError = true; // latch
320
- if (noteConnectionLost()) {
321
- return { hadError, stoppedOnError, connectionLost };
322
- }
323
- if (res.status === "error" && ctx.settings.onErrorStop) {
324
- stoppedOnError = true;
325
- return { hadError, stoppedOnError, connectionLost };
326
- }
327
- continue;
328
- }
329
- // eof / incomplete: stash residue and stop. Use `r.sql` so any `:NAME`
330
- // tokens fully consumed in this chunk make it into the buffer in
331
- // substituted form. (Same caveat as the mainloop: cross-chunk colon
332
- // references fall back to the literal.)
333
- queryBuf += r.sql;
334
- working = "";
335
- }
336
- // Tail dispatch: if the file ended mid-statement (no trailing `;`), run
337
- // the residue. This matches `process_file` behaviour in upstream.
338
- const tail = queryBuf.trim();
339
- if (tail.length > 0 && ctx.settings.db && ctx.cond.isActive()) {
340
- if (print) {
341
- const stats = await sendQuery(ctx, queryBuf);
342
- // LATCH, same as the semicolon branch — a trailing statement (no `;`)
343
- // that succeeds must not clear an earlier error, or `-c "bad; ok"`
344
- // wrongly exits 0. The function's latch invariant applies
345
- // to the tail path too.
346
- if (stats.hadError)
347
- hadError = true;
348
- noteConnectionLost();
349
- }
350
- else {
351
- try {
352
- await ctx.settings.db.execSimple(queryBuf);
353
- }
354
- catch (err) {
355
- const msg = err instanceof Error ? err.message : String(err);
356
- ctx.stderr.write(`psql: ERROR: ${msg}\n`);
357
- hadError = true;
358
- noteConnectionLost();
359
- }
360
- }
361
- }
362
- return { hadError, stoppedOnError, connectionLost };
154
+ * Execute the supplied input string against the running REPL context. Used
155
+ * by `loadPsqlrc` (and exported for tests). This is a minimal cousin of
156
+ * `runMainLoop`'s processChunk — see the module header for the duplication
157
+ * rationale.
158
+ *
159
+ * Returns when EOF is reached; `\q` and other exit commands inside an rc
160
+ * file are treated as "stop reading this file" (the REPL itself continues).
161
+ *
162
+ * The returned outcome lets `runPsql`'s `-c`/`-f` loop apply upstream's
163
+ * per-switch exit-code semantics (see comment above).
164
+ */
165
+ const executeInputString = async (input, ctx, opts = {}) => {
166
+ let working = input;
167
+ let queryBuf = "";
168
+ let scanState = initialScanState();
169
+ let hadError = false;
170
+ let stoppedOnError = false;
171
+ let connectionLost = false;
172
+ const print = opts.print ?? false;
173
+ const noteConnectionLost = () => {
174
+ if (ctx.settings.db?.isClosed()) {
175
+ ctx.stderr.write("psql: error: connection to server was lost\n");
176
+ connectionLost = true;
177
+ return true;
178
+ }
179
+ return false;
180
+ };
181
+ const sqlVarLookup = (name) => ctx.settings.vars.get(name);
182
+ while (working.length > 0) {
183
+ const r = scanSql(working, scanState, sqlVarLookup);
184
+ scanState = r.nextState;
185
+ if (r.kind === "semicolon") {
186
+ const sqlText = queryBuf + r.sql;
187
+ queryBuf = "";
188
+ working = working.slice(r.consumed);
189
+ scanState = initialScanState();
190
+ if (!ctx.cond.isActive()) continue;
191
+ if (sqlText.trim().length === 0) continue;
192
+ if (!ctx.settings.db) continue;
193
+ if (print) {
194
+ const stats = await sendQuery(ctx, sqlText);
195
+ if (stats.hadError) hadError = true;
196
+ if (noteConnectionLost()) return {
197
+ hadError,
198
+ stoppedOnError,
199
+ connectionLost
200
+ };
201
+ if (stats.hadError && ctx.settings.onErrorStop) {
202
+ stoppedOnError = true;
203
+ return {
204
+ hadError,
205
+ stoppedOnError,
206
+ connectionLost
207
+ };
208
+ }
209
+ } else try {
210
+ await ctx.settings.db.execSimple(sqlText);
211
+ } catch (err) {
212
+ const msg = err instanceof Error ? err.message : String(err);
213
+ ctx.stderr.write(`psql: ERROR: ${msg}\n`);
214
+ hadError = true;
215
+ if (noteConnectionLost()) return {
216
+ hadError,
217
+ stoppedOnError,
218
+ connectionLost
219
+ };
220
+ if (ctx.settings.onErrorStop) {
221
+ stoppedOnError = true;
222
+ return {
223
+ hadError,
224
+ stoppedOnError,
225
+ connectionLost
226
+ };
227
+ }
228
+ }
229
+ continue;
230
+ }
231
+ if (r.kind === "backslash") {
232
+ queryBuf += r.sql;
233
+ working = working.slice(r.consumed);
234
+ const cmdName = r.cmd;
235
+ if (COND_COMMAND_NAMES.has(cmdName)) continue;
236
+ if (!ctx.cond.isActive()) continue;
237
+ const bctx = makeBackslashContext(ctx, cmdName, r.rest, queryBuf);
238
+ let res;
239
+ try {
240
+ res = await dispatchBackslash(ctx.registry, cmdName, bctx);
241
+ } catch (err) {
242
+ const msg = err instanceof Error ? err.message : String(err);
243
+ ctx.stderr.write(`psql: ERROR: ${msg}\n`);
244
+ hadError = true;
245
+ if (ctx.settings.onErrorStop) {
246
+ stoppedOnError = true;
247
+ return {
248
+ hadError,
249
+ stoppedOnError,
250
+ connectionLost
251
+ };
252
+ }
253
+ continue;
254
+ }
255
+ if (res.status === "exit") return {
256
+ hadError,
257
+ stoppedOnError,
258
+ connectionLost
259
+ };
260
+ if (res.status === "reset-buf") {
261
+ queryBuf = res.newBuf ?? "";
262
+ scanState = initialScanState();
263
+ }
264
+ if (res.status === "error") {
265
+ queryBuf = "";
266
+ scanState = initialScanState();
267
+ }
268
+ if (res.status === "error") hadError = true;
269
+ if (noteConnectionLost()) return {
270
+ hadError,
271
+ stoppedOnError,
272
+ connectionLost
273
+ };
274
+ if (res.status === "error" && ctx.settings.onErrorStop) {
275
+ stoppedOnError = true;
276
+ return {
277
+ hadError,
278
+ stoppedOnError,
279
+ connectionLost
280
+ };
281
+ }
282
+ continue;
283
+ }
284
+ queryBuf += r.sql;
285
+ working = "";
286
+ }
287
+ if (queryBuf.trim().length > 0 && ctx.settings.db && ctx.cond.isActive()) if (print) {
288
+ if ((await sendQuery(ctx, queryBuf)).hadError) hadError = true;
289
+ noteConnectionLost();
290
+ } else try {
291
+ await ctx.settings.db.execSimple(queryBuf);
292
+ } catch (err) {
293
+ const msg = err instanceof Error ? err.message : String(err);
294
+ ctx.stderr.write(`psql: ERROR: ${msg}\n`);
295
+ hadError = true;
296
+ noteConnectionLost();
297
+ }
298
+ return {
299
+ hadError,
300
+ stoppedOnError,
301
+ connectionLost
302
+ };
363
303
  };
364
304
  /**
365
- * Discover and execute `.psqlrc` files against `ctx`. Honors the `-X` flag
366
- * via `opts.skip = true`. Safe to call before the connection is ready —
367
- * commands that need `db` will simply no-op (see `executeInputString`).
368
- */
369
- export const loadPsqlrc = async (ctx, opts = {}) => {
370
- if (opts.skip)
371
- return;
372
- const env = opts.env ?? process.env;
373
- // Single-path mode (test ergonomics / explicit override).
374
- if (opts.path !== undefined) {
375
- const content = await readIfExists(opts.path);
376
- if (content === null)
377
- return;
378
- const prevSource = ctx.settings.curCmdSource;
379
- ctx.settings.curCmdSource = "rcfile";
380
- try {
381
- await executeInputString(content, ctx);
382
- }
383
- finally {
384
- ctx.settings.curCmdSource = prevSource;
385
- }
386
- return;
387
- }
388
- const serverVersion = ctx.settings.db?.serverVersion;
389
- const candidates = psqlrcCandidates(env, serverVersion);
390
- // Upstream `process_psqlrc()` is first-match-wins PER LOCATION: it reads at
391
- // most ONE system file (versioned preferred over unversioned) and then at
392
- // most ONE user file. Running both the versioned AND unversioned file in a
393
- // location double-executes side effects and lets the unversioned file
394
- // clobber the versioned one.
395
- let systemDone = false;
396
- for (const c of candidates) {
397
- const isSystem = c.description.startsWith("system");
398
- if (isSystem && systemDone)
399
- continue; // first system file already ran
400
- const content = await readIfExists(c.path);
401
- if (content === null)
402
- continue;
403
- const prevSource = ctx.settings.curCmdSource;
404
- ctx.settings.curCmdSource = "rcfile";
405
- try {
406
- await executeInputString(content, ctx);
407
- }
408
- finally {
409
- ctx.settings.curCmdSource = prevSource;
410
- }
411
- if (isSystem) {
412
- systemDone = true; // consumed the system location; move to the user one
413
- continue;
414
- }
415
- // First user / $PSQLRC match wins; nothing further to read.
416
- return;
417
- }
305
+ * Discover and execute `.psqlrc` files against `ctx`. Honors the `-X` flag
306
+ * via `opts.skip = true`. Safe to call before the connection is ready —
307
+ * commands that need `db` will simply no-op (see `executeInputString`).
308
+ */
309
+ const loadPsqlrc = async (ctx, opts = {}) => {
310
+ if (opts.skip) return;
311
+ const env = opts.env ?? process.env;
312
+ if (opts.path !== void 0) {
313
+ const content = await readIfExists(opts.path);
314
+ if (content === null) return;
315
+ const prevSource = ctx.settings.curCmdSource;
316
+ ctx.settings.curCmdSource = "rcfile";
317
+ try {
318
+ await executeInputString(content, ctx);
319
+ } finally {
320
+ ctx.settings.curCmdSource = prevSource;
321
+ }
322
+ return;
323
+ }
324
+ const serverVersion = ctx.settings.db?.serverVersion;
325
+ const candidates = psqlrcCandidates(env, serverVersion);
326
+ let systemDone = false;
327
+ for (const c of candidates) {
328
+ const isSystem = c.description.startsWith("system");
329
+ if (isSystem && systemDone) continue;
330
+ const content = await readIfExists(c.path);
331
+ if (content === null) continue;
332
+ const prevSource = ctx.settings.curCmdSource;
333
+ ctx.settings.curCmdSource = "rcfile";
334
+ try {
335
+ await executeInputString(content, ctx);
336
+ } finally {
337
+ ctx.settings.curCmdSource = prevSource;
338
+ }
339
+ if (isSystem) {
340
+ systemDone = true;
341
+ continue;
342
+ }
343
+ return;
344
+ }
418
345
  };
419
- // TODO(WP-26-followup): Refactor `core/mainloop.ts` to export an
420
- // `executeInputString(input, ctx)` primitive, then have this module call it
421
- // instead of duplicating the scan-and-dispatch loop. The duplication today is
422
- // roughly 60 LOC; the refactor would shrink this file by half.
346
+ //#endregion
347
+ export { defaultPsqlrcPath, executeInputString, loadPsqlrc, psqlrcCandidates };