neon 3.0.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.
Files changed (198) hide show
  1. package/README.md +54 -0
  2. package/dist/_shared/auth_selection.js +76 -79
  3. package/dist/_shared/credentials.js +166 -187
  4. package/dist/_shared/env-core/env.js +354 -517
  5. package/dist/_shared/env-core/reuse-secrets.js +159 -203
  6. package/dist/_shared/paths.js +129 -126
  7. package/dist/_shared/profiles.js +192 -242
  8. package/dist/_shared/secure_file.js +36 -38
  9. package/dist/_virtual/_rolldown/runtime.js +13 -0
  10. package/dist/analytics.js +163 -207
  11. package/dist/api.js +815 -758
  12. package/dist/auth.js +121 -141
  13. package/dist/auth_context.js +39 -53
  14. package/dist/cli.js +4 -7
  15. package/dist/commands/api.js +220 -250
  16. package/dist/commands/api_keys.js +251 -314
  17. package/dist/commands/auth.js +283 -328
  18. package/dist/commands/bootstrap.js +372 -437
  19. package/dist/commands/branches.js +304 -455
  20. package/dist/commands/bucket.js +374 -514
  21. package/dist/commands/checkout.js +213 -298
  22. package/dist/commands/config.js +573 -690
  23. package/dist/commands/connection_string.js +137 -165
  24. package/dist/commands/data_api.js +238 -260
  25. package/dist/commands/databases.js +67 -76
  26. package/dist/commands/deploy.js +31 -25
  27. package/dist/commands/dev.js +639 -719
  28. package/dist/commands/diff.js +156 -200
  29. package/dist/commands/env.js +243 -303
  30. package/dist/commands/functions.js +275 -355
  31. package/dist/commands/index.js +70 -65
  32. package/dist/commands/init.js +84 -119
  33. package/dist/commands/inspect.js +55 -55
  34. package/dist/commands/ip_allow.js +88 -120
  35. package/dist/commands/link.js +874 -1019
  36. package/dist/commands/logs.js +291 -0
  37. package/dist/commands/neon_auth.js +725 -933
  38. package/dist/commands/operations.js +34 -25
  39. package/dist/commands/orgs.js +28 -18
  40. package/dist/commands/profile.js +614 -845
  41. package/dist/commands/projects.js +313 -373
  42. package/dist/commands/psql.js +60 -58
  43. package/dist/commands/roles.js +55 -58
  44. package/dist/commands/schema_diff.js +87 -131
  45. package/dist/commands/set_context.js +34 -26
  46. package/dist/commands/snapshots.js +288 -413
  47. package/dist/commands/status.js +41 -37
  48. package/dist/commands/user.js +21 -10
  49. package/dist/commands/vpc_endpoints.js +85 -113
  50. package/dist/config.js +7 -6
  51. package/dist/config_format.js +50 -66
  52. package/dist/config_template.js +128 -157
  53. package/dist/context.js +183 -235
  54. package/dist/current_branch_fast_path.js +40 -49
  55. package/dist/dev/env.js +313 -394
  56. package/dist/dev/functions.js +54 -68
  57. package/dist/dev/inputs.js +46 -58
  58. package/dist/dev/runtime.js +135 -164
  59. package/dist/dev/websocket.js +766 -959
  60. package/dist/env.js +27 -33
  61. package/dist/env_file.js +118 -132
  62. package/dist/env_services.js +36 -38
  63. package/dist/errors.js +57 -68
  64. package/dist/functions_api.js +45 -43
  65. package/dist/help.js +189 -140
  66. package/dist/index.js +182 -257
  67. package/dist/init/agents.js +137 -118
  68. package/dist/init/auth.js +58 -68
  69. package/dist/init/bootstrap.js +325 -396
  70. package/dist/init/build_config.js +4 -2
  71. package/dist/init/detect_agent.js +56 -101
  72. package/dist/init/editors.js +35 -52
  73. package/dist/init/enrich_output.js +51 -66
  74. package/dist/init/extension.js +134 -171
  75. package/dist/init/inspect.js +179 -266
  76. package/dist/init/interactive.js +510 -622
  77. package/dist/init/neonctl.js +117 -168
  78. package/dist/init/orchestrate.js +157 -173
  79. package/dist/init/phases/auth.js +188 -202
  80. package/dist/init/phases/cleanup.js +23 -23
  81. package/dist/init/phases/db.js +251 -277
  82. package/dist/init/phases/getting_started.js +213 -223
  83. package/dist/init/phases/mcp.js +174 -224
  84. package/dist/init/phases/migrations.js +247 -248
  85. package/dist/init/phases/neon_auth.js +114 -133
  86. package/dist/init/phases/setup.js +546 -703
  87. package/dist/init/phases/skills.js +75 -86
  88. package/dist/init/phases/status.js +72 -67
  89. package/dist/init/resolve_context.js +102 -99
  90. package/dist/init/route_command.js +91 -98
  91. package/dist/init/skills.js +174 -218
  92. package/dist/init/vsix.js +77 -99
  93. package/dist/log.js +17 -16
  94. package/dist/neon_services.js +104 -129
  95. package/dist/parameters.gen.js +481 -471
  96. package/dist/pkg.js +17 -19
  97. package/dist/profile_keys.js +44 -47
  98. package/dist/psql/cli.js +44 -47
  99. package/dist/psql/command/cmd_cond.js +231 -406
  100. package/dist/psql/command/cmd_connect.js +557 -764
  101. package/dist/psql/command/cmd_copy.js +727 -983
  102. package/dist/psql/command/cmd_describe.js +1499 -1688
  103. package/dist/psql/command/cmd_format.js +733 -905
  104. package/dist/psql/command/cmd_io.js +1293 -2082
  105. package/dist/psql/command/cmd_lo.js +297 -359
  106. package/dist/psql/command/cmd_meta.js +727 -878
  107. package/dist/psql/command/cmd_misc.js +138 -172
  108. package/dist/psql/command/cmd_pipeline.js +547 -1099
  109. package/dist/psql/command/cmd_restrict.js +119 -155
  110. package/dist/psql/command/cmd_show.js +529 -688
  111. package/dist/psql/command/dispatch.js +261 -325
  112. package/dist/psql/command/inputQueue.js +35 -33
  113. package/dist/psql/command/shared.js +49 -63
  114. package/dist/psql/complete/filenames.js +90 -133
  115. package/dist/psql/complete/index.js +59 -97
  116. package/dist/psql/complete/matcher.js +236 -300
  117. package/dist/psql/complete/psqlVars.js +218 -223
  118. package/dist/psql/complete/queries.js +159 -177
  119. package/dist/psql/complete/rules.js +1493 -2299
  120. package/dist/psql/core/common.js +762 -1180
  121. package/dist/psql/core/help.js +456 -546
  122. package/dist/psql/core/mainloop.js +692 -1302
  123. package/dist/psql/core/prompt.js +391 -408
  124. package/dist/psql/core/settings.js +429 -644
  125. package/dist/psql/core/sqlHelp.js +480 -554
  126. package/dist/psql/core/startup.js +626 -815
  127. package/dist/psql/core/syncVars.js +67 -110
  128. package/dist/psql/core/variables.js +156 -278
  129. package/dist/psql/describe/formatters.js +884 -1285
  130. package/dist/psql/describe/processNamePattern.js +173 -260
  131. package/dist/psql/describe/queries.js +1368 -2403
  132. package/dist/psql/describe/versionGate.js +32 -41
  133. package/dist/psql/index.js +1414 -1927
  134. package/dist/psql/io/history.js +232 -271
  135. package/dist/psql/io/input.js +103 -108
  136. package/dist/psql/io/lineEditor/buffer.js +238 -319
  137. package/dist/psql/io/lineEditor/complete.js +135 -213
  138. package/dist/psql/io/lineEditor/filename.js +139 -148
  139. package/dist/psql/io/lineEditor/index.js +653 -870
  140. package/dist/psql/io/lineEditor/keymap.js +544 -702
  141. package/dist/psql/io/lineEditor/vt100.js +294 -341
  142. package/dist/psql/io/pgpass.js +158 -187
  143. package/dist/psql/io/pgservice.js +146 -183
  144. package/dist/psql/io/psqlrc.js +328 -403
  145. package/dist/psql/print/aligned.js +1020 -1683
  146. package/dist/psql/print/asciidoc.js +180 -214
  147. package/dist/psql/print/crosstab.js +281 -442
  148. package/dist/psql/print/csv.js +48 -70
  149. package/dist/psql/print/html.js +195 -226
  150. package/dist/psql/print/json.js +75 -88
  151. package/dist/psql/print/latex.js +291 -364
  152. package/dist/psql/print/pager.js +171 -242
  153. package/dist/psql/print/troff.js +194 -226
  154. package/dist/psql/print/unaligned.js +69 -95
  155. package/dist/psql/print/units.js +167 -169
  156. package/dist/psql/scanner/slash.js +428 -483
  157. package/dist/psql/scanner/sql.js +445 -889
  158. package/dist/psql/scanner/stringutils.js +309 -379
  159. package/dist/psql/types/index.js +2 -7
  160. package/dist/psql/types/scanner.js +25 -22
  161. package/dist/psql/wire/connection.js +2042 -2803
  162. package/dist/psql/wire/copy.js +84 -100
  163. package/dist/psql/wire/notify.js +39 -59
  164. package/dist/psql/wire/pipeline.js +305 -518
  165. package/dist/psql/wire/protocol.js +349 -417
  166. package/dist/psql/wire/sasl.js +180 -265
  167. package/dist/psql/wire/tls.js +400 -561
  168. package/dist/storage_api.js +115 -129
  169. package/dist/test_utils/fixtures.js +94 -113
  170. package/dist/test_utils/oauth_server.js +10 -7
  171. package/dist/test_utils/project_dir.js +33 -0
  172. package/dist/utils/ai_gateway_notice.js +131 -162
  173. package/dist/utils/api_enums.js +21 -28
  174. package/dist/utils/auth.js +10 -4
  175. package/dist/utils/branch_notice.js +20 -19
  176. package/dist/utils/branch_picker.js +83 -89
  177. package/dist/utils/cli_name.js +15 -12
  178. package/dist/utils/compute_units.js +20 -27
  179. package/dist/utils/config_diff.js +127 -158
  180. package/dist/utils/enrichers.js +95 -148
  181. package/dist/utils/esbuild.js +130 -189
  182. package/dist/utils/flags.js +35 -47
  183. package/dist/utils/formats.js +8 -15
  184. package/dist/utils/git_diff.js +69 -80
  185. package/dist/utils/inspect_db.js +101 -143
  186. package/dist/utils/inspect_queries.js +179 -142
  187. package/dist/utils/middlewares.js +37 -44
  188. package/dist/utils/openapi.js +87 -99
  189. package/dist/utils/package_manager.js +312 -110
  190. package/dist/utils/point_in_time.js +49 -53
  191. package/dist/utils/psql.js +89 -106
  192. package/dist/utils/service_picker.js +55 -58
  193. package/dist/utils/string.js +5 -5
  194. package/dist/utils/ui.js +38 -55
  195. package/dist/utils/write_sync.js +26 -35
  196. package/dist/utils/zip.js +4 -3
  197. package/dist/writer.js +67 -87
  198. package/package.json +7 -5
