neonctl 2.27.1 → 2.29.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 (136) hide show
  1. package/README.md +35 -3
  2. package/dist/analytics.js +52 -34
  3. package/dist/api.js +643 -13
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +8 -1
  6. package/dist/commands/auth.js +64 -51
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +160 -150
  9. package/dist/commands/bucket.js +183 -146
  10. package/dist/commands/checkout.js +51 -51
  11. package/dist/commands/config.js +228 -82
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +100 -101
  14. package/dist/commands/databases.js +29 -26
  15. package/dist/commands/deploy.js +12 -12
  16. package/dist/commands/dev.js +114 -114
  17. package/dist/commands/env.js +43 -43
  18. package/dist/commands/functions.js +101 -104
  19. package/dist/commands/index.js +27 -25
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +232 -182
  23. package/dist/commands/neon_auth.js +385 -370
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +103 -101
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +27 -24
  29. package/dist/commands/schema_diff.js +25 -26
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +40 -0
  32. package/dist/commands/user.js +5 -5
  33. package/dist/commands/vpc_endpoints.js +50 -50
  34. package/dist/config.js +7 -7
  35. package/dist/config_format.js +5 -5
  36. package/dist/context.js +37 -14
  37. package/dist/current_branch_fast_path.js +55 -0
  38. package/dist/dev/env.js +33 -33
  39. package/dist/dev/functions.js +4 -4
  40. package/dist/dev/inputs.js +6 -6
  41. package/dist/dev/runtime.js +25 -25
  42. package/dist/env.js +14 -14
  43. package/dist/env_file.js +13 -13
  44. package/dist/errors.js +68 -5
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +110 -107
  48. package/dist/log.js +2 -2
  49. package/dist/parameters.gen.js +14 -14
  50. package/dist/pkg.js +5 -5
  51. package/dist/psql/cli.js +4 -2
  52. package/dist/psql/command/cmd_cond.js +61 -61
  53. package/dist/psql/command/cmd_connect.js +159 -154
  54. package/dist/psql/command/cmd_copy.js +107 -97
  55. package/dist/psql/command/cmd_describe.js +368 -363
  56. package/dist/psql/command/cmd_format.js +276 -263
  57. package/dist/psql/command/cmd_io.js +269 -263
  58. package/dist/psql/command/cmd_lo.js +74 -66
  59. package/dist/psql/command/cmd_meta.js +148 -148
  60. package/dist/psql/command/cmd_misc.js +17 -17
  61. package/dist/psql/command/cmd_pipeline.js +142 -135
  62. package/dist/psql/command/cmd_restrict.js +25 -25
  63. package/dist/psql/command/cmd_show.js +183 -168
  64. package/dist/psql/command/dispatch.js +26 -26
  65. package/dist/psql/command/shared.js +14 -14
  66. package/dist/psql/complete/filenames.js +16 -16
  67. package/dist/psql/complete/index.js +4 -4
  68. package/dist/psql/complete/matcher.js +33 -32
  69. package/dist/psql/complete/psqlVars.js +173 -173
  70. package/dist/psql/complete/queries.js +5 -3
  71. package/dist/psql/complete/rules.js +900 -863
  72. package/dist/psql/core/common.js +136 -133
  73. package/dist/psql/core/help.js +343 -343
  74. package/dist/psql/core/mainloop.js +160 -153
  75. package/dist/psql/core/prompt.js +126 -123
  76. package/dist/psql/core/settings.js +111 -111
  77. package/dist/psql/core/sqlHelp.js +150 -150
  78. package/dist/psql/core/startup.js +211 -205
  79. package/dist/psql/core/syncVars.js +14 -14
  80. package/dist/psql/core/variables.js +24 -24
  81. package/dist/psql/describe/formatters.js +302 -289
  82. package/dist/psql/describe/processNamePattern.js +28 -28
  83. package/dist/psql/describe/queries.js +656 -651
  84. package/dist/psql/index.js +436 -411
  85. package/dist/psql/io/history.js +36 -36
  86. package/dist/psql/io/input.js +15 -15
  87. package/dist/psql/io/lineEditor/buffer.js +27 -25
  88. package/dist/psql/io/lineEditor/complete.js +15 -15
  89. package/dist/psql/io/lineEditor/filename.js +22 -22
  90. package/dist/psql/io/lineEditor/index.js +65 -62
  91. package/dist/psql/io/lineEditor/keymap.js +325 -318
  92. package/dist/psql/io/lineEditor/vt100.js +60 -60
  93. package/dist/psql/io/pgpass.js +18 -18
  94. package/dist/psql/io/pgservice.js +14 -14
  95. package/dist/psql/io/psqlrc.js +46 -46
  96. package/dist/psql/print/aligned.js +175 -166
  97. package/dist/psql/print/asciidoc.js +51 -51
  98. package/dist/psql/print/crosstab.js +34 -31
  99. package/dist/psql/print/csv.js +25 -22
  100. package/dist/psql/print/html.js +54 -54
  101. package/dist/psql/print/json.js +12 -12
  102. package/dist/psql/print/latex.js +118 -118
  103. package/dist/psql/print/pager.js +28 -26
  104. package/dist/psql/print/troff.js +48 -48
  105. package/dist/psql/print/unaligned.js +15 -14
  106. package/dist/psql/print/units.js +17 -17
  107. package/dist/psql/scanner/slash.js +48 -46
  108. package/dist/psql/scanner/sql.js +88 -84
  109. package/dist/psql/scanner/stringutils.js +21 -17
  110. package/dist/psql/types/index.js +7 -7
  111. package/dist/psql/types/scanner.js +8 -8
  112. package/dist/psql/wire/connection.js +341 -327
  113. package/dist/psql/wire/copy.js +7 -7
  114. package/dist/psql/wire/pipeline.js +26 -24
  115. package/dist/psql/wire/protocol.js +102 -102
  116. package/dist/psql/wire/sasl.js +62 -62
  117. package/dist/psql/wire/tls.js +79 -73
  118. package/dist/storage_api.js +22 -23
  119. package/dist/test_utils/fixtures.js +74 -41
  120. package/dist/test_utils/oauth_server.js +5 -5
  121. package/dist/utils/api_enums.js +33 -0
  122. package/dist/utils/branch_notice.js +5 -5
  123. package/dist/utils/branch_picker.js +26 -26
  124. package/dist/utils/compute_units.js +4 -4
  125. package/dist/utils/enrichers.js +28 -16
  126. package/dist/utils/esbuild.js +28 -28
  127. package/dist/utils/formats.js +1 -1
  128. package/dist/utils/middlewares.js +3 -3
  129. package/dist/utils/package_manager.js +68 -0
  130. package/dist/utils/point_in_time.js +12 -12
  131. package/dist/utils/psql.js +30 -30
  132. package/dist/utils/string.js +2 -2
  133. package/dist/utils/ui.js +9 -9
  134. package/dist/utils/zip.js +1 -1
  135. package/dist/writer.js +17 -17
  136. package/package.json +10 -12
