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,116 +1,73 @@
1
+ //#region src/psql/core/syncVars.ts
2
+ const asString = (value) => typeof value === "string" ? value : void 0;
3
+ const asPort = (value) => typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
1
4
  /**
2
- * Connection-driven psql variable sync.
3
- *
4
- * TypeScript port of `SyncVariables()` in upstream PostgreSQL's
5
- * `src/bin/psql/command.c`. After every successful connection (the initial
6
- * connect in `runPsql` and each `\c` reconnect), psql refreshes the set of
7
- * read-only "connection" variables that scripts interpolate with `:DBNAME`,
8
- * `:USER`, etc. Without this the names interpolate to their literal text
9
- * (`:USER` → `:USER`) instead of the live connection facts.
10
- *
11
- * The variables synced here mirror upstream's `SyncVariables()`:
12
- *
13
- * - `DBNAME` — connection database
14
- * - `USER` — connection user
15
- * - `HOST` — host the client connected to (a socket directory
16
- * for a Unix-domain socket — starts with `/`)
17
- * - `PORT` — connection port (stringified)
18
- * - `ENCODING` — client encoding name (the `client_encoding`
19
- * ParameterStatus). The mainloop keeps this in
20
- * sync on later `SET client_encoding`; we seed it
21
- * here so it is correct from the first prompt.
22
- * - `SERVER_VERSION_NAME`— the `server_version` ParameterStatus (e.g. `18.4`)
23
- * - `SERVER_VERSION_NUM` — the numeric server version (e.g. `180004`),
24
- * stringified from `Connection.serverVersion`
25
- *
26
- * The CLIENT version variables (`VERSION` / `VERSION_NAME` / `VERSION_NUM`)
27
- * are constant for the life of the process and set once at startup — see
28
- * {@link setStartupVars}.
29
- */
30
- const asString = (value) => typeof value === "string" ? value : undefined;
31
- const asPort = (value) => typeof value === "number" && Number.isFinite(value)
32
- ? String(value)
33
- : undefined;
34
- /**
35
- * Refresh the connection variables (`DBNAME`, `USER`, `HOST`, `PORT`,
36
- * `ENCODING`, `SERVER_VERSION_NAME`, `SERVER_VERSION_NUM`) from the live
37
- * connection. Mirrors upstream `SyncVariables()`. Call after a successful
38
- * initial connect and after each `\c` reconnect.
39
- *
40
- * A variable is only set when the connection actually surfaces a value; this
41
- * leaves any user-set value untouched if the connection cannot report one.
42
- */
43
- export const syncConnectionVars = (vars, conn) => {
44
- const target = conn;
45
- const database = asString(target.database);
46
- if (database !== undefined)
47
- vars.set("DBNAME", database);
48
- const user = asString(target.user);
49
- if (user !== undefined)
50
- vars.set("USER", user);
51
- const host = asString(target.host);
52
- if (host !== undefined)
53
- vars.set("HOST", host);
54
- const port = asPort(target.port);
55
- if (port !== undefined)
56
- vars.set("PORT", port);
57
- // ENCODING tracks the server's `client_encoding` ParameterStatus. The
58
- // mainloop refreshes it after each `SET client_encoding`; seed it here so
59
- // it is populated from the very first prompt (and re-seeded after `\c`).
60
- const encoding = conn.parameterStatus("client_encoding");
61
- if (encoding !== undefined)
62
- vars.set("ENCODING", encoding);
63
- const serverVersionName = conn.parameterStatus("server_version");
64
- if (serverVersionName !== undefined) {
65
- vars.set("SERVER_VERSION_NAME", serverVersionName);
66
- }
67
- // `Connection.serverVersion` is the libpq-style integer (e.g. 180004 for
68
- // 18.4); 0 means "not yet reported" — skip it so we don't write a bogus 0.
69
- if (conn.serverVersion > 0) {
70
- vars.set("SERVER_VERSION_NUM", String(conn.serverVersion));
71
- }
5
+ * Refresh the connection variables (`DBNAME`, `USER`, `HOST`, `PORT`,
6
+ * `ENCODING`, `SERVER_VERSION_NAME`, `SERVER_VERSION_NUM`) from the live
7
+ * connection. Mirrors upstream `SyncVariables()`. Call after a successful
8
+ * initial connect and after each `\c` reconnect.
9
+ *
10
+ * A variable is only set when the connection actually surfaces a value; this
11
+ * leaves any user-set value untouched if the connection cannot report one.
12
+ */
13
+ const syncConnectionVars = (vars, conn) => {
14
+ const target = conn;
15
+ const database = asString(target.database);
16
+ if (database !== void 0) vars.set("DBNAME", database);
17
+ const user = asString(target.user);
18
+ if (user !== void 0) vars.set("USER", user);
19
+ const host = asString(target.host);
20
+ if (host !== void 0) vars.set("HOST", host);
21
+ const port = asPort(target.port);
22
+ if (port !== void 0) vars.set("PORT", port);
23
+ const encoding = conn.parameterStatus("client_encoding");
24
+ if (encoding !== void 0) vars.set("ENCODING", encoding);
25
+ const serverVersionName = conn.parameterStatus("server_version");
26
+ if (serverVersionName !== void 0) vars.set("SERVER_VERSION_NAME", serverVersionName);
27
+ if (conn.serverVersion > 0) vars.set("SERVER_VERSION_NUM", String(conn.serverVersion));
72
28
  };
73
29
  /**
74
- * Set the constant CLIENT version variables once at startup, mirroring how
75
- * upstream psql seeds `VERSION` / `VERSION_NAME` / `VERSION_NUM` from its
76
- * compiled-in `PG_VERSION` / `PG_VERSION_NUM`:
77
- *
78
- * - `VERSION` — the full banner string (upstream: `PostgreSQL <ver> …`).
79
- * - `VERSION_NAME` — the bare version number (upstream: e.g. `18.4`).
80
- * - `VERSION_NUM` — the numeric version (upstream: e.g. `180004`).
81
- *
82
- * The embedded psql is not a real PostgreSQL build, so there is no
83
- * `PG_VERSION` to read. We derive the values from neonctl's own package
84
- * version (passed in as {@link clientVersion}, e.g. `2.22.0`) so the client
85
- * identifier is real and traceable to the shipped binary, while keeping
86
- * upstream's variable *shapes*:
87
- *
88
- * - `VERSION` → `psql-ts (neon) <clientVersion>` — a banner that
89
- * names the implementation so users can tell they are on the embedded
90
- * TS port, mirroring the startup banner's `psql-ts (neon, …)` shape.
91
- * - `VERSION_NAME` → `<clientVersion>` (e.g. `2.22.0`).
92
- * - `VERSION_NUM` → the same version mapped into PG's NNMMPP integer form
93
- * (`2.22.0` → `22200`) via {@link clientVersionNum}, so a script doing a
94
- * numeric `:VERSION_NUM` comparison gets a monotonic integer.
95
- */
96
- export const setStartupVars = (vars, clientVersion) => {
97
- vars.set("VERSION", `psql-ts (neon) ${clientVersion}`);
98
- vars.set("VERSION_NAME", clientVersion);
99
- vars.set("VERSION_NUM", String(clientVersionNum(clientVersion)));
30
+ * Set the constant CLIENT version variables once at startup, mirroring how
31
+ * upstream psql seeds `VERSION` / `VERSION_NAME` / `VERSION_NUM` from its
32
+ * compiled-in `PG_VERSION` / `PG_VERSION_NUM`:
33
+ *
34
+ * - `VERSION` — the full banner string (upstream: `PostgreSQL <ver> …`).
35
+ * - `VERSION_NAME` — the bare version number (upstream: e.g. `18.4`).
36
+ * - `VERSION_NUM` — the numeric version (upstream: e.g. `180004`).
37
+ *
38
+ * The embedded psql is not a real PostgreSQL build, so there is no
39
+ * `PG_VERSION` to read. We derive the values from neonctl's own package
40
+ * version (passed in as {@link clientVersion}, e.g. `2.22.0`) so the client
41
+ * identifier is real and traceable to the shipped binary, while keeping
42
+ * upstream's variable *shapes*:
43
+ *
44
+ * - `VERSION` → `psql-ts (neon) <clientVersion>` — a banner that
45
+ * names the implementation so users can tell they are on the embedded
46
+ * TS port, mirroring the startup banner's `psql-ts (neon, …)` shape.
47
+ * - `VERSION_NAME` → `<clientVersion>` (e.g. `2.22.0`).
48
+ * - `VERSION_NUM` → the same version mapped into PG's NNMMPP integer form
49
+ * (`2.22.0` → `22200`) via {@link clientVersionNum}, so a script doing a
50
+ * numeric `:VERSION_NUM` comparison gets a monotonic integer.
51
+ */
52
+ const setStartupVars = (vars, clientVersion) => {
53
+ vars.set("VERSION", `psql-ts (neon) ${clientVersion}`);
54
+ vars.set("VERSION_NAME", clientVersion);
55
+ vars.set("VERSION_NUM", String(clientVersionNum(clientVersion)));
100
56
  };
101
57
  /**
102
- * Map a `MAJOR.MINOR.PATCH` semver-style version string into PG's
103
- * `PG_VERSION_NUM` integer layout (`MAJOR * 10000 + MINOR * 100 + PATCH`,
104
- * e.g. `2.22.0` → `22200`). Missing components default to 0; a non-numeric
105
- * leading component yields `0`. Kept deliberately tolerant — the value only
106
- * needs to be a monotonic integer for `:VERSION_NUM` comparisons.
107
- */
108
- export const clientVersionNum = (version) => {
109
- const m = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(version.trim());
110
- if (!m)
111
- return 0;
112
- const major = parseInt(m[1], 10);
113
- const minor = m[2] !== undefined ? parseInt(m[2], 10) : 0;
114
- const patch = m[3] !== undefined ? parseInt(m[3], 10) : 0;
115
- return major * 10000 + minor * 100 + patch;
58
+ * Map a `MAJOR.MINOR.PATCH` semver-style version string into PG's
59
+ * `PG_VERSION_NUM` integer layout (`MAJOR * 10000 + MINOR * 100 + PATCH`,
60
+ * e.g. `2.22.0` → `22200`). Missing components default to 0; a non-numeric
61
+ * leading component yields `0`. Kept deliberately tolerant — the value only
62
+ * needs to be a monotonic integer for `:VERSION_NUM` comparisons.
63
+ */
64
+ const clientVersionNum = (version) => {
65
+ const m = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(version.trim());
66
+ if (!m) return 0;
67
+ const major = parseInt(m[1], 10);
68
+ const minor = m[2] !== void 0 ? parseInt(m[2], 10) : 0;
69
+ const patch = m[3] !== void 0 ? parseInt(m[3], 10) : 0;
70
+ return major * 1e4 + minor * 100 + patch;
116
71
  };
72
+ //#endregion
73
+ export { clientVersionNum, setStartupVars, syncConnectionVars };
@@ -1,287 +1,165 @@
1
- /**
2
- * psql Variables store.
3
- *
4
- * TypeScript port of PostgreSQL's `src/bin/psql/variables.c`. Models a psql
5
- * "variable space" — a name → string-value mapping with per-variable
6
- * notification hooks and the parsing helpers psql uses to coerce values to
7
- * booleans, tri-state ("on"/"off"/"auto") values, and integers.
8
- *
9
- * Deviations from upstream that are intentional:
10
- *
11
- * - Storage is a `Map<string, string>` rather than a doubly-linked list.
12
- * Insertion order is preserved by Map (psql sorts alphabetically purely for
13
- * pretty-printing in `\set`; that responsibility belongs to a future
14
- * printer/help WP, not the store).
15
- * - Multiple hooks per name are allowed (upstream has at most one substitute
16
- * + one assign hook per variable). All hooks must return `true` for a
17
- * `set()` to be accepted; if any vetoes, the value is left unchanged.
18
- * - On `addHook()` we synchronously replay the current value (or `null` if
19
- * unset) through the new hook. This matches the upstream behaviour where
20
- * `SetVariableHooks` fires the substitute and assign hooks immediately so
21
- * derived psql state can sync.
22
- * - On `unset()` registered hooks are notified with `null` and remain
23
- * registered. The value is removed from the map (so `has()` returns
24
- * `false`), but a later `set()` will still consult the hooks.
25
- * - Variable names are validated against `[A-Za-z_][A-Za-z0-9_]*` per the
26
- * WP-06 spec. Upstream additionally accepts non-ASCII bytes and a leading
27
- * digit; we deliberately tighten the rule for the TS port.
28
- */
1
+ //#region src/psql/core/variables.ts
29
2
  const VALID_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
30
3
  /** Case-insensitive prefix match: does `value` start with `prefix`? */
31
- const isPrefixOf = (value, prefix) => value.length > 0 &&
32
- value.length <= prefix.length &&
33
- prefix.slice(0, value.length).toLowerCase() === value.toLowerCase();
4
+ const isPrefixOf = (value, prefix) => value.length > 0 && value.length <= prefix.length && prefix.slice(0, value.length).toLowerCase() === value.toLowerCase();
34
5
  /**
35
- * Parse a string the way psql's `ParseVariableBool` does.
36
- *
37
- * Recognised tokens (case-insensitive, with unique-prefix matching for the
38
- * word forms): `true`, `false`, `yes`, `no`, `on`, `off`, `1`, `0`. For `on`
39
- * and `off` we require at least two characters of input — a bare `o` is
40
- * ambiguous and upstream rejects it.
41
- *
42
- * Returns the parsed boolean, or `null` if the string is not recognised.
43
- */
6
+ * Parse a string the way psql's `ParseVariableBool` does.
7
+ *
8
+ * Recognised tokens (case-insensitive, with unique-prefix matching for the
9
+ * word forms): `true`, `false`, `yes`, `no`, `on`, `off`, `1`, `0`. For `on`
10
+ * and `off` we require at least two characters of input — a bare `o` is
11
+ * ambiguous and upstream rejects it.
12
+ *
13
+ * Returns the parsed boolean, or `null` if the string is not recognised.
14
+ */
44
15
  const parseBool = (value) => {
45
- if (value.length === 0)
46
- return null;
47
- if (isPrefixOf(value, "true"))
48
- return true;
49
- if (isPrefixOf(value, "false"))
50
- return false;
51
- if (isPrefixOf(value, "yes"))
52
- return true;
53
- if (isPrefixOf(value, "no"))
54
- return false;
55
- // 'on'/'off' need at least 2 chars; 'o' alone is ambiguous.
56
- if (value.length >= 2) {
57
- const lower = value.toLowerCase();
58
- if ("on".startsWith(lower))
59
- return true;
60
- if ("off".startsWith(lower))
61
- return false;
62
- }
63
- if (value === "1")
64
- return true;
65
- if (value === "0")
66
- return false;
67
- // WP-06 extension: any other strtol-parsable integer is truthy if non-zero,
68
- // falsy if zero. Upstream `ParseVariableBool` rejects "42" outright; we
69
- // accept it so callers don't need a separate code path for numeric flags.
70
- const asNum = parseInt32(value);
71
- if (asNum !== null)
72
- return asNum !== 0;
73
- return null;
16
+ if (value.length === 0) return null;
17
+ if (isPrefixOf(value, "true")) return true;
18
+ if (isPrefixOf(value, "false")) return false;
19
+ if (isPrefixOf(value, "yes")) return true;
20
+ if (isPrefixOf(value, "no")) return false;
21
+ if (value.length >= 2) {
22
+ const lower = value.toLowerCase();
23
+ if ("on".startsWith(lower)) return true;
24
+ if ("off".startsWith(lower)) return false;
25
+ }
26
+ if (value === "1") return true;
27
+ if (value === "0") return false;
28
+ const asNum = parseInt32(value);
29
+ if (asNum !== null) return asNum !== 0;
30
+ return null;
74
31
  };
75
32
  /**
76
- * Parse a string as an integer the way psql's `ParseVariableNum` does
77
- * (base 0, i.e. `0x` and leading-zero octal forms are accepted), and clamp
78
- * to the 32-bit signed range that psql uses (the C cast `numval == (int)
79
- * numval` check).
80
- *
81
- * Returns the integer, or `null` on syntax / range failure.
82
- */
33
+ * Parse a string as an integer the way psql's `ParseVariableNum` does
34
+ * (base 0, i.e. `0x` and leading-zero octal forms are accepted), and clamp
35
+ * to the 32-bit signed range that psql uses (the C cast `numval == (int)
36
+ * numval` check).
37
+ *
38
+ * Returns the integer, or `null` on syntax / range failure.
39
+ */
83
40
  const parseInt32 = (value) => {
84
- if (value.length === 0)
85
- return null;
86
- const trimmed = value.trim();
87
- if (trimmed.length === 0)
88
- return null;
89
- // Match the prefixes strtol(_, _, 0) accepts and pick the matching radix
90
- // explicitly so we can validate the entire string (Number()/parseInt with
91
- // base 0 are not portable enough for this).
92
- let body = trimmed;
93
- let sign = 1;
94
- if (body.startsWith("+")) {
95
- body = body.slice(1);
96
- }
97
- else if (body.startsWith("-")) {
98
- sign = -1;
99
- body = body.slice(1);
100
- }
101
- if (body.length === 0)
102
- return null;
103
- let radix = 10;
104
- if (body.startsWith("0x") || body.startsWith("0X")) {
105
- radix = 16;
106
- body = body.slice(2);
107
- }
108
- else if (body.startsWith("0o") || body.startsWith("0O")) {
109
- radix = 8;
110
- body = body.slice(2);
111
- }
112
- else if (body.length > 1 && body.startsWith("0")) {
113
- // C strtol with base 0 treats a leading 0 as octal. JS users typically
114
- // expect decimal; we follow upstream for behavioural fidelity.
115
- radix = 8;
116
- body = body.slice(1);
117
- }
118
- if (body.length === 0)
119
- return null;
120
- const digitRe = radix === 16 ? /^[0-9a-fA-F]+$/ : radix === 8 ? /^[0-7]+$/ : /^[0-9]+$/;
121
- if (!digitRe.test(body))
122
- return null;
123
- const parsed = sign * parseInt(body, radix);
124
- if (!Number.isFinite(parsed))
125
- return null;
126
- // Match `numval == (int) numval` — 32-bit signed range.
127
- if (parsed < -0x80000000 || parsed > 0x7fffffff)
128
- return null;
129
- return parsed;
41
+ if (value.length === 0) return null;
42
+ const trimmed = value.trim();
43
+ if (trimmed.length === 0) return null;
44
+ let body = trimmed;
45
+ let sign = 1;
46
+ if (body.startsWith("+")) body = body.slice(1);
47
+ else if (body.startsWith("-")) {
48
+ sign = -1;
49
+ body = body.slice(1);
50
+ }
51
+ if (body.length === 0) return null;
52
+ let radix = 10;
53
+ if (body.startsWith("0x") || body.startsWith("0X")) {
54
+ radix = 16;
55
+ body = body.slice(2);
56
+ } else if (body.startsWith("0o") || body.startsWith("0O")) {
57
+ radix = 8;
58
+ body = body.slice(2);
59
+ } else if (body.length > 1 && body.startsWith("0")) {
60
+ radix = 8;
61
+ body = body.slice(1);
62
+ }
63
+ if (body.length === 0) return null;
64
+ if (!(radix === 16 ? /^[0-9a-fA-F]+$/ : radix === 8 ? /^[0-7]+$/ : /^[0-9]+$/).test(body)) return null;
65
+ const parsed = sign * parseInt(body, radix);
66
+ if (!Number.isFinite(parsed)) return null;
67
+ if (parsed < -2147483648 || parsed > 2147483647) return null;
68
+ return parsed;
69
+ };
70
+ var VarStore = class {
71
+ constructor() {
72
+ this.values = /* @__PURE__ */ new Map();
73
+ this.hooks = /* @__PURE__ */ new Map();
74
+ }
75
+ set(name, value) {
76
+ return this.trySet(name, value).ok;
77
+ }
78
+ trySet(name, value) {
79
+ if (!VALID_NAME_RE.test(name)) return {
80
+ ok: false,
81
+ reason: "invalid-name"
82
+ };
83
+ const hooks = this.hooks.get(name);
84
+ let toStore = value;
85
+ if (hooks) for (const hook of hooks) {
86
+ const result = hook(toStore);
87
+ if (result === false) return {
88
+ ok: false,
89
+ reason: "hook-veto"
90
+ };
91
+ if (typeof result === "string") return {
92
+ ok: false,
93
+ reason: "hook-veto",
94
+ error: result
95
+ };
96
+ if (typeof result === "object" && result !== null) toStore = result.substitute;
97
+ }
98
+ this.values.set(name, toStore);
99
+ return { ok: true };
100
+ }
101
+ get(name) {
102
+ return this.values.get(name);
103
+ }
104
+ unset(name) {
105
+ const had = this.values.delete(name);
106
+ const hooks = this.hooks.get(name);
107
+ if (hooks) {
108
+ let substituted = null;
109
+ for (const hook of hooks) {
110
+ const r = hook(null);
111
+ if (typeof r === "object" && r !== null && "substitute" in r) substituted = r.substitute;
112
+ }
113
+ if (substituted !== null) {
114
+ this.values.set(name, substituted);
115
+ for (const hook of hooks) hook(substituted);
116
+ }
117
+ }
118
+ return had;
119
+ }
120
+ has(name) {
121
+ return this.values.has(name);
122
+ }
123
+ hasSubstituteHook(name) {
124
+ const hooks = this.hooks.get(name);
125
+ return hooks !== void 0 && hooks.length > 0;
126
+ }
127
+ addHook(name, hook) {
128
+ if (!VALID_NAME_RE.test(name)) return;
129
+ const existing = this.hooks.get(name);
130
+ if (existing) existing.push(hook);
131
+ else this.hooks.set(name, [hook]);
132
+ const result = hook(this.values.get(name) ?? null);
133
+ if (typeof result === "object" && result !== null && "substitute" in result) {
134
+ this.values.set(name, result.substitute);
135
+ hook(result.substitute);
136
+ }
137
+ }
138
+ entries() {
139
+ return this.values.entries();
140
+ }
141
+ asBool(name, defaultValue = false) {
142
+ const value = this.values.get(name);
143
+ if (value === void 0) return defaultValue;
144
+ return parseBool(value) ?? defaultValue;
145
+ }
146
+ asTriple(name, defaultValue) {
147
+ const value = this.values.get(name);
148
+ if (value === void 0) return defaultValue;
149
+ if (isPrefixOf(value, "auto")) return "auto";
150
+ const parsed = parseBool(value);
151
+ if (parsed === null) return { error: `unrecognized value "${value}" for "${name}": Boolean expected` };
152
+ return parsed ? "on" : "off";
153
+ }
154
+ asInt(name, defaultValue = 0) {
155
+ const value = this.values.get(name);
156
+ if (value === void 0) return defaultValue;
157
+ const parsed = parseInt32(value);
158
+ if (parsed === null) return { error: `invalid value "${value}" for "${name}": integer expected` };
159
+ return parsed;
160
+ }
130
161
  };
131
- export class VarStore {
132
- constructor() {
133
- this.values = new Map();
134
- this.hooks = new Map();
135
- }
136
- set(name, value) {
137
- return this.trySet(name, value).ok;
138
- }
139
- trySet(name, value) {
140
- if (!VALID_NAME_RE.test(name)) {
141
- return { ok: false, reason: "invalid-name" };
142
- }
143
- const hooks = this.hooks.get(name);
144
- let toStore = value;
145
- if (hooks) {
146
- // All hooks must accept the value. Each hook can either:
147
- // - return `true` to accept as-is,
148
- // - return `false` to reject silently (the prior value is kept),
149
- // - return a `string` to reject with that error message
150
- // (cmdSet renders it with the `psql: ` prefix), or
151
- // - return `{ substitute: '<value>' }` to rewrite the stored value
152
- // before subsequent hooks see it.
153
- //
154
- // The substitute return is the collapsed equivalent of upstream's
155
- // separate substitute/assign hook pair (see
156
- // `bool_substitute_hook` + `bool_assign_hook` in `command.c`).
157
- // Hooks are responsible for ensuring their substituted value passes
158
- // their own validation — we do NOT re-run a hook against its own
159
- // substitution.
160
- for (const hook of hooks) {
161
- const result = hook(toStore);
162
- if (result === false) {
163
- return { ok: false, reason: "hook-veto" };
164
- }
165
- if (typeof result === "string") {
166
- return { ok: false, reason: "hook-veto", error: result };
167
- }
168
- if (typeof result === "object" && result !== null) {
169
- toStore = result.substitute;
170
- }
171
- }
172
- }
173
- this.values.set(name, toStore);
174
- return { ok: true };
175
- }
176
- get(name) {
177
- return this.values.get(name);
178
- }
179
- unset(name) {
180
- const had = this.values.delete(name);
181
- const hooks = this.hooks.get(name);
182
- if (hooks) {
183
- // Notify hooks of deletion so they can clear derived state.
184
- // Upstream substitute hooks (e.g. `on_error_rollback_substitute_hook`,
185
- // `bool_substitute_hook`) re-inject a default when `newval == NULL` —
186
- // so `\unset ON_ERROR_ROLLBACK` actually re-stores "off",
187
- // `\unset AUTOCOMMIT` re-stores "on", etc. Honor the substitute by
188
- // re-storing the value the hook returns. Plain `true` / `false` /
189
- // error-string returns mean "no substitute" and the slot stays empty.
190
- let substituted = null;
191
- for (const hook of hooks) {
192
- const r = hook(null);
193
- if (typeof r === "object" && r !== null && "substitute" in r) {
194
- substituted = r.substitute;
195
- }
196
- }
197
- if (substituted !== null) {
198
- this.values.set(name, substituted);
199
- // Re-notify hooks with the substituted value so derived state
200
- // (settings.onErrorRollback, etc.) gets the correct default.
201
- for (const hook of hooks)
202
- hook(substituted);
203
- }
204
- }
205
- return had;
206
- }
207
- has(name) {
208
- return this.values.has(name);
209
- }
210
- hasSubstituteHook(name) {
211
- const hooks = this.hooks.get(name);
212
- return hooks !== undefined && hooks.length > 0;
213
- }
214
- addHook(name, hook) {
215
- if (!VALID_NAME_RE.test(name))
216
- return;
217
- const existing = this.hooks.get(name);
218
- if (existing) {
219
- existing.push(hook);
220
- }
221
- else {
222
- this.hooks.set(name, [hook]);
223
- }
224
- // Replay the current value so the hook can sync immediately, matching
225
- // upstream `SetVariableHooks`:
226
- // if (shook) current->value = (*shook)(current->value);
227
- // if (ahook) (void) (*ahook)(current->value);
228
- // Our hooks combine substitute + assign in a single callback. If the
229
- // initial replay returns a `{substitute}` (the bool_substitute_hook /
230
- // verbosity_substitute_hook etc. pattern), persist that and re-run the
231
- // hook so derived state (settings.verbosity, settings.echo, ...) syncs
232
- // to the substituted value. This is how upstream seeds defaults like
233
- // `ON_ERROR_STOP=off`, `VERBOSITY=default`, `QUIET=off` etc. simply
234
- // from `SetVariableHooks` — no explicit `SetVariable("…", "off")` call
235
- // is needed for variables whose default matches the unset substitute.
236
- const current = this.values.get(name);
237
- const result = hook(current ?? null);
238
- if (typeof result === "object" &&
239
- result !== null &&
240
- "substitute" in result) {
241
- this.values.set(name, result.substitute);
242
- hook(result.substitute);
243
- }
244
- }
245
- entries() {
246
- return this.values.entries();
247
- }
248
- asBool(name, defaultValue = false) {
249
- const value = this.values.get(name);
250
- if (value === undefined)
251
- return defaultValue;
252
- const parsed = parseBool(value);
253
- return parsed ?? defaultValue;
254
- }
255
- asTriple(name, defaultValue) {
256
- const value = this.values.get(name);
257
- if (value === undefined)
258
- return defaultValue;
259
- // "auto" is matched first as a unique prefix, so "a", "au", "aut",
260
- // "auto" all map to 'auto'. psql's actual call site does an
261
- // `pg_strncasecmp(value, "auto", len)` before falling through to
262
- // ParseVariableBool — we do the same.
263
- if (isPrefixOf(value, "auto"))
264
- return "auto";
265
- const parsed = parseBool(value);
266
- if (parsed === null) {
267
- return {
268
- error: `unrecognized value "${value}" for "${name}": Boolean expected`,
269
- };
270
- }
271
- return parsed ? "on" : "off";
272
- }
273
- asInt(name, defaultValue = 0) {
274
- const value = this.values.get(name);
275
- if (value === undefined)
276
- return defaultValue;
277
- const parsed = parseInt32(value);
278
- if (parsed === null) {
279
- return {
280
- error: `invalid value "${value}" for "${name}": integer expected`,
281
- };
282
- }
283
- return parsed;
284
- }
285
- }
286
162
  /** Factory mirroring the upstream `CreateVariableSpace()` entry point. */
287
- export const createVarStore = () => new VarStore();
163
+ const createVarStore = () => new VarStore();
164
+ //#endregion
165
+ export { VarStore, createVarStore };