neon 6.4.0 → 7.0.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.
package/README.md CHANGED
@@ -966,15 +966,12 @@ The plugins CLI installs every plugin it finds in the Neon plugin package. Today
966
966
 
967
967
  `neon snapshots` (alias `neon snapshot`) manages **snapshots** — point-in-time backups of a branch that you can list, rename, expire, restore into a branch, or schedule automatically. Snapshots are a Beta Neon feature and were previously only available in the Console and REST API; this command group brings them to the CLI.
968
968
 
969
- Every sub-command resolves the project through the standard chain (`--project-id`, then the `.neon` context file, then a single-project auto-detect). Branch-scoped sub-commands (`create`, `schedule`) default to the branch pinned in `.neon`, falling back to the project's default branch, and accept `--branch <id|name>`. The `get`, `update`, `delete`, and `restore` sub-commands take a snapshot **id, unique name, or slug** as their positional argument. An id wins. A unique name still wins over another snapshot's matching slug, so a name you already use keeps targeting that snapshot. Slug is used when no name matches. An ambiguous name errors and asks you to use the id.
969
+ Every sub-command resolves the project through the standard chain (`--project-id`, then the `.neon` context file, then a single-project auto-detect). Branch-scoped sub-commands (`create`, `schedule`) default to the branch pinned in `.neon`, falling back to the project's default branch, and accept `--branch <id|name>`. The `get`, `update`, `delete`, and `restore` sub-commands take a snapshot **id or name** as their positional argument (an id wins; an ambiguous name errors and asks you to use the id).
970
970
 