@@ -1,33 +1,33 @@
1
- import { spawn, spawnSync } from 'node:child_process';
2
- import { once } from 'node:events';
3
- import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
4
- import { dirname, join, resolve } from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import chalk from 'chalk';
7
- import { log } from '../log.js';
8
- import { bundleEntry } from '../utils/esbuild.js';
9
- import { resolveDevEnv } from '../dev/env.js';
10
- import { resolveFunctionsFromConfig, } from '../dev/functions.js';
11
- import { resolveWatchInputs } from '../dev/inputs.js';
12
- import { branchIdResolve } from '../utils/enrichers.js';
13
- export const command = 'dev';
14
- export const describe = 'Run Neon Functions locally with a dev server';
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { once } from "node:events";
3
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import chalk from "chalk";
7
+ import { resolveDevEnv } from "../dev/env.js";
8
+ import { resolveFunctionsFromConfig, } from "../dev/functions.js";
9
+ import { resolveWatchInputs } from "../dev/inputs.js";
10
+ import { log } from "../log.js";
11
+ import { branchIdResolve } from "../utils/enrichers.js";
12
+ import { bundleEntry } from "../utils/esbuild.js";
13
+ export const command = "dev";
14
+ export const describe = "Run Neon Functions locally with a dev server";
15
15
  export const builder = (argv) => argv
