neon 8.11.1 → 8.11.2
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 +1 -1
- package/dist/_chunks/api-GbEaBZJ5.js +388 -0
- package/dist/_chunks/api_keys-CNnnugbQ.js +281 -0
- package/dist/_chunks/ask-DVwy0eUL.js +155 -0
- package/dist/_chunks/auth-CIUtXByB.js +495 -0
- package/dist/_chunks/bootstrap-wPZWa1sT.js +499 -0
- package/dist/_chunks/branches-BNa1xX1L.js +460 -0
- package/dist/_chunks/bucket-BCdryTkD.js +409 -0
- package/dist/_chunks/checkout-CXIOydqZ.js +348 -0
- package/dist/_chunks/claim-DqAvAvDm.js +473 -0
- package/dist/_chunks/config-BH_qRHiG.js +1113 -0
- package/dist/_chunks/connection_string-DB4awPzZ.js +154 -0
- package/dist/_chunks/credentials-BSjE9fRR.js +146 -0
- package/dist/_chunks/data_api-Djxj5ZQD.js +263 -0
- package/dist/_chunks/databases-Dok4wru7.js +84 -0
- package/dist/_chunks/deploy-D7B0Xfjg.js +33 -0
- package/dist/_chunks/dev-CSvxAecE.js +945 -0
- package/dist/_chunks/diff-DhxxbdQE.js +178 -0
- package/dist/_chunks/docs-CrVybkTP.js +197 -0
- package/dist/_chunks/env-5HS5qQGd.js +284 -0
- package/dist/_chunks/feedback-CMayyTa8.js +88 -0
- package/dist/_chunks/functions-Q0zuvtnk.js +464 -0
- package/dist/_chunks/git-H32TNt6M.js +356 -0
- package/dist/_chunks/init-BkA6RilG.js +111 -0
- package/dist/_chunks/inspect-g0wekylj.js +90 -0
- package/dist/_chunks/ip_allow-5lLFvIuE.js +106 -0
- package/dist/_chunks/link-BgtkOBws.js +936 -0
- package/dist/_chunks/logs-DWkpjzIH.js +291 -0
- package/dist/_chunks/mcp-Bo-7TKc7.js +253 -0
- package/dist/_chunks/neon_auth-CBs1_3qu.js +822 -0
- package/dist/_chunks/open-CX3BT3Tp.js +33 -0
- package/dist/_chunks/operations-D4I-AxVs.js +37 -0
- package/dist/_chunks/orgs-xGfANwHQ.js +52 -0
- package/dist/_chunks/plugins-DqD7BDO1.js +169 -0
- package/dist/_chunks/profile-yXOiKk9R.js +672 -0
- package/dist/_chunks/projects-BwI2Uo0z.js +439 -0
- package/dist/_chunks/psql-BM-doe8e.js +64 -0
- package/dist/_chunks/realtime-BRqIyGR-.js +79 -0
- package/dist/_chunks/roles-B4w3YT_7.js +79 -0
- package/dist/_chunks/set_context-DbrwoImy.js +38 -0
- package/dist/_chunks/skills-DyiBXKS3.js +255 -0
- package/dist/_chunks/snapshots-RJBzW8GM.js +338 -0
- package/dist/_chunks/status-DV8Z2kw3.js +44 -0
- package/dist/_chunks/triggers-BrRo1z4b.js +302 -0
- package/dist/_chunks/user-dlOGXbX9.js +60 -0
- package/dist/_chunks/vpc_endpoints-CNb0YfMo.js +105 -0
- package/dist/auth_recovery.js +1 -1
- package/dist/commands/api.js +1 -388
- package/dist/commands/api_keys.js +1 -281
- package/dist/commands/ask.js +1 -155
- package/dist/commands/auth.js +1 -495
- package/dist/commands/bootstrap.js +1 -499
- package/dist/commands/branches.js +1 -460
- package/dist/commands/bucket.js +1 -409
- package/dist/commands/checkout.js +1 -348
- package/dist/commands/claim.js +1 -473
- package/dist/commands/config.js +1 -1113
- package/dist/commands/connection_string.js +1 -154
- package/dist/commands/credentials.js +1 -146
- package/dist/commands/data_api.js +1 -263
- package/dist/commands/databases.js +1 -84
- package/dist/commands/deploy.js +1 -33
- package/dist/commands/dev.js +1 -945
- package/dist/commands/diff.js +1 -178
- package/dist/commands/docs.js +1 -197
- package/dist/commands/env.js +1 -284
- package/dist/commands/feedback.js +1 -88
- package/dist/commands/functions.js +1 -464
- package/dist/commands/functions_new.js +1 -1
- package/dist/commands/git.js +1 -356
- package/dist/commands/index.js +45 -45
- package/dist/commands/init.js +1 -111
- package/dist/commands/inspect.js +1 -90
- package/dist/commands/ip_allow.js +1 -106
- package/dist/commands/link.js +1 -936
- package/dist/commands/logs.js +1 -291
- package/dist/commands/mcp.js +1 -253
- package/dist/commands/neon_auth.js +1 -822
- package/dist/commands/open.js +1 -33
- package/dist/commands/operations.js +1 -37
- package/dist/commands/orgs.js +1 -52
- package/dist/commands/plugins.js +1 -169
- package/dist/commands/profile.js +1 -672
- package/dist/commands/projects.js +1 -439
- package/dist/commands/psql.js +1 -64
- package/dist/commands/realtime.js +1 -79
- package/dist/commands/roles.js +1 -79
- package/dist/commands/set_context.js +1 -38
- package/dist/commands/skills.js +1 -255
- package/dist/commands/snapshots.js +1 -338
- package/dist/commands/status.js +1 -44
- package/dist/commands/subscribe.js +1 -1
- package/dist/commands/triggers.js +1 -302
- package/dist/commands/user.js +1 -60
- package/dist/commands/vpc_endpoints.js +1 -105
- package/dist/functions/registry.js +29 -151
- package/dist/functions/source.js +42 -2
- package/dist/index.js +1 -1
- package/dist/init/auth.js +3 -3
- package/dist/init/link.js +2 -2
- package/dist/init/run.js +3 -3
- package/dist/init/tooling.js +3 -3
- package/dist/mcp/mint.js +1 -1
- package/dist/test_utils/registry.js +1 -2
- package/package.json +8 -6
package/dist/commands/bucket.js
CHANGED
|
@@ -1,409 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { log } from "../log.js";
|
|
3
|
-
import { isNeonApiError, retryOnLock } from "../api.js";
|
|
4
|
-
import { createProjectBranchBucket, deleteProjectBranchBucket, deleteProjectBranchBucketObject, deleteProjectBranchBucketObjectsByPrefix, getProjectBranchBucketObject, listProjectBranchBucketObjects, listProjectBranchBuckets, presignUpload } from "../storage_api.js";
|
|
5
|
-
import { writer } from "../writer.js";
|
|
6
|
-
import { branchIdFromProps, fillSingleProject } from "../utils/enrichers.js";
|
|
7
|
-
import { createReadStream, createWriteStream } from "node:fs";
|
|
8
|
-
import { basename } from "node:path";
|
|
9
|
-
import { stat, unlink } from "node:fs/promises";
|
|
10
|
-
import { pipeline } from "node:stream/promises";
|
|
11
|
-
//#region src/commands/bucket.ts
|
|
12
|
-
var bucket_exports = /* @__PURE__ */ __exportAll({
|
|
13
|
-
aliases: () => aliases,
|
|
14
|
-
builder: () => builder,
|
|
15
|
-
command: () => command,
|
|
16
|
-
describe: () => describe,
|
|
17
|
-
handler: () => handler,
|
|
18
|
-
resolveListDelimiter: () => resolveListDelimiter,
|
|
19
|
-
splitBucketTarget: () => splitBucketTarget
|
|
20
|
-
});
|
|
21
|
-
const OBJECT_FIELDS = [
|
|
22
|
-
"key",
|
|
23
|
-
"size",
|
|
24
|
-
"last_modified",
|
|
25
|
-
"etag"
|
|
26
|
-
];
|
|
27
|
-
const BUCKET_FIELDS = ["name", "access_level"];
|
|
28
|
-
const ACCESS_LEVELS = ["private", "public_read"];
|
|
29
|
-
const MAX_OBJECT_BYTES = 104857600;
|
|
30
|
-
const scopeOptions = {
|
|
31
|
-
"project-id": {
|
|
32
|
-
describe: "Project ID",
|
|
33
|
-
type: "string"
|
|
34
|
-
},
|
|
35
|
-
branch: {
|
|
36
|
-
describe: "Branch ID or name",
|
|
37
|
-
type: "string"
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
const splitBucketTarget = (target) => {
|
|
41
|
-
const slash = target.indexOf("/");
|
|
42
|
-
if (slash === -1) return {
|
|
43
|
-
bucket: target,
|
|
44
|
-
rest: ""
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
bucket: target.slice(0, slash),
|
|
48
|
-
rest: target.slice(slash + 1)
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
const command = "buckets";
|
|
52
|
-
const describe = "Manage branch object-storage buckets and their objects";
|
|
53
|
-
const aliases = ["bucket"];
|
|
54
|
-
const builder = (argv) => argv.usage("$0 bucket <sub-command> [options]").options({ "project-id": {
|
|
55
|
-
describe: "Project ID",
|
|
56
|
-
type: "string"
|
|
57
|
-
} }).middleware(fillSingleProject).command("create <name>", "Create a bucket on a branch", (yargs) => yargs.usage("$0 bucket create <name> [options]").positional("name", {
|
|
58
|
-
describe: "The bucket name to create",
|
|
59
|
-
type: "string",
|
|
60
|
-
demandOption: true
|
|
61
|
-
}).options({
|
|
62
|
-
...scopeOptions,
|
|
63
|
-
"access-level": {
|
|
64
|
-
describe: "The visibility of the bucket",
|
|
65
|
-
type: "string",
|
|
66
|
-
choices: ACCESS_LEVELS,
|
|
67
|
-
default: "private"
|
|
68
|
-
}
|
|
69
|
-
}), (args) => createBucket(args)).command({
|
|
70
|
-
command: "list",
|
|
71
|
-
aliases: ["ls"],
|
|
72
|
-
describe: "List the buckets on a branch",
|
|
73
|
-
builder: (yargs) => yargs.usage("$0 bucket list [options]").options(scopeOptions),
|
|
74
|
-
handler: (args) => listBuckets(args)
|
|
75
|
-
}).command({
|
|
76
|
-
command: "delete <name>",
|
|
77
|
-
aliases: ["rm"],
|
|
78
|
-
describe: "Delete a bucket from a branch",
|
|
79
|
-
builder: (yargs) => yargs.usage("$0 bucket delete <name> [options]").positional("name", {
|
|
80
|
-
describe: "The bucket name to delete",
|
|
81
|
-
type: "string",
|
|
82
|
-
demandOption: true
|
|
83
|
-
}).options(scopeOptions),
|
|
84
|
-
handler: (args) => deleteBucket(args)
|
|
85
|
-
}).command("object", "List, download, upload or delete objects in a bucket", (yargs) => yargs.usage("$0 bucket object <sub-command> [options]").command({
|
|
86
|
-
command: "list <target>",
|
|
87
|
-
aliases: ["ls"],
|
|
88
|
-
describe: "List objects in a bucket. By default folders are collapsed (like \"aws s3 ls\"); pass --recursive for a flat listing of every key",
|
|
89
|
-
builder: (yargs) => yargs.usage("$0 bucket object list <bucket>[/<prefix>] [options]").positional("target", {
|
|
90
|
-
describe: "The bucket to list, optionally with a key prefix: <bucket>[/<prefix>]",
|
|
91
|
-
type: "string",
|
|
92
|
-
demandOption: true
|
|
93
|
-
}).options({
|
|
94
|
-
...scopeOptions,
|
|
95
|
-
recursive: {
|
|
96
|
-
describe: "List every key flat, descending into nested folders (no delimiter). Mutually exclusive with --delimiter. Mirrors \"aws s3 ls --recursive\"",
|
|
97
|
-
type: "boolean",
|
|
98
|
-
default: false
|
|
99
|
-
},
|
|
100
|
-
delimiter: {
|
|
101
|
-
describe: "Collapse keys sharing this prefix separator into folders. Defaults to \"/\" (folder view); ignored when --recursive is set",
|
|
102
|
-
type: "string"
|
|
103
|
-
},
|
|
104
|
-
cursor: {
|
|
105
|
-
describe: "Pagination cursor returned as next_cursor by a previous call",
|
|
106
|
-
type: "string"
|
|
107
|
-
},
|
|
108
|
-
limit: {
|
|
109
|
-
describe: "Maximum number of items (objects + folders) to return",
|
|
110
|
-
type: "number"
|
|
111
|
-
}
|
|
112
|
-
}),
|
|
113
|
-
handler: (args) => listObjects(args)
|
|
114
|
-
}).command("get <target>", "Download an object from a bucket to a local file", (yargs) => yargs.usage("$0 bucket object get <bucket>/<key> [options]").positional("target", {
|
|
115
|
-
describe: "The object to download: <bucket>/<key>",
|
|
116
|
-
type: "string",
|
|
117
|
-
demandOption: true
|
|
118
|
-
}).options({
|
|
119
|
-
...scopeOptions,
|
|
120
|
-
file: {
|
|
121
|
-
describe: "Path to write the downloaded object to (defaults to the object filename in the current directory)",
|
|
122
|
-
type: "string"
|
|
123
|
-
}
|
|
124
|
-
}), (args) => getObject(args)).command("put <target>", "Upload a local file to a bucket as an object", (yargs) => yargs.usage("$0 bucket object put <bucket>/<key> [options]").positional("target", {
|
|
125
|
-
describe: "The object to upload to: <bucket>/<key>",
|
|
126
|
-
type: "string",
|
|
127
|
-
demandOption: true
|
|
128
|
-
}).options({
|
|
129
|
-
...scopeOptions,
|
|
130
|
-
file: {
|
|
131
|
-
describe: "Path to the local file to upload",
|
|
132
|
-
type: "string",
|
|
133
|
-
demandOption: true
|
|
134
|
-
},
|
|
135
|
-
"content-type": {
|
|
136
|
-
describe: "Content-Type to store the object with (e.g. text/plain)",
|
|
137
|
-
type: "string"
|
|
138
|
-
}
|
|
139
|
-
}), (args) => putObject(args)).command({
|
|
140
|
-
command: "delete <target>",
|
|
141
|
-
aliases: ["rm"],
|
|
142
|
-
describe: "Delete an object, or every object under a prefix",
|
|
143
|
-
builder: (yargs) => yargs.usage("$0 bucket object delete <bucket>/<key> [options]").positional("target", {
|
|
144
|
-
describe: "The object to delete: <bucket>/<key>, or <bucket>/<prefix>/ with --recursive",
|
|
145
|
-
type: "string",
|
|
146
|
-
demandOption: true
|
|
147
|
-
}).options({
|
|
148
|
-
...scopeOptions,
|
|
149
|
-
recursive: {
|
|
150
|
-
describe: "Delete every object under the given prefix. The prefix must end with \"/\"",
|
|
151
|
-
type: "boolean",
|
|
152
|
-
default: false
|
|
153
|
-
}
|
|
154
|
-
}),
|
|
155
|
-
handler: (args) => deleteObject(args)
|
|
156
|
-
}).strictCommands());
|
|
157
|
-
const handler = (args) => {
|
|
158
|
-
return args;
|
|
159
|
-
};
|
|
160
|
-
const createBucket = async (props) => {
|
|
161
|
-
const branchId = await branchIdFromProps(props);
|
|
162
|
-
const { data } = await retryOnLock(() => createProjectBranchBucket(props.apiClient, {
|
|
163
|
-
projectId: props.projectId,
|
|
164
|
-
branchId,
|
|
165
|
-
name: props.name,
|
|
166
|
-
accessLevel: props.accessLevel
|
|
167
|
-
}));
|
|
168
|
-
log.info(`Bucket "${data.bucket.name}" (${data.bucket.access_level}) created on branch ${branchId}`);
|
|
169
|
-
};
|
|
170
|
-
const listBuckets = async (props) => {
|
|
171
|
-
const branchId = await branchIdFromProps(props);
|
|
172
|
-
const { data } = await listProjectBranchBuckets(props.apiClient, {
|
|
173
|
-
projectId: props.projectId,
|
|
174
|
-
branchId
|
|
175
|
-
});
|
|
176
|
-
if (props.output === "json" || props.output === "yaml") {
|
|
177
|
-
writer(props).end(data.buckets, { fields: BUCKET_FIELDS });
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
writer(props).end(data.buckets, {
|
|
181
|
-
fields: BUCKET_FIELDS,
|
|
182
|
-
title: "buckets",
|
|
183
|
-
emptyMessage: "No buckets found."
|
|
184
|
-
});
|
|
185
|
-
};
|
|
186
|
-
const deleteBucket = async (props) => {
|
|
187
|
-
const branchId = await branchIdFromProps(props);
|
|
188
|
-
try {
|
|
189
|
-
await retryOnLock(() => deleteProjectBranchBucket(props.apiClient, {
|
|
190
|
-
projectId: props.projectId,
|
|
191
|
-
branchId,
|
|
192
|
-
bucketName: props.name
|
|
193
|
-
}));
|
|
194
|
-
} catch (err) {
|
|
195
|
-
if (isNeonApiError(err) && err.status === 404) throw new Error(`Bucket "${props.name}" not found on branch ${branchId}.`);
|
|
196
|
-
throw err;
|
|
197
|
-
}
|
|
198
|
-
log.info(`Bucket "${props.name}" deleted from branch ${branchId}`);
|
|
199
|
-
};
|
|
200
|
-
const resolveListDelimiter = (props) => {
|
|
201
|
-
if (props.recursive && props.delimiter !== void 0) throw new Error("--recursive and --delimiter cannot be used together. Use --recursive for a flat listing, or --delimiter to collapse on a separator.");
|
|
202
|
-
if (props.recursive) return;
|
|
203
|
-
if (props.delimiter !== void 0) return props.delimiter;
|
|
204
|
-
return "/";
|
|
205
|
-
};
|
|
206
|
-
const listObjects = async (props) => {
|
|
207
|
-
const delimiter = resolveListDelimiter(props);
|
|
208
|
-
const branchId = await branchIdFromProps(props);
|
|
209
|
-
const { bucket, rest } = splitBucketTarget(props.target);
|
|
210
|
-
const { data } = await listProjectBranchBucketObjects(props.apiClient, {
|
|
211
|
-
projectId: props.projectId,
|
|
212
|
-
branchId,
|
|
213
|
-
bucketName: bucket,
|
|
214
|
-
prefix: rest === "" ? void 0 : rest,
|
|
215
|
-
delimiter,
|
|
216
|
-
cursor: props.cursor,
|
|
217
|
-
limit: props.limit
|
|
218
|
-
});
|
|
219
|
-
if (props.output === "json" || props.output === "yaml") {
|
|
220
|
-
writer(props).end(data, { fields: [
|
|
221
|
-
"folders",
|
|
222
|
-
"objects",
|
|
223
|
-
"prefix",
|
|
224
|
-
"next_cursor",
|
|
225
|
-
"is_truncated"
|
|
226
|
-
] });
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const w = writer(props);
|
|
230
|
-
if (data.folders.length > 0) w.write(data.folders.map((name) => ({ name })), {
|
|
231
|
-
fields: ["name"],
|
|
232
|
-
title: "folders"
|
|
233
|
-
});
|
|
234
|
-
w.write(data.objects, {
|
|
235
|
-
fields: OBJECT_FIELDS,
|
|
236
|
-
title: "objects",
|
|
237
|
-
emptyMessage: "No objects found."
|
|
238
|
-
});
|
|
239
|
-
w.end();
|
|
240
|
-
if (data.is_truncated && data.next_cursor) log.info(`More results available. Re-run with --cursor ${data.next_cursor} to fetch the next page.`);
|
|
241
|
-
};
|
|
242
|
-
const filenameFromContentDisposition = (contentDisposition, key) => {
|
|
243
|
-
if (contentDisposition) {
|
|
244
|
-
const extended = /filename\*=(?:UTF-8'')?([^;]+)/i.exec(contentDisposition);
|
|
245
|
-
if (extended?.[1]) try {
|
|
246
|
-
return basename(decodeURIComponent(extended[1].trim()));
|
|
247
|
-
} catch {}
|
|
248
|
-
const plain = /filename="?([^";]+)"?/i.exec(contentDisposition);
|
|
249
|
-
if (plain?.[1]) return basename(plain[1].trim());
|
|
250
|
-
}
|
|
251
|
-
return basename(key) || key;
|
|
252
|
-
};
|
|
253
|
-
const serverErrorMessage = (body) => {
|
|
254
|
-
const message = body?.message;
|
|
255
|
-
return typeof message === "string" && message.trim() !== "" ? message : void 0;
|
|
256
|
-
};
|
|
257
|
-
const streamErrorMessage = async (stream) => {
|
|
258
|
-
if (typeof stream?.[Symbol.asyncIterator] !== "function") return;
|
|
259
|
-
try {
|
|
260
|
-
const chunks = [];
|
|
261
|
-
for await (const chunk of stream) chunks.push(Buffer.from(chunk));
|
|
262
|
-
return serverErrorMessage(JSON.parse(Buffer.concat(chunks).toString()));
|
|
263
|
-
} catch {
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
const objectNotFoundFallback = (key, bucket, branchId) => `Object "${key}" not found in bucket "${bucket}" on branch ${branchId}.`;
|
|
268
|
-
const objectNotFoundMessage = (err, key, bucket, branchId) => {
|
|
269
|
-
if (isNeonApiError(err)) {
|
|
270
|
-
const serverMessage = serverErrorMessage(err.data);
|
|
271
|
-
if (serverMessage !== void 0) return serverMessage;
|
|
272
|
-
}
|
|
273
|
-
return objectNotFoundFallback(key, bucket, branchId);
|
|
274
|
-
};
|
|
275
|
-
const fileToWebStream = (path) => {
|
|
276
|
-
const source = createReadStream(path);
|
|
277
|
-
return new ReadableStream({
|
|
278
|
-
start(controller) {
|
|
279
|
-
source.on("data", (chunk) => {
|
|
280
|
-
const bytes = typeof chunk === "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);
|
|
281
|
-
controller.enqueue(bytes);
|
|
282
|
-
if ((controller.desiredSize ?? 0) <= 0) source.pause();
|
|
283
|
-
});
|
|
284
|
-
source.on("end", () => {
|
|
285
|
-
controller.close();
|
|
286
|
-
});
|
|
287
|
-
source.on("error", (err) => {
|
|
288
|
-
controller.error(err instanceof Error ? err : new Error(String(err)));
|
|
289
|
-
});
|
|
290
|
-
},
|
|
291
|
-
pull() {
|
|
292
|
-
source.resume();
|
|
293
|
-
},
|
|
294
|
-
cancel() {
|
|
295
|
-
source.destroy();
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
};
|
|
299
|
-
const getObject = async (props) => {
|
|
300
|
-
const branchId = await branchIdFromProps(props);
|
|
301
|
-
const { bucket, rest: key } = splitBucketTarget(props.target);
|
|
302
|
-
if (key === "") throw new Error("Object target must be in the form <bucket>/<key>.");
|
|
303
|
-
let response;
|
|
304
|
-
try {
|
|
305
|
-
response = await getProjectBranchBucketObject(props.apiClient, {
|
|
306
|
-
projectId: props.projectId,
|
|
307
|
-
branchId,
|
|
308
|
-
bucketName: bucket,
|
|
309
|
-
objectKey: key
|
|
310
|
-
});
|
|
311
|
-
} catch (err) {
|
|
312
|
-
if (isNeonApiError(err) && err.status === 404) {
|
|
313
|
-
const serverMessage = await streamErrorMessage(err.data);
|
|
314
|
-
throw new Error(serverMessage ?? objectNotFoundFallback(key, bucket, branchId));
|
|
315
|
-
}
|
|
316
|
-
throw err;
|
|
317
|
-
}
|
|
318
|
-
const contentDisposition = response.headers["content-disposition"];
|
|
319
|
-
const destination = props.file ?? filenameFromContentDisposition(contentDisposition, key);
|
|
320
|
-
try {
|
|
321
|
-
await pipeline(response.data, createWriteStream(destination));
|
|
322
|
-
} catch (err) {
|
|
323
|
-
await unlink(destination).catch(() => void 0);
|
|
324
|
-
throw err;
|
|
325
|
-
}
|
|
326
|
-
log.info(`Object "${key}" downloaded from bucket "${bucket}" on branch ${branchId} to ${destination}`);
|
|
327
|
-
};
|
|
328
|
-
const putObject = async (props) => {
|
|
329
|
-
const branchId = await branchIdFromProps(props);
|
|
330
|
-
const { bucket, rest: key } = splitBucketTarget(props.target);
|
|
331
|
-
if (bucket === "" || key === "") throw new Error("Object target must be in the form <bucket>/<key>.");
|
|
332
|
-
let fileSize;
|
|
333
|
-
try {
|
|
334
|
-
const fileStat = await stat(props.file);
|
|
335
|
-
if (!fileStat.isFile()) throw new Error(`"${props.file}" is not a regular file.`);
|
|
336
|
-
fileSize = fileStat.size;
|
|
337
|
-
} catch (err) {
|
|
338
|
-
if (err?.code === "ENOENT") throw new Error(`File "${props.file}" does not exist.`);
|
|
339
|
-
throw err;
|
|
340
|
-
}
|
|
341
|
-
if (fileSize > MAX_OBJECT_BYTES) throw new Error(`File "${props.file}" is ${fileSize} bytes, which exceeds the ${MAX_OBJECT_BYTES}-byte (100 MB) single-upload limit. Larger objects are not supported yet.`);
|
|
342
|
-
let presign;
|
|
343
|
-
try {
|
|
344
|
-
({data: presign} = await presignUpload(props.apiClient, {
|
|
345
|
-
projectId: props.projectId,
|
|
346
|
-
branchId,
|
|
347
|
-
bucketName: bucket,
|
|
348
|
-
objectKey: key,
|
|
349
|
-
contentType: props.contentType
|
|
350
|
-
}));
|
|
351
|
-
} catch (err) {
|
|
352
|
-
if (isNeonApiError(err)) {
|
|
353
|
-
const status = err.status;
|
|
354
|
-
if (status === 404) throw new Error(objectNotFoundMessage(err, key, bucket, branchId));
|
|
355
|
-
const serverMessage = serverErrorMessage(err.data);
|
|
356
|
-
throw new Error(serverMessage ?? `Failed to presign upload for "${key}" in bucket "${bucket}" on branch ${branchId}${status !== void 0 ? ` (HTTP ${status})` : ""}: ${err.message}`);
|
|
357
|
-
}
|
|
358
|
-
throw err;
|
|
359
|
-
}
|
|
360
|
-
const upload = {
|
|
361
|
-
method: "PUT",
|
|
362
|
-
headers: {
|
|
363
|
-
...presign.headers,
|
|
364
|
-
"Content-Length": String(fileSize)
|
|
365
|
-
},
|
|
366
|
-
body: fileToWebStream(props.file),
|
|
367
|
-
redirect: "error",
|
|
368
|
-
duplex: "half"
|
|
369
|
-
};
|
|
370
|
-
let uploadResponse;
|
|
371
|
-
try {
|
|
372
|
-
uploadResponse = await fetch(presign.url, upload);
|
|
373
|
-
} catch (err) {
|
|
374
|
-
throw new Error(`Failed to upload "${props.file}" to "${key}" in bucket "${bucket}" on branch ${branchId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
375
|
-
}
|
|
376
|
-
if (!uploadResponse.ok) throw new Error(`Failed to upload "${props.file}" to "${key}" in bucket "${bucket}" on branch ${branchId} (HTTP ${uploadResponse.status}): Request failed with status code ${uploadResponse.status}`);
|
|
377
|
-
log.info(`File "${props.file}" uploaded to "${key}" in bucket "${bucket}" on branch ${branchId}`);
|
|
378
|
-
};
|
|
379
|
-
const deleteObject = async (props) => {
|
|
380
|
-
const branchId = await branchIdFromProps(props);
|
|
381
|
-
const { bucket, rest } = splitBucketTarget(props.target);
|
|
382
|
-
if (props.recursive) {
|
|
383
|
-
if (rest === "") throw new Error("Recursive delete requires a non-empty prefix ending in \"/\".");
|
|
384
|
-
if (!rest.endsWith("/")) throw new Error(`Recursive delete requires a prefix ending in "/" (got "${rest}").`);
|
|
385
|
-
const { data } = await retryOnLock(() => deleteProjectBranchBucketObjectsByPrefix(props.apiClient, {
|
|
386
|
-
projectId: props.projectId,
|
|
387
|
-
branchId,
|
|
388
|
-
bucketName: bucket,
|
|
389
|
-
prefix: rest
|
|
390
|
-
}));
|
|
391
|
-
log.info(`Deleted ${data.deleted} object(s) under prefix "${rest}" from bucket "${bucket}" on branch ${branchId}`);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
if (rest === "") throw new Error("Object target must be in the form <bucket>/<key>.");
|
|
395
|
-
try {
|
|
396
|
-
await retryOnLock(() => deleteProjectBranchBucketObject(props.apiClient, {
|
|
397
|
-
projectId: props.projectId,
|
|
398
|
-
branchId,
|
|
399
|
-
bucketName: bucket,
|
|
400
|
-
objectKey: rest
|
|
401
|
-
}));
|
|
402
|
-
} catch (err) {
|
|
403
|
-
if (isNeonApiError(err) && err.status === 404) throw new Error(objectNotFoundMessage(err, rest, bucket, branchId));
|
|
404
|
-
throw err;
|
|
405
|
-
}
|
|
406
|
-
log.info(`Object "${rest}" deleted from bucket "${bucket}" on branch ${branchId}`);
|
|
407
|
-
};
|
|
408
|
-
//#endregion
|
|
409
|
-
export { aliases, builder, command, describe, handler, resolveListDelimiter, splitBucketTarget, bucket_exports as t };
|
|
1
|
+
export { t as aliases, r as builder, i as command, a as describe, o as handler, s as resolveListDelimiter, c as splitBucketTarget } from "../_chunks/bucket-BCdryTkD.js";
|