@@ -1,159 +1,106 @@
1
1
  import { isNeonApiError, messageFromBody } from "../api.js";
2
2
  import { isConfigInit, isCurrentBranchProbe } from "../context.js";
3
3
  import { looksLikeBranchId } from "./formats.js";
4
- export const branchIdResolve = async ({ branch, apiClient, projectId, }) => {
5
- branch = branch.toString();
6
- if (looksLikeBranchId(branch)) {
7
- return branch;
8
- }
9
- const { data } = await apiClient.listProjectBranches({
10
- projectId,
11
- });
12
- const branchData = data.branches.find((b) => b.name === branch);
13
- if (!branchData) {
14
- throw new Error(`Branch ${branch} not found.\nAvailable branches: ${data.branches
15
- .map((b) => b.name)
16
- .join(", ")}`);
17
- }
18
- return branchData.id;
4
+ //#region src/utils/enrichers.ts
5
+ const branchIdResolve = async ({ branch, apiClient, projectId }) => {
6
+ branch = branch.toString();
7
+ if (looksLikeBranchId(branch)) return branch;
8
+ const { data } = await apiClient.listProjectBranches({ projectId });
9
+ const branchData = data.branches.find((b) => b.name === branch);
10
+ if (!branchData) throw new Error(`Branch ${branch} not found.\nAvailable branches: ${data.branches.map((b) => b.name).join(", ")}`);
11
+ return branchData.id;
19
12
  };
20
13
  const getBranchIdFromProps = async (props) => {
21
- const branch = "branch" in props && typeof props.branch === "string"
22
- ? props.branch
23
- : props.id;
24
- if (branch) {
25
- return await branchIdResolve({
26
- branch,
27
- apiClient: props.apiClient,
28
- projectId: props.projectId,
29
- });
30
- }
31
- const { data } = await props.apiClient.listProjectBranches({
32
- projectId: props.projectId,
33
- });
34
- const defaultBranch = data.branches.find((b) => b.default);
35
- if (defaultBranch) {
36
- return defaultBranch.id;
37
- }
38
- throw new Error("No default branch found");
14
+ const branch = "branch" in props && typeof props.branch === "string" ? props.branch : props.id;
15
+ if (branch) return await branchIdResolve({
16
+ branch,
17
+ apiClient: props.apiClient,
18
+ projectId: props.projectId
19
+ });
20
+ const { data } = await props.apiClient.listProjectBranches({ projectId: props.projectId });
21
+ const defaultBranch = data.branches.find((b) => b.default);
22
+ if (defaultBranch) return defaultBranch.id;
23
+ throw new Error("No default branch found");
39
24
  };
40
- export const branchIdFromProps = async (props) => {
41
- props.branchId = await getBranchIdFromProps(props);
42
- return props.branchId;
25
+ const branchIdFromProps = async (props) => {
26
+ props.branchId = await getBranchIdFromProps(props);
27
+ return props.branchId;
43
28
  };
44
- export const resolveBranchRef = async (props) => {
45
- const branch = typeof props.branch === "string" ? props.branch : props.id;
46
- const { data } = await props.apiClient.listProjectBranches({
47
- projectId: props.projectId,
48
- });
49
- const branches = data.branches;
50
- if (branch) {
51
- const ref = branch.toString();
52
- const found = looksLikeBranchId(ref)
53
- ? branches.find((b) => b.id === ref)
54
- : branches.find((b) => b.name === ref);
55
- if (found) {
56
- return {
57
- branchId: found.id,
58
- branchName: found.name ?? found.id,
59
- usedDefault: false,
60
- };
61
- }
62
- // A `br-…` id absent from the listing is still usable as an id (trust it like
63
- // branchIdResolve does); only an unresolved *name* is a genuine error.
64
- if (looksLikeBranchId(ref)) {
65
- return { branchId: ref, branchName: ref, usedDefault: false };
66
- }
67
- throw new Error(`Branch ${ref} not found.\nAvailable branches: ${branches
68
- .map((b) => b.name)
69
- .join(", ")}`);
70
- }
71
- const defaultBranch = branches.find((b) => b.default);
72
- if (!defaultBranch) {
73
- throw new Error("No default branch found");
74
- }
75
- return {
76
- branchId: defaultBranch.id,
77
- branchName: defaultBranch.name ?? defaultBranch.id,
78
- usedDefault: true,
79
- };
29
+ const resolveBranchRef = async (props) => {
30
+ const branch = typeof props.branch === "string" ? props.branch : props.id;
31
+ const { data } = await props.apiClient.listProjectBranches({ projectId: props.projectId });
32
+ const branches = data.branches;
33
+ if (branch) {
34
+ const ref = branch.toString();
35
+ const found = looksLikeBranchId(ref) ? branches.find((b) => b.id === ref) : branches.find((b) => b.name === ref);
36
+ if (found) return {
37
+ branchId: found.id,
38
+ branchName: found.name ?? found.id,
39
+ usedDefault: false
40
+ };
41
+ if (looksLikeBranchId(ref)) return {
42
+ branchId: ref,
43
+ branchName: ref,
44
+ usedDefault: false
45
+ };
46
+ throw new Error(`Branch ${ref} not found.\nAvailable branches: ${branches.map((b) => b.name).join(", ")}`);
47
+ }
48
+ const defaultBranch = branches.find((b) => b.default);
49
+ if (!defaultBranch) throw new Error("No default branch found");
50
+ return {
51
+ branchId: defaultBranch.id,
52
+ branchName: defaultBranch.name ?? defaultBranch.id,
53
+ usedDefault: true
54
+ };
80
55
  };
81
- export const resolveSingleDatabase = async (props) => {
82
- const { data } = await props.apiClient.listProjectBranchDatabases(props.projectId, props.branchId);
83
- const databases = data.databases;
84
- if (props.database !== undefined) {
85
- if (!databases.find((d) => d.name === props.database)) {
86
- throw new Error(`Database not found: ${props.database}. Available databases on branch ${props.branchId}: ${databases.map((d) => d.name).join(", ")}`);
87
- }
88
- return props.database;
89
- }
90
- if (databases.length === 0) {
91
- throw new Error(`No databases found for the branch: ${props.branchId}`);
92
- }
93
- if (databases.length === 1) {
94
- return databases[0].name;
95
- }
96
- throw new Error(`Multiple databases found for the branch, please provide one with the --database option: ${databases.map((d) => d.name).join(", ")}`);
56
+ const resolveSingleDatabase = async (props) => {
57
+ const { data } = await props.apiClient.listProjectBranchDatabases(props.projectId, props.branchId);
58
+ const databases = data.databases;
59
+ if (props.database !== void 0) {
60
+ if (!databases.find((d) => d.name === props.database)) throw new Error(`Database not found: ${props.database}. Available databases on branch ${props.branchId}: ${databases.map((d) => d.name).join(", ")}`);
61
+ return props.database;
62
+ }
63
+ if (databases.length === 0) throw new Error(`No databases found for the branch: ${props.branchId}`);
64
+ if (databases.length === 1) return databases[0].name;
65
+ throw new Error(`Multiple databases found for the branch, please provide one with the --database option: ${databases.map((d) => d.name).join(", ")}`);
97
66
  };
98
- export const fillSingleProject = async (props) => {
99
- // The offline `--current-branch` probe needs no project at all and runs with no
100
- // API client (auth was skipped), so resolving a single project here would both
101
- // hit the network and dereference a null client. Skip it entirely.
102
- if (isCurrentBranchProbe(props)) {
103
- return props;
104
- }
105
- // `config init` is purely local (scaffold + npm install) and runs with no API
106
- // client, so resolving a single project here would dereference a null client.
107
- if (isConfigInit(props)) {
108
- return props;
109
- }
110
- if (props.projectId) {
111
- return { ...props, projectId: props.projectId };
112
- }
113
- // If no orgId is provided, try to auto-fill it if there's only one org
114
- let orgId = props.orgId;
115
- if (!orgId) {
116
- const { data: orgsData } = await props.apiClient.getCurrentUserOrganizations();
117
- if (orgsData.organizations.length === 1) {
118
- orgId = orgsData.organizations[0].id;
119
- }
120
- }
121
- try {
122
- const { data } = await props.apiClient.listProjects({
123
- limit: 2,
124
- org_id: orgId,
125
- });
126
- if (data.projects.length === 0) {
127
- throw new Error("No projects found");
128
- }
129
- if (data.projects.length > 1) {
130
- throw new Error(`Multiple projects found, please provide one with the --project-id option`);
131
- }
132
- return {
133
- ...props,
134
- projectId: data.projects[0].id,
135
- };
136
- }
137
- catch (error) {
138
- // If the API error is about missing org_id, provide a user-friendly message
139
- if (isNeonApiError(error) &&
140
- error.status === 400 &&
141
- messageFromBody(error.data)?.includes("org_id is required")) {
142
- throw new Error("Multiple projects found, please provide one with the --project-id option");
143
- }
144
- throw error;
145
- }
67
+ const fillSingleProject = async (props) => {
68
+ if (isCurrentBranchProbe(props)) return props;
69
+ if (isConfigInit(props)) return props;
70
+ if (props.projectId) return {
71
+ ...props,
72
+ projectId: props.projectId
73
+ };
74
+ let orgId = props.orgId;
75
+ if (!orgId) {
76
+ const { data: orgsData } = await props.apiClient.getCurrentUserOrganizations();
77
+ if (orgsData.organizations.length === 1) orgId = orgsData.organizations[0].id;
78
+ }
79
+ try {
80
+ const { data } = await props.apiClient.listProjects({
81
+ limit: 2,
82
+ org_id: orgId
83
+ });
84
+ if (data.projects.length === 0) throw new Error("No projects found");
85
+ if (data.projects.length > 1) throw new Error(`Multiple projects found, please provide one with the --project-id option`);
86
+ return {
87
+ ...props,
88
+ projectId: data.projects[0].id
89
+ };
90
+ } catch (error) {
91
+ if (isNeonApiError(error) && error.status === 400 && messageFromBody(error.data)?.includes("org_id is required")) throw new Error("Multiple projects found, please provide one with the --project-id option");
92
+ throw error;
93
+ }
146
94
  };
147
- export const fillSingleOrg = async (props) => {
148
- if (props.orgId) {
149
- return props;
150
- }
151
- const { data } = await props.apiClient.getCurrentUserOrganizations();
152
- if (data.organizations.length === 0) {
153
- throw new Error("No organizations found");
154
- }
155
- if (data.organizations.length > 1) {
156
- throw new Error(`Multiple organizations found, please provide one with the --org-id option`);
157
- }
158
- return { ...props, orgId: data.organizations[0].id };
95
+ const fillSingleOrg = async (props) => {
96
+ if (props.orgId) return props;
97
+ const { data } = await props.apiClient.getCurrentUserOrganizations();
98
+ if (data.organizations.length === 0) throw new Error("No organizations found");
99
+ if (data.organizations.length > 1) throw new Error(`Multiple organizations found, please provide one with the --org-id option`);
100
+ return {
101
+ ...props,
102
+ orgId: data.organizations[0].id
103
+ };
159
104
  };
105
+ //#endregion
106
+ export { branchIdFromProps, branchIdResolve, fillSingleOrg, fillSingleProject, resolveBranchRef, resolveSingleDatabase };
@@ -1,210 +1,151 @@
1
- import { spawn } from "node:child_process";
1
+ import { globalInstallCommand, resolveInvokingPackageManager } from "./package_manager.js";
2
2
  import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
3
  import { basename, join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { spawn } from "node:child_process";
5
6
  import which from "which";
6
- const NOT_FOUND = "esbuild not found. neon ships esbuild for most platforms; if you see " +
7
- "this, install esbuild and ensure it is on your PATH (e.g. `npm i -g " +
8
- "esbuild`), or set NEON_ESBUILD_PATH to an esbuild binary.";
9
- // Prepended to the ESM bundle. Bundled dependencies are frequently CommonJS, but an ESM
10
- // output (`--format=esm`) has no `require` / `__filename` / `__dirname` in scope — so any
11
- // bundled CJS code that calls `require(...)` would fail at load with
12
- // `Dynamic require of "x" is not supported`. Re-create those globals via `createRequire`
13
- // so CJS and ESM dependencies coexist in the single `index.mjs`.
7
+ //#region src/utils/esbuild.ts
8
+ const notFoundMessage = () => {
9
+ const install = globalInstallCommand(resolveInvokingPackageManager(), "esbuild");
10
+ const how = install ? `install esbuild and ensure it is on your PATH (e.g. \`${install.command} ${install.args.join(" ")}\`), or ` : "put an esbuild binary on your PATH, or ";
11
+ return `esbuild not found. neon ships esbuild for most platforms, so this is unexpected. ${how[0].toUpperCase()}${how.slice(1)}set NEON_ESBUILD_PATH to an esbuild binary.`;
12
+ };
14
13
  const ESM_CJS_INTEROP_BANNER = "import{createRequire as ___cr}from'module';import{fileURLToPath as ___f}from'url';import{dirname as ___d}from'path';const require=___cr(import.meta.url);const __filename=___f(import.meta.url);const __dirname=___d(__filename);";
15
14
  const defaultDeps = {
16
- // @yao-pkg/pkg defines process.pkg inside the packaged binary.
17
- isPackaged: () => process.pkg !== undefined,
18
- loadEsbuild: (name) => import(name),
15
+ isPackaged: () => process.pkg !== void 0,
16
+ loadEsbuild: (name) => import(name)
19
17
  };
20
- // Internal signal: the esbuild JS module could not be imported (exotic platform
21
- // or not installed). Tells bundleEntry to fall back to the binary; never shown
22
- // to the user.
23
- class ModuleNotAvailable extends Error {
24
- }
18
+ var ModuleNotAvailable = class extends Error {};
25
19
  const message = (err) => err instanceof Error ? err.message : String(err);
26
20
  const toFilesByBasename = (files) => {
27
- const out = {};
28
- for (const f of files)
29
- out[basename(f.path)] = f.contents;
30
- return out;
21
+ const out = {};
22
+ for (const f of files) out[basename(f.path)] = f.contents;
23
+ return out;
31
24
  };
32
25
  const bundleViaModule = async (source, loadEsbuild, externalPackages) => {
33
- // esbuild is resolved by a COMPUTED specifier, never the literal string
34
- // 'esbuild'. Both rollup (bundle step) and @yao-pkg/pkg (binary step)
35
- // statically scan for literal import()/require() calls and would otherwise
36
- // pull esbuild and its native Go binary into the bundle/snapshot — bloating
37
- // the packaged CLI and emitting "cannot bundle native binary" warnings. The
38
- // packaged binary never imports esbuild at all (the isPackaged guard sends it
39
- // to the binary path), so keeping this specifier invisible to the scanners is
40
- // what keeps esbuild out of the snapshot.
41
- // Do NOT "simplify" this back to import('esbuild').
42
- const name = ["es", "build"].join("");
43
- let esbuild;
44
- try {
45
- esbuild = await loadEsbuild(name);
46
- }
47
- catch {
48
- throw new ModuleNotAvailable();
49
- }
50
- // Mirrors the binary-path bundling flags; write:false keeps output in memory.
51
- // logLevel:'silent' suppresses esbuild's own stderr — the rejected error
52
- // still carries the diagnostic, matching the binary path's captured-stderr.
53
- const result = await esbuild
54
- .build({
55
- entryPoints: [source],
56
- bundle: true,
57
- // Emit `index.mjs` (not `out.js`): the Functions runtime imports the archive's entry
58
- // by the conventional `index.{js,mjs}` name, and `.mjs` makes Node treat the ESM
59
- // output as a module without needing a `package.json` type marker alongside it.
60
- outfile: "index.mjs",
61
- write: false,
62
- minify: true,
63
- format: "esm",
64
- platform: "node",
65
- // Bundle dependencies into the entry so the deployed archive is self-contained (the
66
- // Functions runtime has no node_modules). Node built-ins stay external on
67
- // platform:'node'. The banner re-creates require/__filename/__dirname for bundled CJS.
68
- banner: { js: ESM_CJS_INTEROP_BANNER },
69
- // Only what the policy declared unbundleable; everything else is still inlined.
70
- external: [...externalPackages],
71
- // Reveals which packages were inlined, so a deploy can report an undeclared
72
- // native dependency. Free here — esbuild is already running.
73
- metafile: true,
74
- logLevel: "silent",
75
- })
76
- .catch((err) => {
77
- throw new Error(`Failed to bundle function from ${source}. ${message(err)}`.trim());
78
- });
79
- const files = result.outputFiles ?? [];
80
- // write:false with one entry always yields index.mjs (no source map — we don't emit one);
81
- // an empty set means the API contract changed under us — fail loud rather than ship an
82
- // empty archive.
83
- if (files.length === 0) {
84
- throw new Error(`Failed to bundle function from ${source}. esbuild produced no output.`);
85
- }
86
- return {
87
- files: toFilesByBasename(files),
88
- ...(result.metafile ? { metafile: result.metafile } : {}),
89
- warnings: [],
90
- };
26
+ const name = ["es", "build"].join("");
27
+ let esbuild;
28
+ try {
29
+ esbuild = await loadEsbuild(name);
30
+ } catch {
31
+ throw new ModuleNotAvailable();
32
+ }
33
+ const result = await esbuild.build({
34
+ entryPoints: [source],
35
+ bundle: true,
36
+ outfile: "index.mjs",
37
+ write: false,
38
+ minify: true,
39
+ format: "esm",
40
+ platform: "node",
41
+ banner: { js: ESM_CJS_INTEROP_BANNER },
42
+ external: [...externalPackages],
43
+ metafile: true,
44
+ logLevel: "silent"
45
+ }).catch((err) => {
46
+ throw new Error(`Failed to bundle function from ${source}. ${message(err)}`.trim());
47
+ });
48
+ const files = result.outputFiles ?? [];
49
+ if (files.length === 0) throw new Error(`Failed to bundle function from ${source}. esbuild produced no output.`);
50
+ return {
51
+ files: toFilesByBasename(files),
52
+ ...result.metafile ? { metafile: result.metafile } : {},
53
+ warnings: []
54
+ };
91
55
  };
92
- // Find the esbuild binary at deploy time. An explicit override is authoritative
93
- // (so it fails loudly if wrong); otherwise prefer the host PATH, then a locally
94
- // installed copy.
95
56
  const resolveEsbuild = () => {
96
- const override = process.env.NEON_ESBUILD_PATH;
97
- if (override) {
98
- if (existsSync(override))
99
- return override;
100
- throw new Error(NOT_FOUND);
101
- }
102
- const onPath = which.sync("esbuild", { nothrow: true });
103
- if (onPath)
104
- return onPath;
105
- // CWD-relative (not install-relative): helps the dev checkout where esbuild is
106
- // a devDependency. In `npm i -g` and pkg installs the PATH branch above wins.
107
- const local = join(process.cwd(), "node_modules", ".bin", "esbuild");
108
- if (existsSync(local))
109
- return local;
110
- throw new Error(NOT_FOUND);
57
+ const override = process.env.NEON_ESBUILD_PATH;
58
+ if (override) {
59
+ if (existsSync(override)) return override;
60
+ throw new Error(`NEON_ESBUILD_PATH is set to ${override}, but no file exists there. Point it at an esbuild binary, or unset it to use the one neon ships.`);
61
+ }
62
+ const onPath = which.sync("esbuild", { nothrow: true });
63
+ if (onPath) return onPath;
64
+ const local = join(process.cwd(), "node_modules", ".bin", "esbuild");
65
+ if (existsSync(local)) return local;
66
+ throw new Error(notFoundMessage());
111
67
  };
112
68
  const runEsbuild = (bin, args) => new Promise((resolve, reject) => {
113
- // stderr is captured (NOT inherited): with --log-level=error a success emits
114
- // nothing, and a failure's diagnostic is read out below. Never use 'inherit'.
115
- const child = spawn(bin, args, { stdio: ["ignore", "ignore", "pipe"] });
116
- let stderr = "";
117
- child.stderr.on("data", (chunk) => {
118
- stderr += chunk.toString();
119
- });
120
- child.on("error", reject);
121
- child.on("close", (code) => {
122
- resolve({ code, stderr });
123
- });
69
+ const child = spawn(bin, args, { stdio: [
70
+ "ignore",
71
+ "ignore",
72
+ "pipe"
73
+ ] });
74
+ let stderr = "";
75
+ child.stderr.on("data", (chunk) => {
76
+ stderr += chunk.toString();
77
+ });
78
+ child.on("error", reject);
79
+ child.on("close", (code) => {
80
+ resolve({
81
+ code,
82
+ stderr
83
+ });
84
+ });
124
85
  });
125
86
  const bundleViaBinary = async (source, externalPackages) => {
126
- const bin = resolveEsbuild();
127
- const outDir = mkdtempSync(join(tmpdir(), "neon-fn-bundle-"));
128
- const outfile = join(outDir, "index.mjs");
129
- const metafilePath = join(outDir, "meta.json");
130
- try {
131
- const { code, stderr } = await runEsbuild(bin, [
132
- source,
133
- "--bundle",
134
- `--outfile=${outfile}`,
135
- "--minify",
136
- "--format=esm",
137
- "--platform=node",
138
- `--banner:js=${ESM_CJS_INTEROP_BANNER}`,
139
- // One flag per package, mirroring the module path's `external` array.
140
- ...externalPackages.map((pkg) => `--external:${pkg}`),
141
- // Written beside the output so a deploy can report an undeclared native
142
- // dependency here too, not only on the module path.
143
- `--metafile=${metafilePath}`,
144
- "--log-level=error",
145
- ]);
146
- if (code !== 0) {
147
- throw new Error(`Failed to bundle function from ${source}. ${stderr.trim()}`.trim());
148
- }
149
- // No `--sourcemap`: the Functions runtime has no source-map support, so an uploaded
150
- // `index.mjs.map` is never consumed — emitting it only inflated the archive.
151
- const metafile = readMetafile(metafilePath);
152
- return {
153
- files: { "index.mjs": new Uint8Array(readFileSync(outfile)) },
154
- ...(metafile.metafile ? { metafile: metafile.metafile } : {}),
155
- warnings: metafile.warnings,
156
- };
157
- }
158
- finally {
159
- rmSync(outDir, { recursive: true, force: true });
160
- }
87
+ const bin = resolveEsbuild();
88
+ const outDir = mkdtempSync(join(tmpdir(), "neon-fn-bundle-"));
89
+ const outfile = join(outDir, "index.mjs");
90
+ const metafilePath = join(outDir, "meta.json");
91
+ try {
92
+ const { code, stderr } = await runEsbuild(bin, [
93
+ source,
94
+ "--bundle",
95
+ `--outfile=${outfile}`,
96
+ "--minify",
97
+ "--format=esm",
98
+ "--platform=node",
99
+ `--banner:js=${ESM_CJS_INTEROP_BANNER}`,
100
+ ...externalPackages.map((pkg) => `--external:${pkg}`),
101
+ `--metafile=${metafilePath}`,
102
+ "--log-level=error"
103
+ ]);
104
+ if (code !== 0) throw new Error(`Failed to bundle function from ${source}. ${stderr.trim()}`.trim());
105
+ const metafile = readMetafile(metafilePath);
106
+ return {
107
+ files: { "index.mjs": new Uint8Array(readFileSync(outfile)) },
108
+ ...metafile.metafile ? { metafile: metafile.metafile } : {},
109
+ warnings: metafile.warnings
110
+ };
111
+ } finally {
112
+ rmSync(outDir, {
113
+ recursive: true,
114
+ force: true
115
+ });
116
+ }
161
117
  };
162
118
  /**
163
- * Read the metafile the binary path asked esbuild to write.
164
- *
165
- * We always pass `--metafile`, so an unreadable one means esbuild did not do what it was
166
- * told. That is worth saying rather than swallowing — but not worth failing a deploy over,
167
- * because the metafile only powers an advisory report. Reported and skipped.
168
- */
119
+ * Read the metafile the binary path asked esbuild to write.
120
+ *
121
+ * We always pass `--metafile`, so an unreadable one means esbuild did not do what it was
122
+ * told. That is worth saying rather than swallowing — but not worth failing a deploy over,
123
+ * because the metafile only powers an advisory report. Reported and skipped.
124
+ */
169
125
  const readMetafile = (path) => {
170
- let parsed;
171
- try {
172
- parsed = JSON.parse(readFileSync(path, "utf8"));
173
- }
174
- catch (cause) {
175
- return {
176
- warnings: [
177
- `esbuild was asked for a metafile but none could be read (${message(cause)}). ` +
178
- `The bundle is unaffected; this deploy cannot check for an undeclared ` +
179
- `native dependency.`,
180
- ],
181
- };
182
- }
183
- if (typeof parsed !== "object" || parsed === null) {
184
- return {
185
- warnings: [
186
- "esbuild wrote a metafile that is not an object. The bundle is unaffected; " +
187
- "this deploy cannot check for an undeclared native dependency.",
188
- ],
189
- };
190
- }
191
- return { metafile: parsed, warnings: [] };
126
+ let parsed;
127
+ try {
128
+ parsed = JSON.parse(readFileSync(path, "utf8"));
129
+ } catch (cause) {
130
+ return { warnings: [`esbuild was asked for a metafile but none could be read (${message(cause)}). The bundle is unaffected; this deploy cannot check for an undeclared native dependency.`] };
131
+ }
132
+ if (typeof parsed !== "object" || parsed === null) return { warnings: ["esbuild wrote a metafile that is not an object. The bundle is unaffected; this deploy cannot check for an undeclared native dependency."] };
133
+ return {
134
+ metafile: parsed,
135
+ warnings: []
136
+ };
192
137
  };
193
- // Bundle `source` into the files the Functions archive expects, keyed by
194
- // basename. npm installs bundle in-process via the esbuild module; the packaged
195
- // binary (and platforms esbuild can't run on) shell out to an esbuild binary.
196
- export const bundleEntry = async (source, options = {}) => {
197
- const isPackaged = options.isPackaged ?? defaultDeps.isPackaged;
198
- const loadEsbuild = options.loadEsbuild ?? defaultDeps.loadEsbuild;
199
- const external = options.externalPackages ?? [];
200
- if (isPackaged())
201
- return bundleViaBinary(source, external);
202
- try {
203
- return await bundleViaModule(source, loadEsbuild, external);
204
- }
205
- catch (err) {
206
- if (err instanceof ModuleNotAvailable)
207
- return bundleViaBinary(source, external);
208
- throw err;
209
- }
138
+ const bundleEntry = async (source, options = {}) => {
139
+ const isPackaged = options.isPackaged ?? defaultDeps.isPackaged;
140
+ const loadEsbuild = options.loadEsbuild ?? defaultDeps.loadEsbuild;
141
+ const external = options.externalPackages ?? [];
142
+ if (isPackaged()) return bundleViaBinary(source, external);
143
+ try {
144
+ return await bundleViaModule(source, loadEsbuild, external);
145
+ } catch (err) {
146
+ if (err instanceof ModuleNotAvailable) return bundleViaBinary(source, external);
147
+ throw err;
148
+ }
210
149
  };
150
+ //#endregion
151
+ export { bundleEntry };