neon 8.3.0 → 8.3.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.
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
2
2
  import { log } from "../log.js";
3
- import { retryOnLock } from "../api.js";
3
+ import { isNeonApiError, retryOnLock } from "../api.js";
4
4
  import { writer } from "../writer.js";
5
- import { looksLikeLSN, looksLikeTimestamp, toIso } from "../utils/formats.js";
5
+ import { looksLikeBranchId, looksLikeLSN, looksLikeSnapshotId, looksLikeTimestamp, toIso } from "../utils/formats.js";
6
6
  import { branchIdResolve, fillSingleProject, resolveBranchRef } from "../utils/enrichers.js";
7
7
  import { BRANCH_FIELDS } from "./branches.js";
8
8
  //#region src/commands/snapshots.ts
@@ -166,6 +166,25 @@ const resolveSnapshot = async (props) => {
166
166
  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")}`);
167
167
  throw new Error(`Snapshot "${props.id}" not found.\nAvailable snapshots: ${snapshots.map((s) => `${s.name} (${s.id})`).join(", ") || "none"}`);
168
168
  };
169
+ /**
170
+ * Runs `call` on the snapshot `props.id` names. An id goes straight to the API without the
171
+ * listing; a 404 sends it through {@link resolveSnapshot}, since a name can look like an id.
172
+ * When the listing has that id, the 404 was about something else (a target branch), so it stands.
173
+ */
174
+ const withSnapshotId = async (props, call) => {
175
+ let notFound;
176
+ if (looksLikeSnapshotId(props.id)) try {
177
+ return await call(props.id);
178
+ } catch (err) {
179
+ if (!(isNeonApiError(err) && err.status === 404)) throw err;
180
+ notFound = err;
181
+ }
182
+ const snapshot = await resolveSnapshot(props);
183
+ if (notFound && snapshot.id === props.id) throw notFound;
184
+ return call(snapshot.id);
185
+ };
186
+ /** A `br-…` id needs no branch listing; a name or the context/default branch does. */
187
+ const snapshotBranchId = async (props) => props.branch && looksLikeBranchId(props.branch) ? props.branch : (await resolveBranchRef(props)).branchId;
169
188
  const list = async (props) => {
170
189
  const { data: { snapshots } } = await props.apiClient.listSnapshots(props.projectId);
171
190
  writer(props).end(snapshots, {
@@ -185,10 +204,7 @@ const get = async (props) => {
185
204
  const create = async (props) => {
186
205
  if (props.lsn !== void 0 && !looksLikeLSN(props.lsn)) throw new Error(`Invalid --lsn value: "${props.lsn}". Expected an LSN like 0/1F3C8A0.`);
187
206
  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.`);
188
- const { branchId } = await resolveBranchRef({
189
- ...props,
190
- branch: props.branch
191
- });
207
+ const branchId = await snapshotBranchId(props);
192
208
  const { data } = await retryOnLock(() => props.apiClient.createSnapshot(props.projectId, branchId, {
193
209
  name: props.name,
194
210
  timestamp: props.timestamp,
@@ -203,12 +219,11 @@ const create = async (props) => {
203
219
  };
204
220
  const update = async (props) => {
205
221
  if (props.name === void 0 && props.expiresAt === void 0 && !props.clearExpiration) throw new Error("Nothing to update. Pass --name, --expires-at, or --clear-expiration.");
206
- const snapshot = await resolveSnapshot(props);
207
222
  const expiresAt = props.clearExpiration ? null : props.expiresAt !== void 0 ? toIso(props.expiresAt, "--expires-at") : void 0;
208
- const { data } = await retryOnLock(() => props.apiClient.updateSnapshot(props.projectId, snapshot.id, { snapshot: {
223
+ const { data } = await withSnapshotId(props, (snapshotId) => retryOnLock(() => props.apiClient.updateSnapshot(props.projectId, snapshotId, { snapshot: {
209
224
  name: props.name,
210
225
  expires_at: expiresAt
211
- } }));
226
+ } })));
212
227
  writer(props).end(data.snapshot, {
213
228
  fields: SNAPSHOT_FIELDS,
214
229
  renderColumns: { expires_at: (s) => s.expires_at || "never" }
@@ -223,17 +238,18 @@ const deleteSnapshot = async (props) => {
223
238
  });
224
239
  };
225
240
  const restore = async (props) => {
226
- const snapshot = await resolveSnapshot(props);
227
- const targetBranchId = props.targetBranch ? await branchIdResolve({
228
- branch: props.targetBranch,
229
- projectId: props.projectId,
230
- apiClient: props.apiClient
231
- }) : void 0;
232
- const { data } = await retryOnLock(() => props.apiClient.restoreSnapshot(props.projectId, snapshot.id, {
233
- name: props.name,
234
- target_branch_id: targetBranchId,
235
- finalize_restore: props.finalize
236
- }));
241
+ const { data } = await withSnapshotId(props, async (snapshotId) => {
242
+ const targetBranchId = props.targetBranch ? await branchIdResolve({
243
+ branch: props.targetBranch,
244
+ projectId: props.projectId,
245
+ apiClient: props.apiClient
246
+ }) : void 0;
247
+ return retryOnLock(() => props.apiClient.restoreSnapshot(props.projectId, snapshotId, {
248
+ name: props.name,
249
+ target_branch_id: targetBranchId,
250
+ finalize_restore: props.finalize
251
+ }));
252
+ });
237
253
  const out = writer(props).write(data.branch, {
238
254
  fields: BRANCH_FIELDS,
239
255
  title: "restored branch"
@@ -259,10 +275,7 @@ const finalize = async (props) => {
259
275
  });
260
276
  };
261
277
  const scheduleGet = async (props) => {
262
- const { branchId } = await resolveBranchRef({
263
- ...props,
264
- branch: props.branch
265
- });
278
+ const branchId = await snapshotBranchId(props);
266
279
  const { data } = await props.apiClient.getSnapshotSchedule(props.projectId, branchId);
267
280
  writer(props).end(data.schedule, {
268
281
  fields: SCHEDULE_FIELDS,
@@ -304,10 +317,6 @@ const parseScheduleJson = (raw) => {
304
317
  });
305
318
  };
306
319
  const scheduleSet = async (props) => {
307
- const { branchId } = await resolveBranchRef({
308
- ...props,
309
- branch: props.branch
310
- });
311
320
  let schedule;
312
321
  if (props.schedule) schedule = parseScheduleJson(props.schedule);
313
322
  else if (props.frequency) {
@@ -318,6 +327,7 @@ const scheduleSet = async (props) => {
318
327
  if (props.retention !== void 0) item.retention_seconds = props.retention;
319
328
  schedule = [item];
320
329
  } else throw new Error("Provide --frequency (optionally with --hour/--day/--month/--retention) or --schedule <json>.");
330
+ const branchId = await snapshotBranchId(props);
321
331
  await retryOnLock(() => props.apiClient.setSnapshotSchedule(props.projectId, branchId, { schedule }));
322
332
  writer(props).end(schedule, {
323
333
  fields: SCHEDULE_FIELDS,