neonctl 2.28.0 → 2.29.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 (135) hide show
  1. package/README.md +71 -71
  2. package/dist/analytics.js +35 -33
  3. package/dist/api.js +34 -34
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +2 -2
  6. package/dist/commands/auth.js +58 -52
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +154 -147
  9. package/dist/commands/bucket.js +124 -118
  10. package/dist/commands/checkout.js +49 -49
  11. package/dist/commands/config.js +212 -88
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +96 -96
  14. package/dist/commands/databases.js +23 -23
  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 +97 -98
  19. package/dist/commands/index.js +26 -26
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +223 -166
  23. package/dist/commands/neon_auth.js +381 -363
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +101 -99
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +21 -21
  29. package/dist/commands/schema_diff.js +23 -23
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +17 -17
  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 +23 -16
  37. package/dist/current_branch_fast_path.js +6 -6
  38. package/dist/dev/env.js +34 -34
  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 +19 -19
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +94 -92
  48. package/dist/log.js +2 -2
  49. package/dist/pkg.js +5 -5
  50. package/dist/psql/cli.js +4 -2
  51. package/dist/psql/command/cmd_cond.js +61 -61
  52. package/dist/psql/command/cmd_connect.js +159 -154
  53. package/dist/psql/command/cmd_copy.js +107 -97
  54. package/dist/psql/command/cmd_describe.js +368 -363
  55. package/dist/psql/command/cmd_format.js +276 -263
  56. package/dist/psql/command/cmd_io.js +269 -263
  57. package/dist/psql/command/cmd_lo.js +74 -66
  58. package/dist/psql/command/cmd_meta.js +148 -148
  59. package/dist/psql/command/cmd_misc.js +17 -17
  60. package/dist/psql/command/cmd_pipeline.js +142 -135
  61. package/dist/psql/command/cmd_restrict.js +25 -25
  62. package/dist/psql/command/cmd_show.js +183 -168
  63. package/dist/psql/command/dispatch.js +26 -26
  64. package/dist/psql/command/shared.js +14 -14
  65. package/dist/psql/complete/filenames.js +16 -16
  66. package/dist/psql/complete/index.js +4 -4
  67. package/dist/psql/complete/matcher.js +33 -32
  68. package/dist/psql/complete/psqlVars.js +173 -173
  69. package/dist/psql/complete/queries.js +5 -3
  70. package/dist/psql/complete/rules.js +900 -863
  71. package/dist/psql/core/common.js +136 -133
  72. package/dist/psql/core/help.js +343 -343
  73. package/dist/psql/core/mainloop.js +160 -153
  74. package/dist/psql/core/prompt.js +126 -123
  75. package/dist/psql/core/settings.js +111 -111
  76. package/dist/psql/core/sqlHelp.js +150 -150
  77. package/dist/psql/core/startup.js +211 -205
  78. package/dist/psql/core/syncVars.js +14 -14
  79. package/dist/psql/core/variables.js +24 -24
  80. package/dist/psql/describe/formatters.js +302 -289
  81. package/dist/psql/describe/processNamePattern.js +28 -28
  82. package/dist/psql/describe/queries.js +656 -651
  83. package/dist/psql/index.js +436 -411
  84. package/dist/psql/io/history.js +36 -36
  85. package/dist/psql/io/input.js +15 -15
  86. package/dist/psql/io/lineEditor/buffer.js +27 -25
  87. package/dist/psql/io/lineEditor/complete.js +15 -15
  88. package/dist/psql/io/lineEditor/filename.js +22 -22
  89. package/dist/psql/io/lineEditor/index.js +65 -62
  90. package/dist/psql/io/lineEditor/keymap.js +325 -318
  91. package/dist/psql/io/lineEditor/vt100.js +60 -60
  92. package/dist/psql/io/pgpass.js +18 -18
  93. package/dist/psql/io/pgservice.js +14 -14
  94. package/dist/psql/io/psqlrc.js +46 -46
  95. package/dist/psql/print/aligned.js +175 -166
  96. package/dist/psql/print/asciidoc.js +51 -51
  97. package/dist/psql/print/crosstab.js +34 -31
  98. package/dist/psql/print/csv.js +25 -22
  99. package/dist/psql/print/html.js +54 -54
  100. package/dist/psql/print/json.js +12 -12
  101. package/dist/psql/print/latex.js +118 -118
  102. package/dist/psql/print/pager.js +28 -26
  103. package/dist/psql/print/troff.js +48 -48
  104. package/dist/psql/print/unaligned.js +15 -14
  105. package/dist/psql/print/units.js +17 -17
  106. package/dist/psql/scanner/slash.js +48 -46
  107. package/dist/psql/scanner/sql.js +88 -84
  108. package/dist/psql/scanner/stringutils.js +21 -17
  109. package/dist/psql/types/index.js +7 -7
  110. package/dist/psql/types/scanner.js +8 -8
  111. package/dist/psql/wire/connection.js +341 -327
  112. package/dist/psql/wire/copy.js +7 -7
  113. package/dist/psql/wire/pipeline.js +26 -24
  114. package/dist/psql/wire/protocol.js +102 -102
  115. package/dist/psql/wire/sasl.js +62 -62
  116. package/dist/psql/wire/tls.js +79 -73
  117. package/dist/storage_api.js +15 -15
  118. package/dist/test_utils/fixtures.js +34 -31
  119. package/dist/test_utils/oauth_server.js +5 -5
  120. package/dist/utils/api_enums.js +13 -13
  121. package/dist/utils/branch_notice.js +5 -5
  122. package/dist/utils/branch_picker.js +26 -26
  123. package/dist/utils/compute_units.js +4 -4
  124. package/dist/utils/enrichers.js +20 -15
  125. package/dist/utils/esbuild.js +28 -28
  126. package/dist/utils/formats.js +1 -1
  127. package/dist/utils/middlewares.js +3 -3
  128. package/dist/utils/package_manager.js +68 -0
  129. package/dist/utils/point_in_time.js +12 -12
  130. package/dist/utils/psql.js +30 -30
  131. package/dist/utils/string.js +2 -2
  132. package/dist/utils/ui.js +9 -9
  133. package/dist/utils/zip.js +1 -1
  134. package/dist/writer.js +17 -17
  135. package/package.json +6 -7