971
971
  ```bash
972
972
  # Snapshot the head of the current/default branch
973
973
  neon snapshots create --name pre-migration
974
974
 
975
- # Give the snapshot a slug (unique in the project; omit to let the API generate one)
976
- neon snapshots create --branch main --name "Before migration" --slug before-migration
977
-
978
975
  # Snapshot a specific branch at a point in time (RFC 3339 timestamp OR LSN — mutually exclusive)
979
976
  neon snapshots create --branch main --timestamp 2025-01-01T00:00:00Z
980
977
  neon snapshots create --branch main --lsn 0/1F3C8A0 --expires-at 2025-12-31T23:59:59Z
@@ -982,7 +979,6 @@ neon snapshots create --branch main --lsn 0/1F3C8A0 --expires-at 2025-12-31T23:5
982
979
  # List / inspect
983
980
  neon snapshots list
984
981
  neon snapshots get pre-migration
985
- neon snapshots get before-migration
986
982
 
987
983
  # Rename or change expiration (omit both to error; --expires-at and --clear-expiration conflict)
988
984
  neon snapshots update snap-1234 --name nightly
@@ -17,7 +17,6 @@ var snapshots_exports = /* @__PURE__ */ __exportAll({
17
17
  const SNAPSHOT_FIELDS = [
18
18
  "id",
19
19
  "name",
20
- "slug",
21
20
  "source_branch_id",
22
21
  "expires_at",
23
22
  "created_at"
@@ -39,10 +38,8 @@ const SNAPSHOT_FREQUENCIES = [
39
38
  "weekly",
40
39
  "monthly"
41
40
  ];
42
- /** Matches createSnapshot.query.slug in the Management API spec. */
43
- const SNAPSHOT_SLUG = /^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
44
41
  const SNAPSHOT_REF = {
45
- describe: "Snapshot id, unique name, or slug. Lookup order: id, unique name, slug.",
42
+ describe: "Snapshot id or name. An id match wins over a name.",
46
43
  type: "string"
47
44
  };
48
45
  /** Narrow an arbitrary string to a supported {@link SnapshotFrequency}. */
@@ -53,7 +50,7 @@ const aliases = ["snapshot"];
53
50
  const builder = (argv) => argv.usage("$0 snapshots <sub-command> [options]").options({ "project-id": {
54
51
  describe: "Project ID",
55
52
  type: "string"
56
- } }).middleware(fillSingleProject).command("list", "List snapshots in the project", (yargs) => yargs, (args) => list(args)).command("get <id>", "Get a snapshot by id, unique name, or slug", (yargs) => yargs.positional("id", SNAPSHOT_REF), (args) => get(args)).command("create", "Create a snapshot from a branch", (yargs) => yargs.options({
53
+ } }).middleware(fillSingleProject).command("list", "List snapshots in the project", (yargs) => yargs, (args) => list(args)).command("get <id>", "Get a snapshot by id or name", (yargs) => yargs.positional("id", SNAPSHOT_REF), (args) => get(args)).command("create", "Create a snapshot from a branch", (yargs) => yargs.strict().options({
57
54
  branch: {
58
55
  alias: "b",
59
56
  describe: "Branch id or name to snapshot. Defaults to the branch in your context, or the project's default branch.",
@@ -63,10 +60,6 @@ const builder = (argv) => argv.usage("$0 snapshots <sub-command> [options]").opt
63
60
  describe: "A name for the snapshot",
64
61
  type: "string"
65
62
  },
66
- slug: {
67
- describe: "User-defined resource ID, unique in the project (1-63 characters: start with a lowercase letter, then lowercase letters, digits, or hyphens, ending with a letter or digit). Omit to let the API generate one. It cannot be changed later.",
68
- type: "string"
69
- },
70
63
  timestamp: {
71
64
  describe: "Take the snapshot at this point in time (RFC 3339, e.g. 2025-01-01T00:00:00Z). Must fall within the branch's restore window. Mutually exclusive with --lsn.",
72
65
  type: "string"
@@ -82,10 +75,9 @@ const builder = (argv) => argv.usage("$0 snapshots <sub-command> [options]").opt
82
75
  }).conflicts("timestamp", "lsn").example([
83
76
  ["$0 snapshots create", "Snapshot the head of the context/default branch"],
84
77
  ["$0 snapshots create --branch main --name pre-migration", "Snapshot the head of main with a name"],
85
- ["$0 snapshots create --branch main --name \"Before migration\" --slug before-migration", "Snapshot main with a display name and a slug"],
86
78
  ["$0 snapshots create --branch main --timestamp 2025-01-01T00:00:00Z", "Snapshot main at a point in time"],
87
79
  ["$0 snapshots create --branch main --lsn 0/1F3C8A0 --expires-at 2025-12-31T23:59:59Z", "Snapshot main at an LSN, auto-deleting at the given time"]
88
- ]), (args) => create(args)).command("update <id>", "Update a snapshot's name or expiration by id, unique name, or slug", (yargs) => yargs.positional("id", SNAPSHOT_REF).options({
80
+ ]), (args) => create(args)).command("update <id>", "Update a snapshot's name or expiration", (yargs) => yargs.positional("id", SNAPSHOT_REF).options({
89
81
  name: {
90
82
  describe: "Rename the snapshot",
91
83
  type: "string"
@@ -98,7 +90,7 @@ const builder = (argv) => argv.usage("$0 snapshots <sub-command> [options]").opt
98
90
  describe: "Clear the expiration so the snapshot is kept indefinitely.",
99
91
  type: "boolean"
100
92
  }
101
- }).conflicts("expires-at", "clear-expiration"), (args) => update(args)).command("delete <id>", "Delete a snapshot by id, unique name, or slug", (yargs) => yargs.positional("id", SNAPSHOT_REF), (args) => deleteSnapshot(args)).command("restore <id>", "Restore a snapshot (id, unique name, or slug) into a branch", (yargs) => yargs.positional("id", SNAPSHOT_REF).options({
93
+ }).conflicts("expires-at", "clear-expiration"), (args) => update(args)).command("delete <id>", "Delete a snapshot by id or name", (yargs) => yargs.positional("id", SNAPSHOT_REF), (args) => deleteSnapshot(args)).command("restore <id>", "Restore a snapshot into a branch", (yargs) => yargs.positional("id", SNAPSHOT_REF).options({
102
94
  name: {
103
95
  describe: "Name for the newly restored branch. Auto-generated when omitted.",
104
96
  type: "string"
@@ -167,8 +159,9 @@ const toIso = (value, flag) => {
167
159
  return new Date(ms).toISOString();
168
160
  };
169
161
  /**
170
- * Unique names precede slugs so existing name-based commands keep targeting
171
- * the named snapshot when another snapshot's slug matches that name.
162
+ * Resolve a snapshot from an id **or** a name. Snapshot names are not guaranteed
163
+ * unique, so an id match wins; a name that resolves to more than one snapshot is a
164
+ * hard error asking the user to disambiguate by id.
172
165
  */
173
166
  const resolveSnapshot = async (props) => {
174
167
  const { data: { snapshots } } = await props.apiClient.listSnapshots(props.projectId);
@@ -177,11 +170,8 @@ const resolveSnapshot = async (props) => {
177
170
  const byName = snapshots.filter((s) => s.name === props.id);
178
171
  if (byName.length === 1) return byName[0];
179
172
  if (byName.length > 1) throw new Error(`Multiple snapshots are named "${props.id}". Re-run with the snapshot id:\n${byName.map((s) => ` ${s.id}`).join("\n")}`);
180
- const bySlug = snapshots.find((s) => s.slug === props.id);
181
- if (bySlug) return bySlug;
182
- throw new Error(`Snapshot "${props.id}" not found.\nAvailable snapshots: ${snapshots.map((s) => formatSnapshotRef(s)).join(", ") || "none"}`);
173
+ throw new Error(`Snapshot "${props.id}" not found.\nAvailable snapshots: ${snapshots.map((s) => `${s.name} (${s.id})`).join(", ") || "none"}`);
183
174
  };
184
- const formatSnapshotRef = (snapshot) => snapshot.slug ? `${snapshot.name} (${snapshot.id}, slug: ${snapshot.slug})` : `${snapshot.name} (${snapshot.id})`;
185
175
  const list = async (props) => {
186
176
  const { data: { snapshots } } = await props.apiClient.listSnapshots(props.projectId);
187
177
  writer(props).end(snapshots, {
@@ -201,14 +191,12 @@ const get = async (props) => {
201
191
  const create = async (props) => {
202
192
  if (props.lsn !== void 0 && !looksLikeLSN(props.lsn)) throw new Error(`Invalid --lsn value: "${props.lsn}". Expected an LSN like 0/1F3C8A0.`);
203
193
  if (props.timestamp !== void 0 && !looksLikeTimestamp(props.timestamp)) throw new Error(`Invalid --timestamp value: "${props.timestamp}". Use an RFC 3339 timestamp, e.g. 2025-01-01T00:00:00Z.`);
204
- if (props.slug !== void 0 && !SNAPSHOT_SLUG.test(props.slug)) throw new Error(`Invalid --slug value: "${props.slug}". Use 1-63 characters: start with a lowercase letter, then lowercase letters, digits, or hyphens, and end with a letter or digit.`);
205
194
  const { branchId } = await resolveBranchRef({
206
195
  ...props,
207
196
  branch: props.branch
208
197
  });
209
198
  const { data } = await retryOnLock(() => props.apiClient.createSnapshot(props.projectId, branchId, {
210
199
  name: props.name,
211
- slug: props.slug,
212
200
  timestamp: props.timestamp,
213
201
  lsn: props.lsn,
214
202
  expires_at: props.expiresAt ? toIso(props.expiresAt, "--expires-at") : void 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neon",
3
- "version": "6.4.0",
3
+ "version": "7.0.0",
4
4
  "description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
5
5
  "keywords": [
6
6
  "neon",
@@ -64,9 +64,9 @@
64
64
  "yaml": "^2.9.0",
65
65
  "yargs": "17.7.2",
66
66
  "yoctocolors": "^2.1.2",
67
- "@neon/config-runtime": "1.7.2",
68
- "@neon/sdk": "6.1.2",
69
- "@neon/config": "1.8.2"
67
+ "@neon/config": "1.8.3",
68
+ "@neon/config-runtime": "1.7.3",
69
+ "@neon/sdk": "7.0.0"
70
70
  },
71
71
  "optionalDependencies": {
72
72
  "@napi-rs/keyring": "1.3.0",
@@ -100,7 +100,7 @@
100
100
  "typescript": "^5.9.0",
101
101
  "vitest": "^3.0.9",
102
102
  "@neon-internals/cli-core": "0.0.0",
103
- "@neon-internals/env-core": "0.0.25",
103
+ "@neon-internals/env-core": "0.0.26",
104
104
  "@neon/e2e-harness": "0.0.0",
105
105
  "@neon/functions": "0.11.0"
106
106
  },