16
- .usage('$0 dev [--source <path>] [options]')
17
- .example('$0 dev --source ./functions/hello.ts', 'Serve one function on a free port with hot reload')
18
- .example('$0 dev', 'Serve every function declared in neon.ts (one dev server each)')
19
- .example('$0 dev --source ./functions/hello.ts --port 3000', 'Serve one function on an explicit port (fails if the port is taken)')
16
+ .usage("$0 dev [--source <path>] [options]")
17
+ .example("$0 dev --source ./functions/hello.ts", "Serve one function on a free port with hot reload")
18
+ .example("$0 dev", "Serve every function declared in neon.ts (one dev server each)")
19
+ .example("$0 dev --source ./functions/hello.ts --port 3000", "Serve one function on an explicit port (fails if the port is taken)")
20
20
  .options({
21
21
  source: {
22
- describe: 'Path to a single function entry module. Omit to serve every ' +
23
- 'function declared in neon.ts.',
24
- type: 'string',
22
+ describe: "Path to a single function entry module. Omit to serve every " +
23
+ "function declared in neon.ts.",
24
+ type: "string",
25
25
  },
26
26
  port: {
27
- describe: 'Port to listen on (single-function mode only, with --source). ' +
28
- 'Fails if taken. Without it (and without a PORT env var) a free ' +
29
- 'port is chosen automatically.',
30
- type: 'number',
27
+ describe: "Port to listen on (single-function mode only, with --source). " +
28
+ "Fails if taken. Without it (and without a PORT env var) a free " +
29
+ "port is chosen automatically.",
30
+ type: "number",
31
31
  },
32
32
  })
33
33
  .strict();
@@ -39,8 +39,8 @@ export const handler = async (props) => {
39
39
  // No --source: --port has no single target to bind, so reject it explicitly
40
40
  // rather than silently ignoring it.
41
41
  if (props.port !== undefined) {
42
- throw new Error('--port can only be used with --source. To set ports for the functions ' +
43
- 'in neon.ts, give each one a `dev.port` in its config.');
42
+ throw new Error("--port can only be used with --source. To set ports for the functions " +
43
+ "in neon.ts, give each one a `dev.port` in its config.");
44
44
  }
45
45
  await runFromConfig(props);
46
46
  };