@@ -1,11 +1,11 @@
1
- import { createPatch } from 'diff';
2
- import chalk from 'chalk';
3
- import { writer } from '../writer.js';
4
- import { branchIdFromProps } from '../utils/enrichers.js';
5
- import { parsePointInTime, } from '../utils/point_in_time.js';
6
- import { isNeonApiError, messageFromBody } from '../api.js';
7
- import { sendError } from '../analytics.js';
8
- import { log } from '../log.js';
1
+ import chalk from "chalk";
2
+ import { createPatch } from "diff";
3
+ import { sendError } from "../analytics.js";
4
+ import { isNeonApiError, messageFromBody } from "../api.js";
5
+ import { log } from "../log.js";
6
+ import { branchIdFromProps } from "../utils/enrichers.js";
7
+ import { parsePointInTime, } from "../utils/point_in_time.js";
8
+ import { writer } from "../writer.js";
9
9
  const COLORS = {
10
10
  added: chalk.green,
11
11
  removed: chalk.red,
@@ -22,10 +22,10 @@ export const schemaDiff = async (props) => {
22
22
  api: props.apiClient,
23
23
  });
24
24
  // Swap base and compare points if comparing with parent branch
25
- const comparingWithParent = props.compareSource.startsWith('^parent');
25
+ const comparingWithParent = props.compareSource.startsWith("^parent");
26
26
  let baseBranchPoint = {
27
27
  branchId: baseBranch,
28
- tag: 'head',
28
+ tag: "head",
29
29
  };
30
30
  [baseBranchPoint, pointInTime] = comparingWithParent
31
31
  ? [pointInTime, baseBranchPoint]
@@ -65,11 +65,11 @@ const fetchSchema = async (pointInTime, database, props) => {
65
65
  db_name: database.name,
66
66
  ...pointInTimeParams(pointInTime),
67
67
  });
68
- return response.data.sql ?? '';
68
+ return response.data.sql ?? "";
69
69
  }
