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.
- package/dist/commands/snapshots.js +38 -28
- package/dist/error_reporting.js +4043 -2
- package/dist/utils/formats.js +2 -1
- package/package.json +3 -3
|
@@ -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
|
|
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,
|
|
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
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
|
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,
|