@@ -61,7 +61,7 @@ const runSingleSource = async (props) => {
61
61
  const unit = {
62
62
  slug: null,
63
63
  source,
64
- bundleDir: join(process.cwd(), 'node_modules', '.neon-dev'),
64
+ bundleDir: join(process.cwd(), "node_modules", ".neon-dev"),
65
65
  childEnv: buildChildEnv(neonEnv, portFromProps(props.port)),
66
66
  label: null,
67
67
  envSummary: { neon: Object.keys(neonEnv), fn: [] },
@@ -80,14 +80,14 @@ const runFromConfig = async (props) => {
80
80
  const branchId = await resolveBranchId(props);
81
81
  const resolved = await resolveFunctionsFromConfig(process.cwd());
82
82
  if (resolved === null) {
83
- throw new Error('No --source given and no neon.ts found. Pass --source <path> to run a ' +
84
- 'single function, or add a neon.ts that declares functions under ' +
85
- '`preview.functions`.');
83
+ throw new Error("No --source given and no neon.ts found. Pass --source <path> to run a " +
84
+ "single function, or add a neon.ts that declares functions under " +
85
+ "`preview.functions`.");
86
86
  }
87
87
  const { configPath, functions } = resolved;
88
88
  if (functions.length === 0) {
89
- throw new Error('neon.ts has no functions to serve. Add at least one under ' +
90
- '`preview.functions`, or pass --source <path>.');
89
+ throw new Error("neon.ts has no functions to serve. Add at least one under " +
90
+ "`preview.functions`, or pass --source <path>.");
91
91
  }
92
92
  const { vars: neonEnv, skipped } = await resolveDevEnv({
93
93
  cwd: process.cwd(),
@@ -147,18 +147,18 @@ const resolveBranchId = async (props) => {
147
147
  });
148
148
  }
149
149
  catch (err) {
150
- log.debug('dev: could not resolve branch id: %s', err instanceof Error ? err.message : String(err));
150
+ log.debug("dev: could not resolve branch id: %s", err instanceof Error ? err.message : String(err));
151
151
  return undefined;
152
152
  }
153
153
  };
154
154
  const DEFAULT_PORT_BASE = 8787;
155
155
  const portFromProps = (port) => {
156
156
  if (port !== undefined)
157
- return { mode: 'explicit', port };
158
- if (process.env.PORT !== undefined && process.env.PORT !== '') {
159
- return { mode: 'explicit', port: Number(process.env.PORT) };
157
+ return { mode: "explicit", port };
158
+ if (process.env.PORT !== undefined && process.env.PORT !== "") {
159
+ return { mode: "explicit", port: Number(process.env.PORT) };
160
160
  }
161
- return { mode: 'search', from: DEFAULT_PORT_BASE };
161
+ return { mode: "search", from: DEFAULT_PORT_BASE };
162
162
  };
163
163
  /**
164
164
  * Translate a {@link PlannedFunction} into a {@link ServedUnit}. Port rules:
@@ -168,13 +168,13 @@ const portFromProps = (port) => {
168
168
  */
169
169
  const plannedToUnit = (fn, branchEnv, searchBase) => {
170
170
  const port = fn.port !== undefined
171
- ? { mode: 'explicit', port: fn.port }
172
- : { mode: 'search', from: searchBase };
171
+ ? { mode: "explicit", port: fn.port }
172
+ : { mode: "search", from: searchBase };
173
173
  const childEnv = buildChildEnv({ ...branchEnv, ...fn.env }, port);
174
174
  return {
175
175
  slug: fn.slug,
176
176
  source: fn.source,
177
- bundleDir: join(process.cwd(), 'node_modules', '.neon-dev', fn.slug),
177
+ bundleDir: join(process.cwd(), "node_modules", ".neon-dev", fn.slug),
178
178
  childEnv,
179
179
  label: fn.slug,
180
180
  envSummary: { neon: Object.keys(branchEnv), fn: Object.keys(fn.env) },
@@ -199,10 +199,10 @@ const buildChildEnv = (neonEnv, port) => {
199
199
  const env = { ...process.env, ...neonEnv };
200
200
  delete env.NEON_DEV_PORT;
201
201
  delete env.NEON_DEV_PORT_BASE;
202
- if (port.mode === 'explicit') {
202
+ if (port.mode === "explicit") {
203
203
  env.NEON_DEV_PORT = String(port.port);
204
204
  }
205
- else if (port.mode === 'search') {
205
+ else if (port.mode === "search") {
206
206
  env.NEON_DEV_PORT_BASE = String(port.from);
207
207
  }
208
208
  return env;
@@ -232,8 +232,8 @@ const runSupervisor = async (units, options = {}) => {
232
232
  bundlePath = await writeBundle(r.unit.source, r.unit.bundleDir);
233
233
  }
234
234
  catch (err) {
235
- r.status = 'error';
236
- logUnit(r.unit, chalk.red('bundle failed: ') +
235
+ r.status = "error";
236
+ logUnit(r.unit, chalk.red("bundle failed: ") +
237
237
  (err instanceof Error ? err.message : String(err)));
238
238
  return;
239
239
  }
@@ -243,15 +243,15 @@ const runSupervisor = async (units, options = {}) => {
243
243
  r.child = next;
244
244
  const ready = waitForReady(next);
245
245
  pipeChildOutput(next, r.unit.label);
246
- next.on('exit', (code, signal) => {
246
+ next.on("exit", (code, signal) => {
247
247
  if (shuttingDown || r.child !== next)
248
248
  return;
249
249
  if (signal) {
250
- log.debug('runtime for %s exited via %s', r.unit.slug ?? '(source)', signal);
250
+ log.debug("runtime for %s exited via %s", r.unit.slug ?? "(source)", signal);
251
251
  return;
252
252
  }
253
253
  if (code && code !== 0 && r.everReady) {
254
- r.status = 'error';
254
+ r.status = "error";
255
255
  logUnit(r.unit, chalk.red(`exited with code ${code} (waiting for a change)`));
256
256
  }
257
257
  });
@@ -259,10 +259,10 @@ const runSupervisor = async (units, options = {}) => {
259
259
  if (port !== null) {
260
260
  r.boundPort = port;
261
261
  r.everReady = true;
262
- r.status = 'ready';
262
+ r.status = "ready";
263
263
  }
264
264
  else {
265
- r.status = 'error';
265
+ r.status = "error";
266
266
  }
267
267
  };
268
268
  const restart = (r) => {
@@ -272,14 +272,14 @@ const runSupervisor = async (units, options = {}) => {
272
272
  clearTimeout(r.restartTimer);
273
273
  r.restartTimer = setTimeout(() => {
274
274
  void (async () => {
275
- logUnit(r.unit, chalk.dim('change detected, restarting…'));
275
+ logUnit(r.unit, chalk.dim("change detected, restarting…"));
276
276
  if (r.child)
277
277
  await killTree(r.child);
278
278
  if (shuttingDown)
279
279
  return;
280
280
  await bundleAndStart(r);
281
- if (r.status === 'ready') {
282
- logUnit(r.unit, chalk.green('ready') + ` ${urlFor(r.boundPort)}`);
281
+ if (r.status === "ready") {
282
+ logUnit(r.unit, chalk.green("ready") + ` ${urlFor(r.boundPort)}`);
283
283
  }
284
284
  })();
285
285
  }, 150);
@@ -304,9 +304,9 @@ const runSupervisor = async (units, options = {}) => {
304
304
  };
305
305
  // Start every unit. They are independent: keep going if one fails.
306
306
  await Promise.all(running.map((r) => startUnit(r)));
307
- if (running.every((r) => r.status === 'error')) {
307
+ if (running.every((r) => r.status === "error")) {
308
308
  await Promise.all(running.map((r) => stopUnit(r)));
309
- throw new Error('No function started. See the output above for details.');
309
+ throw new Error("No function started. See the output above for details.");
310
310
  }
311
311
  printBanner(running, envNote);
312
312
  // Config mode only: watch neon.ts and reconcile the live unit set when it changes.
@@ -347,12 +347,12 @@ const runSupervisor = async (units, options = {}) => {
347
347
  void (async () => {
348
348
  await configWatcher?.close();
349
349
  await Promise.all(running.map((r) => stopUnit(r)));
350
- log.info(chalk.dim('Stopped the dev server.'));
350
+ log.info(chalk.dim("Stopped the dev server."));
351
351
  resolveRun();
352
352
  })();
353
353
  };
354
- process.on('SIGINT', shutdown);
355
- process.on('SIGTERM', shutdown);
354
+ process.on("SIGINT", shutdown);
355
+ process.on("SIGTERM", shutdown);
356
356
  });
357
357
  };
358
358
  const makeRunningUnit = (unit) => ({
@@ -362,7 +362,7 @@ const makeRunningUnit = (unit) => ({
362
362
  everReady: false,
363
363
  restartTimer: null,
364
364
  watcher: null,
365
- status: 'starting',
365
+ status: "starting",
366
366
  });
367
367
  /**
368
368
  * Pure slug-keyed diff of the live units against the freshly-resolved desired set:
@@ -417,16 +417,16 @@ const reconcileOnce = async (running, replan, ops) => {
417
417
  desired = await replan(nextSearchBase(running));
418
418
  }
419
419
  catch (err) {
420
- log.info(chalk.red('neon.ts change ignored: ') +
420
+ log.info(chalk.red("neon.ts change ignored: ") +
421
421
  (err instanceof Error ? err.message : String(err)) +
422
- chalk.dim(' (fix it and save again)'));
422
+ chalk.dim(" (fix it and save again)"));
423
423
  return;
424
424
  }
425
425
  if (ops.isShuttingDown())
426
426
  return;
427
427
  const plan = diffUnits(running, desired);
428
428
  for (const r of plan.remove) {
429
- logUnit(r.unit, chalk.dim('removed from neon.ts, stopping…'));
429
+ logUnit(r.unit, chalk.dim("removed from neon.ts, stopping…"));
430
430
  await ops.stopUnit(r);
431
431
  const idx = running.indexOf(r);
432
432
  if (idx !== -1)
@@ -438,16 +438,16 @@ const reconcileOnce = async (running, replan, ops) => {
438
438
  const added = plan.add.map((unit) => {
439
439
  const r = makeRunningUnit(unit);
440
440
  running.push(r);
441
- logUnit(unit, chalk.dim('added in neon.ts, starting…'));
441
+ logUnit(unit, chalk.dim("added in neon.ts, starting…"));
442
442
  return r;
443
443
  });
444
444
  await Promise.all(added.map((r) => ops.startUnit(r)));
445
445
  for (const r of added) {
446
- if (r.status === 'ready') {
446
+ if (r.status === "ready") {
447
447
  const env = formatEnvSummary(r.unit.envSummary);
448
- logUnit(r.unit, chalk.green('ready') +
448
+ logUnit(r.unit, chalk.green("ready") +
449
449
  ` ${urlFor(r.boundPort)}` +
450
- (env ? chalk.dim(` ${env}`) : ''));
450
+ (env ? chalk.dim(` ${env}`) : ""));
451
451
  }
452
452
  }
453
453
  }
@@ -472,7 +472,7 @@ const nextSearchBase = (running) => {
472
472
  */
473
473
  const spawnChild = (unit, runtimePath, bundlePath) => {
474
474
  return spawn(process.execPath, [runtimePath, bundlePath], {
475
- stdio: ['ignore', 'pipe', 'pipe'],
475
+ stdio: ["ignore", "pipe", "pipe"],
476
476
  env: unit.childEnv,
477
477
  detached: true,
478
478
  });
@@ -485,23 +485,23 @@ const writeBundle = async (source, bundleDir) => {
485
485
  for (const [name, contents] of Object.entries(files)) {
486
486
  writeFileSync(join(bundleDir, name), contents);
487
487
  }
488
- return join(bundleDir, 'index.mjs');
488
+ return join(bundleDir, "index.mjs");
489
489
  };
490
- const urlFor = (port) => port === null ? chalk.red('not running') : `http://localhost:${port}`;
490
+ const urlFor = (port) => port === null ? chalk.red("not running") : `http://localhost:${port}`;
491
491
  const waitForReady = (child) => new Promise((resolveReady) => {
492
492
  let settled = false;
493
- let buffer = '';
493
+ let buffer = "";
494
494
  const onData = (chunk) => {
495
495
  buffer += chunk.toString();
496
496
  const match = READY_PATTERN.exec(buffer);
497
497
  if (match && !settled) {
498
498
  settled = true;
499
- child.stdout?.off('data', onData);
499
+ child.stdout?.off("data", onData);
500
500
  resolveReady(Number(match[1]));
501
501
  }
502
502
  };
503
- child.stdout?.on('data', onData);
504
- child.once('exit', () => {
503
+ child.stdout?.on("data", onData);
504
+ child.once("exit", () => {
505
505
  if (!settled) {
506
506
  settled = true;
507
507
  resolveReady(null);
@@ -514,13 +514,13 @@ const waitForReady = (child) => new Promise((resolveReady) => {
514
514
  * prefixed with `[slug]` so concurrent servers' output stays readable.
515
515
  */
516
516
  const pipeChildOutput = (child, label) => {
517
- const prefix = label ? chalk.dim(`[${label}] `) : '';
517
+ const prefix = label ? chalk.dim(`[${label}] `) : "";
518
518
  const forward = (stream) => {
519
- let buffer = '';
520
- child[stream]?.on('data', (chunk) => {
519
+ let buffer = "";
520
+ child[stream]?.on("data", (chunk) => {
521
521
  buffer += chunk.toString();
522
- const lines = buffer.split('\n');
523
- buffer = lines.pop() ?? '';
522
+ const lines = buffer.split("\n");
523
+ buffer = lines.pop() ?? "";
524
524
  for (const line of lines) {
525
525
  if (READY_PATTERN.test(line))
526
526
  continue;
@@ -528,26 +528,26 @@ const pipeChildOutput = (child, label) => {
528
528
  }
529
529
  });
530
530
  };
531
- forward('stdout');
532
- forward('stderr');
531
+ forward("stdout");
532
+ forward("stderr");
533
533
  };
534
534
  const printBanner = (running, envNote) => {
535
- log.info('');
536
- log.info(chalk.green.bold(' Neon Functions dev server'));
537
- log.info('');
535
+ log.info("");
536
+ log.info(chalk.green.bold(" Neon Functions dev server"));
537
+ log.info("");
538
538
  for (const r of running) {
539
- const name = r.unit.label ?? 'function';
539
+ const name = r.unit.label ?? "function";
540
540
  const url = urlFor(r.boundPort);
541
541
  log.info(` ${chalk.dim(name.padEnd(20))} ${url}`);
542
542
  const env = formatEnvSummary(r.unit.envSummary);
543
543
  if (env)
544
- log.info(` ${' '.repeat(20)} ${chalk.dim(env)}`);
544
+ log.info(` ${" ".repeat(20)} ${chalk.dim(env)}`);
545
545
  }
546
546
  if (envNote) {
547
- log.info('');
548
- log.info(` ${chalk.yellow('!')} ${chalk.dim(`Neon env: ${envNote}`)}`);
547
+ log.info("");
548
+ log.info(` ${chalk.yellow("!")} ${chalk.dim(`Neon env: ${envNote}`)}`);
549
549
  }
550
- log.info('');
550
+ log.info("");
551
551
  };
552
552
  /**
553
553
  * Render a unit's injected env into one transparent line for the banner, e.g.
@@ -557,22 +557,22 @@ const printBanner = (running, envNote) => {
557
557
  */
558
558
  export const formatEnvSummary = (summary) => {
559
559
  if (!summary)
560
- return '';
560
+ return "";
561
561
  const parts = [];
562
562
  if (summary.neon.length > 0) {
563
- parts.push(`env: ${[...summary.neon].sort().join(', ')}`);
563
+ parts.push(`env: ${[...summary.neon].sort().join(", ")}`);
564
564
  }
565
565
  if (summary.fn.length > 0) {
566
- parts.push(`neon.ts: ${[...summary.fn].sort().join(', ')}`);
566
+ parts.push(`neon.ts: ${[...summary.fn].sort().join(", ")}`);
567
567
  }
568
- return parts.join(' · ');
568
+ return parts.join(" · ");
569
569
  };
570
570
  const logUnit = (unit, message) => {
571
- const prefix = unit.label ? chalk.dim(`[${unit.label}] `) : '';
571
+ const prefix = unit.label ? chalk.dim(`[${unit.label}] `) : "";
572
572
  log.info(`${prefix}${message}`);
573
573
  };
574
574
  const startWatcher = async (source, restart) => {
575
- const { default: chokidar } = await import('chokidar');
575
+ const { default: chokidar } = await import("chokidar");
576
576
  const initialInputs = await resolveWatchInputs(source);
577
577
  if (initialInputs === null) {
578
578
  return startDirectoryWatcher(chokidar, source, restart);
@@ -588,10 +588,10 @@ const startWatcher = async (source, restart) => {
588
588
  * jiti-loaded config.
589
589
  */
590
590
  const startConfigWatcher = async (configPath, onChange) => {
591
- const { default: chokidar } = await import('chokidar');
591
+ const { default: chokidar } = await import("chokidar");
592
592
  const watcher = chokidar.watch(configPath, { ignoreInitial: true });
593
- await once(watcher, 'ready');
594
- watcher.on('all', () => {
593
+ await once(watcher, "ready");
594
+ watcher.on("all", () => {
595
595
  onChange();
596
596
  });
597
597
  return { sync: () => Promise.resolve(), close: () => watcher.close() };
@@ -599,8 +599,8 @@ const startConfigWatcher = async (configPath, onChange) => {
599
599
  const startInputWatcher = async (chokidar, source, initialInputs, restart) => {
600
600
  const watched = new Set([source, ...initialInputs]);
601
601
  const watcher = chokidar.watch([...watched], { ignoreInitial: true });
602
- await once(watcher, 'ready');
603
- watcher.on('all', () => {
602
+ await once(watcher, "ready");
603
+ watcher.on("all", () => {
604
604
  restart();
605
605
  });
606
606
  const sync = async () => {
@@ -627,16 +627,16 @@ const startDirectoryWatcher = async (chokidar, source, restart) => {
627
627
  const watchedDir = dirname(source);
628
628
  const isIgnored = (p) => {
629
629
  const segments = p.split(/[/\\]/);
630
- return (segments.includes('node_modules') ||
631
- segments.includes('.git') ||
632
- segments.includes('dist'));
630
+ return (segments.includes("node_modules") ||
631
+ segments.includes(".git") ||
632
+ segments.includes("dist"));
633
633
  };
634
634
  const watcher = chokidar.watch(watchedDir, {
635
635
  ignoreInitial: true,
636
636
  ignored: (path) => isIgnored(path),
637
637
  });
638
- await once(watcher, 'ready');
639
- watcher.on('all', () => {
638
+ await once(watcher, "ready");
639
+ watcher.on("all", () => {
640
640
  restart();
641
641
  });
642
642
  return { sync: () => Promise.resolve(), close: () => watcher.close() };
@@ -656,41 +656,41 @@ const killTree = (child) => {
656
656
  const timeout = setTimeout(() => {
657
657
  forceKill(child, pid);
658
658
  }, 2000);
659
- child.once('exit', () => {
659
+ child.once("exit", () => {
660
660
  clearTimeout(timeout);
661
661
  resolveKill();
662
662
  });
663
- if (pid !== undefined && process.platform !== 'win32') {
663
+ if (pid !== undefined && process.platform !== "win32") {
664
664
  try {
665
- process.kill(-pid, 'SIGTERM');
665
+ process.kill(-pid, "SIGTERM");
666
666
  return;
667
667
  }
668
668
  catch {
669
669
  // Fall through to a direct kill if the group is already gone.
670
670
  }
671
671
  }
672
- child.kill('SIGTERM');
672
+ child.kill("SIGTERM");
673
673
  });
674
674
  };
675
675
  const forceKill = (child, pid) => {
676
676
  if (pid === undefined) {
677
- child.kill('SIGKILL');
677
+ child.kill("SIGKILL");
678
678
  return;
679
679
  }
680
- if (process.platform === 'win32') {
681
- spawnSync('taskkill', ['/pid', String(pid), '/T', '/F']);
680
+ if (process.platform === "win32") {
681
+ spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"]);
682
682
  return;
683
683
  }
684
684
  try {
685
- process.kill(-pid, 'SIGKILL');
685
+ process.kill(-pid, "SIGKILL");
686
686
  }
687
687
  catch {
688
- child.kill('SIGKILL');
688
+ child.kill("SIGKILL");
689
689
  }
690
690
  };
691
691
  const resolveRuntimePath = () => {
692
692
  const here = dirname(fileURLToPath(import.meta.url));
693
- const candidate = join(here, '..', 'dev', 'runtime.js');
693
+ const candidate = join(here, "..", "dev", "runtime.js");
694
694
  if (!existsSync(candidate)) {
695
695
  throw new Error(`Could not locate the dev runtime at ${candidate}`);
696
696
  }