70
70
  catch (error) {
71
71
  if (isNeonApiError(error)) {
72
- sendError(error, 'API_ERROR');
72
+ sendError(error, "API_ERROR");
73
73
  throw new Error(messageFromBody(error.data) ??
74
74
  `Error while fetching schema for branch ${pointInTime.branchId}`);
75
75
  }
@@ -78,10 +78,10 @@ const fetchSchema = async (pointInTime, database, props) => {
78
78
  };
79
79
  const colorize = (patch) => {
80
80
  return patch
81
- .replace(/^([^\n]+)\n([^\n]+)\n/m, '') // Remove first two lines
82
- .replace(/^-.*/gm, colorizer('removed'))
83
- .replace(/^\+.*/gm, colorizer('added'))
84
- .replace(/^@@.+@@.*/gm, colorizer('section'));
81
+ .replace(/^([^\n]+)\n([^\n]+)\n/m, "") // Remove first two lines
82
+ .replace(/^-.*/gm, colorizer("removed"))
83
+ .replace(/^\+.*/gm, colorizer("added"))
84
+ .replace(/^@@.+@@.*/gm, colorizer("section"));
85
85
  };
86
86
  const colorizer = (colorId) => {
87
87
  const color = COLORS[colorId];
@@ -89,11 +89,11 @@ const colorizer = (colorId) => {
89
89
  };
90
90
  const pointInTimeParams = (pointInTime) => {
91
91
  switch (pointInTime.tag) {
92
- case 'timestamp':
92
+ case "timestamp":
93
93
  return {
94
94
  timestamp: pointInTime.timestamp,
95
95
  };
96
- case 'lsn':
96
+ case "lsn":
97
97
  return {
98
98
  lsn: pointInTime.lsn ?? undefined,
99
99
  };
@@ -104,9 +104,9 @@ const pointInTimeParams = (pointInTime) => {
104
104
  const generateHeader = (pointInTime) => {
105
105
  const header = `(Branch: ${pointInTime.branchId}`;
106
106
  switch (pointInTime.tag) {
107
- case 'timestamp':
107
+ case "timestamp":
108
108
  return `${header} at ${pointInTime.timestamp})`;
109
- case 'lsn':
109
+ case "lsn":
110
110
  return `${header} at ${pointInTime.lsn})`;
111
111
  default:
112
112
  return `${header})`;
@@ -133,7 +133,7 @@ export const parseSchemaDiffParams = async (props) => {
133
133
  throw new Error(`No branch specified. Your context branch (${props.branch}) has no parent, so no comparison is possible.`);
134
134
  }
135
135
  log.info(`No branches specified. Comparing your context branch '${props.branch}' with its parent`);
136
- props.compareSource = '^parent';
136
+ props.compareSource = "^parent";
137
137
  }
138
138
  else {
139
139
  const { data } = await props.apiClient.listProjectBranches({
@@ -141,10 +141,10 @@ export const parseSchemaDiffParams = async (props) => {
141
141
  });
142
142
  const defaultBranch = data.branches.find((b) => b.default);
143
143
  if (defaultBranch?.parent_id == undefined) {
144
- throw new Error('No branch specified. Include a base branch or add a set-context branch to continue. Your default branch has no parent, so no comparison is possible.');
144
+ throw new Error("No branch specified. Include a base branch or add a set-context branch to continue. Your default branch has no parent, so no comparison is possible.");
145
145
  }
146
146
  log.info(`No branches specified. Comparing default branch with its parent`);
147
- props.compareSource = '^parent';
147
+ props.compareSource = "^parent";
148
148
  }
149
149
  }
150
150
  return props;
@@ -1,25 +1,25 @@
1
- import { applyContext } from '../context.js';
2
- import { log } from '../log.js';
3
- export const command = 'set-context';
4
- export const describe = 'Deprecated: use `neonctl link`. Set the .neon context (raw write).';
5
- export const builder = (argv) => argv.usage('$0 set-context [options]').options({
6
- 'project-id': {
7
- describe: 'Project ID',
8
- type: 'string',
1
+ import { applyContext } from "../context.js";
2
+ import { log } from "../log.js";
3
+ export const command = "set-context";
4
+ export const describe = "Deprecated: use `neonctl link`. Set the .neon context (raw write).";
5
+ export const builder = (argv) => argv.usage("$0 set-context [options]").options({
6
+ "project-id": {
7
+ describe: "Project ID",
8
+ type: "string",
9
9
  },
10
- 'org-id': {
11
- describe: 'Organization ID',
12
- type: 'string',
10
+ "org-id": {
11
+ describe: "Organization ID",
12
+ type: "string",
13
13
  },
14
- 'branch-id': {
15
- describe: 'Branch ID',
16
- type: 'string',
14
+ "branch-id": {
15
+ describe: "Branch ID",
16
+ type: "string",
17
17
  },
18
18
  });
19
19
  export const handler = (props) => {
20
- log.warning('`neonctl set-context` is deprecated and will be removed in a future release. ' +
21
- 'Use `neonctl link` instead — it verifies inputs and infers the org for you ' +
22
- '(or `neonctl link --no-checks` for the same write-without-checks behavior).');
20
+ log.warning("`neonctl set-context` is deprecated and will be removed in a future release. " +
21
+ "Use `neonctl link` instead — it verifies inputs and infers the org for you " +
22
+ "(or `neonctl link --no-checks` for the same write-without-checks behavior).");
23
23
  const context = {
24
24
  projectId: props.projectId,
25
25
  orgId: props.orgId,
@@ -1,5 +1,5 @@
1
- import { fillSingleProject } from '../utils/enrichers.js';
2
- import { status } from './config.js';
1
+ import { fillSingleProject } from "../utils/enrichers.js";
2
+ import { status } from "./config.js";
3
3
  /**
4
4
  * `neon status` is a top-level alias for `neon config status` — the most-reached-for
5
5
  * config subcommand. It mirrors that command's options (including `--current-branch`,
@@ -9,30 +9,30 @@ import { status } from './config.js';
9
9
  * `NO_SUBCOMMANDS_VERBS` (see index.ts) so the help-fallback middleware doesn't
10
10
  * intercept a bare `neon status`.
11
11
  */
12
- export const command = 'status';
12
+ export const command = "status";
13
13
  export const describe = "Show the branch's live Neon state (alias of `config status`)";
14
14
  export const builder = (argv) => argv
15
- .usage('$0 status [options]')
15
+ .usage("$0 status [options]")
16
16
  .options({
17
- 'project-id': {
18
- describe: 'Project ID',
19
- type: 'string',
17
+ "project-id": {
18
+ describe: "Project ID",
19
+ type: "string",
20
20
  },
21
21
  branch: {
22
- describe: 'Branch ID or name',
23
- type: 'string',
22
+ describe: "Branch ID or name",
23
+ type: "string",
24
24
  },
25
- 'config-json': {
25
+ "config-json": {
26
26
  describe: "Print only the branch's live config as neon.ts-shaped JSON " +
27
- '(services + branch tuning + preview), to stdout. Useful for ' +
28
- 'scripting or copying into a neon.ts.',
29
- type: 'boolean',
27
+ "(services + branch tuning + preview), to stdout. Useful for " +
28
+ "scripting or copying into a neon.ts.",
29
+ type: "boolean",
30
30
  default: false,
31
31
  },
32
- 'current-branch': {
33
- describe: 'Print only the linked branch name from the local .neon file ' +
34
- '(no network). Exits non-zero when no branch is pinned.',
35
- type: 'boolean',
32
+ "current-branch": {
33
+ describe: "Print only the linked branch name from the local .neon file " +
34
+ "(no network). Exits non-zero when no branch is pinned.",
35
+ type: "boolean",
36
36
  default: false,
37
37
  },
38
38
  })
@@ -1,7 +1,7 @@
1
- import { writer } from '../writer.js';
2
- export const command = 'me';
3
- export const describe = 'Show current user';
4
- export const builder = (yargs) => yargs.option('context-file', {
1
+ import { writer } from "../writer.js";
2
+ export const command = "me";
3
+ export const describe = "Show current user";
4
+ export const builder = (yargs) => yargs.option("context-file", {
5
5
  hidden: true,
6
6
  });
7
7
  export const handler = async (args) => {
@@ -10,6 +10,6 @@ export const handler = async (args) => {
10
10
  const me = async (props) => {
11
11
  const { data } = await props.apiClient.getCurrentUserInfo();
12
12
  writer(props).end(data, {
13
- fields: ['login', 'email', 'name', 'projects_limit'],
13
+ fields: ["login", "email", "name", "projects_limit"],
14
14
  });
15
15
  };
@@ -1,92 +1,92 @@
1
- import { writer } from '../writer.js';
2
- import { fillSingleProject, fillSingleOrg } from '../utils/enrichers.js';
3
- import { REGIONS } from './projects.js';
4
- import { log } from '../log.js';
5
- const VPC_ENDPOINT_FIELDS = ['vpc_endpoint_id', 'label'];
1
+ import { log } from "../log.js";
2
+ import { fillSingleOrg, fillSingleProject } from "../utils/enrichers.js";
3
+ import { writer } from "../writer.js";
4
+ import { REGIONS } from "./projects.js";
5
+ const VPC_ENDPOINT_FIELDS = ["vpc_endpoint_id", "label"];
6
6
  const VPC_ENDPOINT_DETAILS_FIELDS = [
7
- 'vpc_endpoint_id',
8
- 'label',
9
- 'state',
10
- 'num_restricted_projects',
11
- 'example_restricted_projects',
7
+ "vpc_endpoint_id",
8
+ "label",
9
+ "state",
10
+ "num_restricted_projects",
11
+ "example_restricted_projects",
12
12
  ];
13
- export const command = 'vpc';
14
- export const describe = 'Manage VPC endpoints and project VPC restrictions';
13
+ export const command = "vpc";
14
+ export const describe = "Manage VPC endpoints and project VPC restrictions";
15
15
  export const builder = (argv) => {
16
16
  return argv
17
- .usage('$0 vpc <sub-command> [options]')
18
- .command('endpoint', 'Manage VPC endpoints.\n' +
19
- 'See: https://neon.tech/docs/guides/neon-private-networking\n' +
20
- 'After adding an endpoint to an organization, client connections will be accepted\n' +
21
- 'from the corresponding VPC for all projects in the organization, unless overridden\n' +
22
- 'by a project-level VPC endpoint restriction.', (yargs) => {
17
+ .usage("$0 vpc <sub-command> [options]")
18
+ .command("endpoint", "Manage VPC endpoints.\n" +
19
+ "See: https://neon.tech/docs/guides/neon-private-networking\n" +
20
+ "After adding an endpoint to an organization, client connections will be accepted\n" +
21
+ "from the corresponding VPC for all projects in the organization, unless overridden\n" +
22
+ "by a project-level VPC endpoint restriction.", (yargs) => {
23
23
  return yargs
24
24
  .options({
25
- 'org-id': {
26
- describe: 'Organization ID',
27
- type: 'string',
25
+ "org-id": {
26
+ describe: "Organization ID",
27
+ type: "string",
28
28
  },
29
- 'region-id': {
30
- describe: `The region ID. Possible values: ${REGIONS.join(', ')}`,
31
- type: 'string',
29
+ "region-id": {
30
+ describe: `The region ID. Possible values: ${REGIONS.join(", ")}`,
31
+ type: "string",
32
32
  demandOption: true,
33
33
  },
34
34
  })
35
35
  .middleware(fillSingleOrg)
36
- .command('list', 'List configured VPC endpoints for this organization.', (yargs) => yargs, async (args) => {
36
+ .command("list", "List configured VPC endpoints for this organization.", (yargs) => yargs, async (args) => {
37
37
  await listOrg(args);
38
38
  })
39
39
  .command({
40
- command: 'assign <id>',
41
- aliases: ['update <id>', 'add <id>'],
42
- describe: 'Add or update a VPC endpoint for this organization.\n' +
43
- 'Note: Azure regions are not yet supported.',
40
+ command: "assign <id>",
41
+ aliases: ["update <id>", "add <id>"],
42
+ describe: "Add or update a VPC endpoint for this organization.\n" +
43
+ "Note: Azure regions are not yet supported.",
44
44
  builder: (yargs) => yargs.options({
45
45
  label: {
46
- describe: 'An optional descriptive label for the VPC endpoint',
47
- type: 'string',
46
+ describe: "An optional descriptive label for the VPC endpoint",
47
+ type: "string",
48
48
  },
49
49
  }),
50
50
  handler: async (args) => {
51
51
  await assignOrg(args);
52
52
  },
53
53
  })
54
- .command('remove <id>', 'Remove a VPC endpoint from this organization.', (yargs) => yargs, async (args) => {
54
+ .command("remove <id>", "Remove a VPC endpoint from this organization.", (yargs) => yargs, async (args) => {
55
55
  await removeOrg(args);
56
56
  })
57
- .command('status <id>', 'Get the status of a VPC endpoint for this organization.', (yargs) => yargs, async (args) => {
57
+ .command("status <id>", "Get the status of a VPC endpoint for this organization.", (yargs) => yargs, async (args) => {
58
58
  await statusOrg(args);
59
59
  });
60
60
  })
61
- .command('project', 'Manage project-level VPC endpoint restrictions.\n' +
62
- 'By default, connections are accepted from any VPC configured at the organization level.\n' +
63
- 'A project-level VPC endpoint restriction can be used to restrict connections to a specific VPC.', (yargs) => {
61
+ .command("project", "Manage project-level VPC endpoint restrictions.\n" +
62
+ "By default, connections are accepted from any VPC configured at the organization level.\n" +
63
+ "A project-level VPC endpoint restriction can be used to restrict connections to a specific VPC.", (yargs) => {
64
64
  return yargs
65
65
  .options({
66
- 'project-id': {
67
- describe: 'Project ID',
68
- type: 'string',
66
+ "project-id": {
67
+ describe: "Project ID",
68
+ type: "string",
69
69
  },
70
70
  })
71
71
  .middleware(fillSingleProject)
72
- .command('list', 'List VPC endpoint restrictions for this project.', (yargs) => yargs, async (args) => {
72
+ .command("list", "List VPC endpoint restrictions for this project.", (yargs) => yargs, async (args) => {
73
73
  await listProject(args);
74
74
  })
75
75
  .command({
76
- command: 'restrict <id>',
77
- aliases: ['update <id>'],
78
- describe: 'Configure or update a VPC endpoint restriction for this project.',
76
+ command: "restrict <id>",
77
+ aliases: ["update <id>"],
78
+ describe: "Configure or update a VPC endpoint restriction for this project.",
79
79
  builder: (yargs) => yargs.options({
80
80
  label: {
81
- describe: 'An optional descriptive label for the VPC endpoint restriction',
82
- type: 'string',
81
+ describe: "An optional descriptive label for the VPC endpoint restriction",
82
+ type: "string",
83
83
  },
84
84
  }),
85
85
  handler: async (args) => {
86
86
  await assignProject(args);
87
87
  },
88
88
  })
89
- .command('remove <id>', 'Remove a VPC endpoint restriction from this project.', (yargs) => yargs, async (args) => {
89
+ .command("remove <id>", "Remove a VPC endpoint restriction from this project.", (yargs) => yargs, async (args) => {
90
90
  await removeProject(args);
91
91
  });
92
92
  });
@@ -99,12 +99,12 @@ const listOrg = async (props) => {
99
99
  };
100
100
  const assignOrg = async (props) => {
101
101
  const vpcEndpointAssignment = {
102
- label: props.label || '',
102
+ label: props.label || "",
103
103
  };
104
104
  const { data } = await props.apiClient.assignOrganizationVpcEndpoint(props.orgId, props.regionId, props.id, vpcEndpointAssignment);
105
105
  writer(props).end(data, { fields: [] });
106
- if (props.regionId.startsWith('azure')) {
107
- log.info('VPC endpoint configuration is not supported for Azure regions');
106
+ if (props.regionId.startsWith("azure")) {
107
+ log.info("VPC endpoint configuration is not supported for Azure regions");
108
108
  }
109
109
  };
110
110
  const removeOrg = async (props) => {
@@ -123,7 +123,7 @@ const listProject = async (props) => {
123
123
  };
124
124
  const assignProject = async (props) => {
125
125
  const vpcEndpointAssignment = {
126
- label: props.label || '',
126
+ label: props.label || "",
127
127
  };
128
128
  const { data } = await props.apiClient.assignProjectVpcEndpoint(props.projectId, props.id, vpcEndpointAssignment);
129
129
  writer(props).end(data, { fields: [] });
package/dist/config.js CHANGED
@@ -1,10 +1,10 @@
1
- import { join } from 'node:path';
2
- import { homedir } from 'node:os';
3
- import { existsSync, mkdirSync } from 'node:fs';
4
- import { isCi } from './env.js';
5
- export const CREDENTIALS_FILE = 'credentials.json';
6
- export const defaultDir = join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'neonctl');
7
- export const ensureConfigDir = ({ 'config-dir': configDir, 'force-auth': forceAuth, }) => {
1
+ import { existsSync, mkdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { isCi } from "./env.js";
5
+ export const CREDENTIALS_FILE = "credentials.json";
6
+ export const defaultDir = join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "neonctl");
7
+ export const ensureConfigDir = ({ "config-dir": configDir, "force-auth": forceAuth, }) => {
8
8
  if (!existsSync(configDir) && (!isCi() || forceAuth)) {
9
9
  mkdirSync(configDir, { recursive: true });
10
10
  }
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Render a TTL in whole seconds back to the canonical `neon.ts` duration string (e.g.
3
3
  * `604800` -> `"7d"`), falling back to seconds when no clean unit boundary matches. Mirrors
4
- * the formatter `@neondatabase/config` uses when it emits a TTL, so `config status` shows
4
+ * the formatter `@neon/config` uses when it emits a TTL, so `config status` shows
5
5
  * the same value a user would write in `neon.ts`.
6
6
  */
7
7
  export const formatDurationSeconds = (totalSeconds) => {
8
8
  const units = [
9
- ['w', 7 * 24 * 60 * 60],
10
- ['d', 24 * 60 * 60],
11
- ['h', 60 * 60],
12
- ['m', 60],
9
+ ["w", 7 * 24 * 60 * 60],
10
+ ["d", 24 * 60 * 60],
11
+ ["h", 60 * 60],
12
+ ["m", 60],
13
13
  ];
14
14
  for (const [unit, perUnit] of units) {
15
15
  if (totalSeconds % perUnit === 0)
package/dist/context.js CHANGED
@@ -1,7 +1,7 @@
1
- import { accessSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { dirname, normalize, resolve } from 'node:path';
4
- import { log } from './log.js';
1
+ import { accessSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, normalize, resolve } from "node:path";
4
+ import { log } from "./log.js";
5
5
  /**
6
6
  * The branch pinned in a context, reading the current `branch` field and
7
7
  * falling back to the legacy `branchId` so pre-migration `.neon` files keep
@@ -22,10 +22,17 @@ export const contextBranch = (context) => context.branch ?? context.branchId;
22
22
  * `config status` (`_ = ['config', 'status']`).
23
23
  */
24
24
  export const isCurrentBranchProbe = (args) => args.currentBranch === true &&
25
- (args._[0] === 'status' ||
26
- (args._[0] === 'config' && args._[1] === 'status'));
27
- const CONTEXT_FILE = '.neon';
28
- const GITIGNORE_FILE = '.gitignore';
25
+ (args._[0] === "status" ||
26
+ (args._[0] === "config" && args._[1] === "status"));
27
+ /**
28
+ * `config init` only scaffolds a local `neon.ts` and installs npm packages — it
29
+ * never calls the Neon API. Gated on the exact command path so the global auth
30
+ * middleware and the single-project resolver can skip it (it runs with no API
31
+ * client), mirroring {@link isCurrentBranchProbe}.
32
+ */
33
+ export const isConfigInit = (args) => args._[0] === "config" && args._[1] === "init";
34
+ const CONTEXT_FILE = ".neon";
35
+ const GITIGNORE_FILE = ".gitignore";
29
36
  const wrapWithContextFile = (dir) => resolve(dir, CONTEXT_FILE);
30
37
  /**
31
38
  * Resolve the default `.neon` path for the current working directory.
@@ -47,7 +54,7 @@ const wrapWithContextFile = (dir) => resolve(dir, CONTEXT_FILE);
47
54
  */
48
55
  export const currentContextFile = (cwd = process.cwd()) => {
49
56
  let currentDir = cwd;
50
- const root = normalize('/');
57
+ const root = normalize("/");
51
58
  const home = homedir();
52
59
  while (currentDir !== root && currentDir !== home) {
53
60
  try {
@@ -57,13 +64,13 @@ export const currentContextFile = (cwd = process.cwd()) => {
57
64
  catch {
58
65
  // ignore
59
66
  }
60
- currentDir = resolve(currentDir, '..');
67
+ currentDir = resolve(currentDir, "..");
61
68
  }
62
69
  return wrapWithContextFile(cwd);
63
70
  };
64
71
  export const readContextFile = (file) => {
65
72
  try {
66
- return JSON.parse(readFileSync(file, 'utf-8'));
73
+ return JSON.parse(readFileSync(file, "utf-8"));
67
74
  }
68
75
  catch {
69
76
  return {};
@@ -73,7 +80,7 @@ export const enrichFromContext = (args) => {
73
80
  // `link` and the deprecated `set-context` manage the context file themselves
74
81
  // and must see the raw flags rather than values pre-filled from an existing
75
82
  // `.neon`, so skip enrichment for both.
76
- if (args._[0] === 'link' || args._[0] === 'set-context') {
83
+ if (args._[0] === "link" || args._[0] === "set-context") {
77
84
  return;
78
85
  }
79
86
  const context = readContextFile(args.contextFile);
@@ -148,17 +155,17 @@ export const ensureGitignored = (file) => {
148
155
  writeFileSync(gitignorePath, `${entry}\n`);
149
156
  return;
150
157
  }
151
- const current = readFileSync(gitignorePath, 'utf-8');
158
+ const current = readFileSync(gitignorePath, "utf-8");
152
159
  if (hasGitignoreEntry(current, entry)) {
153
160
  return;
154
161
  }
155
- const needsLeadingNewline = current.length > 0 && !current.endsWith('\n');
156
- const addition = `${needsLeadingNewline ? '\n' : ''}${entry}\n`;
162
+ const needsLeadingNewline = current.length > 0 && !current.endsWith("\n");
163
+ const addition = `${needsLeadingNewline ? "\n" : ""}${entry}\n`;
157
164
  writeFileSync(gitignorePath, current + addition);
158
165
  }
159
166
  catch (err) {
160
167
  const message = err instanceof Error ? err.message : String(err);
161
- log.debug('Failed to update .gitignore next to %s: %s', file, message);
168
+ log.debug("Failed to update .gitignore next to %s: %s", file, message);
162
169
  }
163
170
  };
164
171
  const basenameOf = (file) => {
@@ -1,5 +1,5 @@
1
- import { contextBranch, currentContextFile, readContextFile } from './context.js';
2
- import { log } from './log.js';
1
+ import { contextBranch, currentContextFile, readContextFile, } from "./context.js";
2
+ import { log } from "./log.js";
3
3
  /**
4
4
  * Offline fast path for `(config) status --current-branch` (used by shell prompts).
5
5
  *
@@ -35,7 +35,7 @@ cwd = process.cwd()) => {
35
35
  process.stdout.write(`${branch}\n`);
36
36
  }
37
37
  else {
38
- log.info('No branch pinned. Run `neonctl checkout <branch>` to pin a branch and pull its env vars.');
38
+ log.info("No branch pinned. Run `neonctl checkout <branch>` to pin a branch and pull its env vars.");
39
39
  process.exitCode = 1;
40
40
  }
41
41
  return true;
@@ -46,10 +46,10 @@ cwd = process.cwd()) => {
46
46
  * positional args) makes this false so the full CLI handles it.
47
47
  */
48
48
  const isExactCurrentBranchInvocation = (args) => {
49
- const rest = args[0] === 'status'
49
+ const rest = args[0] === "status"
50
50
  ? args.slice(1)
51
- : args[0] === 'config' && args[1] === 'status'
51
+ : args[0] === "config" && args[1] === "status"
52
52
  ? args.slice(2)
53
53
  : null;
54
- return rest !== null && rest.length === 1 && rest[0] === '--current-branch';
54
+ return rest !== null && rest.length === 1 && rest[0] === "--current-branch";
55
55
  };