@dropthis/cli 0.4.1 → 0.6.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/dist/cli.cjs +514 -287
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +93 -21
- package/node_modules/@dropthis/node/dist/drops-BPdmUPCT.d.cts +394 -0
- package/node_modules/@dropthis/node/dist/drops-BPdmUPCT.d.ts +394 -0
- package/node_modules/@dropthis/node/dist/edge.cjs +805 -0
- package/node_modules/@dropthis/node/dist/edge.cjs.map +1 -0
- package/node_modules/@dropthis/node/dist/edge.d.cts +21 -0
- package/node_modules/@dropthis/node/dist/edge.d.ts +21 -0
- package/node_modules/@dropthis/node/dist/edge.mjs +778 -0
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -0
- package/node_modules/@dropthis/node/dist/index.cjs +469 -422
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +13 -408
- package/node_modules/@dropthis/node/dist/index.d.ts +13 -408
- package/node_modules/@dropthis/node/dist/index.mjs +468 -422
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/package.json +11 -1
- package/package.json +2 -2
|
@@ -33,28 +33,62 @@ __export(index_exports, {
|
|
|
33
33
|
CursorPage: () => CursorPage,
|
|
34
34
|
DeploymentsResource: () => DeploymentsResource,
|
|
35
35
|
Dropthis: () => Dropthis,
|
|
36
|
+
PublishInputError: () => PublishInputError,
|
|
36
37
|
UploadsResource: () => UploadsResource,
|
|
37
38
|
createErrorResult: () => createErrorResult,
|
|
38
39
|
redactSecrets: () => redactSecrets
|
|
39
40
|
});
|
|
40
41
|
module.exports = __toCommonJS(index_exports);
|
|
41
42
|
|
|
42
|
-
// src/
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// src/publish/checksum.ts
|
|
47
|
-
var import_node_crypto = require("crypto");
|
|
48
|
-
var import_node_fs = require("fs");
|
|
49
|
-
function sha256Bytes(bytes) {
|
|
50
|
-
return (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
|
|
43
|
+
// src/errors.ts
|
|
44
|
+
var API_KEY_RE = /sk_[A-Za-z0-9_-]+/g;
|
|
45
|
+
function redactSecrets(message) {
|
|
46
|
+
return message.replace(API_KEY_RE, "sk_[redacted]");
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
function createErrorResult(code, message, statusCode, extra = {}) {
|
|
49
|
+
return {
|
|
50
|
+
data: null,
|
|
51
|
+
error: {
|
|
52
|
+
code,
|
|
53
|
+
message: redactSecrets(message),
|
|
54
|
+
statusCode,
|
|
55
|
+
...extra.type ? { type: extra.type } : {},
|
|
56
|
+
...extra.title !== void 0 ? { title: extra.title } : {},
|
|
57
|
+
...extra.detail !== void 0 ? { detail: extra.detail } : {},
|
|
58
|
+
...extra.instance !== void 0 ? { instance: extra.instance } : {},
|
|
59
|
+
...extra.param !== void 0 ? { param: extra.param } : {},
|
|
60
|
+
...extra.currentRevision !== void 0 ? { currentRevision: extra.currentRevision } : {},
|
|
61
|
+
...extra.requestId !== void 0 ? { requestId: extra.requestId } : {},
|
|
62
|
+
...extra.suggestion !== void 0 ? { suggestion: extra.suggestion } : {},
|
|
63
|
+
...extra.retryable !== void 0 ? { retryable: extra.retryable } : {},
|
|
64
|
+
...extra.body !== void 0 ? { body: extra.body } : {}
|
|
65
|
+
},
|
|
66
|
+
headers: extra.headers ?? {}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
var PublishInputError = class extends Error {
|
|
70
|
+
constructor(code, message, param, suggestion) {
|
|
71
|
+
super(message);
|
|
72
|
+
this.code = code;
|
|
73
|
+
this.param = param;
|
|
74
|
+
this.suggestion = suggestion;
|
|
75
|
+
this.name = "PublishInputError";
|
|
76
|
+
}
|
|
77
|
+
code;
|
|
78
|
+
param;
|
|
79
|
+
suggestion;
|
|
80
|
+
};
|
|
81
|
+
function toErrorResult(err) {
|
|
82
|
+
if (err instanceof PublishInputError)
|
|
83
|
+
return createErrorResult(err.code, err.message, null, {
|
|
84
|
+
param: err.param ?? null,
|
|
85
|
+
suggestion: err.suggestion ?? null
|
|
86
|
+
});
|
|
87
|
+
return createErrorResult(
|
|
88
|
+
"sdk_error",
|
|
89
|
+
err instanceof Error ? err.message : "Unknown SDK error",
|
|
90
|
+
null
|
|
91
|
+
);
|
|
58
92
|
}
|
|
59
93
|
|
|
60
94
|
// src/publish/detect.ts
|
|
@@ -66,246 +100,100 @@ function isHttpUrl(value) {
|
|
|
66
100
|
return false;
|
|
67
101
|
}
|
|
68
102
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
return trimmed.startsWith("<!doctype html") || trimmed.startsWith("<html") || /^<[a-z][a-z0-9:-]*(\s|>)/.test(trimmed);
|
|
103
|
+
function containsHtmlTag(value) {
|
|
104
|
+
return /<[a-z!/][^>]*>/i.test(value);
|
|
72
105
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
var FILE_EXT = /\.[A-Za-z0-9]{1,8}([?#].*)?$/;
|
|
107
|
+
function isPathShaped(value) {
|
|
108
|
+
if (value.length === 0 || value.length > 4096 || value.includes("\n"))
|
|
109
|
+
return false;
|
|
110
|
+
if (containsHtmlTag(value)) return false;
|
|
111
|
+
if (value.includes("/") || value.includes("\\")) return true;
|
|
112
|
+
if (/^[A-Za-z]:[\\/]/.test(value)) return true;
|
|
113
|
+
return FILE_EXT.test(value);
|
|
114
|
+
}
|
|
115
|
+
function contentTypeForString(value, override) {
|
|
116
|
+
if (override) return override;
|
|
117
|
+
return containsHtmlTag(value) ? "text/html" : "text/plain; charset=utf-8";
|
|
79
118
|
}
|
|
80
119
|
function detectBytesContentType(bytes) {
|
|
81
|
-
const text =
|
|
120
|
+
const text = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
82
121
|
if (text.includes("\uFFFD")) return "application/octet-stream";
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// src/publish/files.ts
|
|
87
|
-
var import_promises = require("fs/promises");
|
|
88
|
-
var import_node_path = require("path");
|
|
89
|
-
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
90
|
-
var import_ignore = __toESM(require("ignore"), 1);
|
|
91
|
-
var import_mime_types = require("mime-types");
|
|
92
|
-
var DEFAULT_IGNORES = [
|
|
93
|
-
".git",
|
|
94
|
-
".git/**",
|
|
95
|
-
"node_modules",
|
|
96
|
-
"node_modules/**",
|
|
97
|
-
".DS_Store",
|
|
98
|
-
".env",
|
|
99
|
-
".env.*",
|
|
100
|
-
".cache",
|
|
101
|
-
".cache/**",
|
|
102
|
-
".tmp",
|
|
103
|
-
".tmp/**",
|
|
104
|
-
"dist/.cache",
|
|
105
|
-
"dist/.cache/**"
|
|
106
|
-
];
|
|
107
|
-
async function collectPublishFiles(inputPath, options = {}) {
|
|
108
|
-
const inputStat = await (0, import_promises.stat)(inputPath);
|
|
109
|
-
if (inputStat.isFile()) {
|
|
110
|
-
return [
|
|
111
|
-
{
|
|
112
|
-
absolutePath: inputPath,
|
|
113
|
-
path: (0, import_node_path.basename)(inputPath),
|
|
114
|
-
contentType: await detectPathContentType(inputPath),
|
|
115
|
-
sizeBytes: inputStat.size
|
|
116
|
-
}
|
|
117
|
-
];
|
|
118
|
-
}
|
|
119
|
-
if (!inputStat.isDirectory()) {
|
|
120
|
-
throw new Error(`Input is not a file or directory: ${inputPath}`);
|
|
121
|
-
}
|
|
122
|
-
const matcher = (0, import_ignore.default)().add([
|
|
123
|
-
...options.ignoreDefaults === false ? [] : DEFAULT_IGNORES,
|
|
124
|
-
...options.ignore ?? []
|
|
125
|
-
]);
|
|
126
|
-
const entries = await (0, import_fast_glob.default)("**/*", {
|
|
127
|
-
cwd: inputPath,
|
|
128
|
-
onlyFiles: true,
|
|
129
|
-
followSymbolicLinks: false,
|
|
130
|
-
dot: true,
|
|
131
|
-
unique: true
|
|
132
|
-
});
|
|
133
|
-
const paths = entries.map((entry) => entry.split(import_node_path.sep).join("/")).filter((entry) => !matcher.ignores(entry)).sort((a, b) => a.localeCompare(b));
|
|
134
|
-
return Promise.all(
|
|
135
|
-
paths.map(async (path) => {
|
|
136
|
-
const absolutePath = `${inputPath}/${path}`;
|
|
137
|
-
const fileStat = await (0, import_promises.stat)(absolutePath);
|
|
138
|
-
return {
|
|
139
|
-
absolutePath,
|
|
140
|
-
path,
|
|
141
|
-
contentType: await detectPathContentType(absolutePath),
|
|
142
|
-
sizeBytes: fileStat.size
|
|
143
|
-
};
|
|
144
|
-
})
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
async function detectPathContentType(path) {
|
|
148
|
-
const detected = (0, import_mime_types.lookup)(path);
|
|
149
|
-
if (detected) return detected;
|
|
150
|
-
return detectBytesContentType(await (0, import_promises.readFile)(path));
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// src/publish/prepare.ts
|
|
154
|
-
var SINGLE_PUT_CHECKSUM_THRESHOLD_BYTES = 10 * 1024 * 1024;
|
|
155
|
-
async function preparePublishRequest(input, options = {}) {
|
|
156
|
-
if (input instanceof URL) {
|
|
157
|
-
throw new Error(
|
|
158
|
-
"URL inputs are not supported. Fetch the content first, then pass it as a string or file."
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
if (typeof input === "string") {
|
|
162
|
-
const local = await localKind(input);
|
|
163
|
-
if (local === "file") {
|
|
164
|
-
return fileStaged(input, options);
|
|
165
|
-
}
|
|
166
|
-
if (local === "directory") {
|
|
167
|
-
return folderStaged(input, options);
|
|
168
|
-
}
|
|
169
|
-
const detection = detectStringInput(input);
|
|
170
|
-
if (detection.mode === "sourceUrl")
|
|
171
|
-
throw new Error(
|
|
172
|
-
"URL inputs are not supported. Fetch the content first, then pass it as a string or file."
|
|
173
|
-
);
|
|
174
|
-
return stringContent(input, options, detection.contentType);
|
|
175
|
-
}
|
|
176
|
-
if (input instanceof Uint8Array || Buffer.isBuffer(input)) {
|
|
177
|
-
return bytesStaged(input, options);
|
|
178
|
-
}
|
|
179
|
-
return explicitInput(input, options);
|
|
180
|
-
}
|
|
181
|
-
async function stringContent(content, options, detectedContentType) {
|
|
182
|
-
const contentType = options.contentType ?? detectedContentType;
|
|
183
|
-
return bytesStaged(Buffer.from(content), {
|
|
184
|
-
...options,
|
|
185
|
-
path: options.path ?? entryForContentType(contentType),
|
|
186
|
-
contentType
|
|
187
|
-
});
|
|
122
|
+
return containsHtmlTag(text) ? "text/html" : "text/plain; charset=utf-8";
|
|
188
123
|
}
|
|
189
124
|
function entryForContentType(contentType) {
|
|
190
|
-
const
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
if (
|
|
194
|
-
if (
|
|
195
|
-
if (normalized === "text/javascript" || normalized === "application/javascript")
|
|
125
|
+
const m = contentType.toLowerCase().split(";", 1)[0]?.trim() ?? "";
|
|
126
|
+
if (m === "text/html" || m === "application/xhtml+xml") return "index.html";
|
|
127
|
+
if (m === "application/json") return "index.json";
|
|
128
|
+
if (m === "text/css") return "index.css";
|
|
129
|
+
if (m === "text/javascript" || m === "application/javascript")
|
|
196
130
|
return "index.js";
|
|
197
|
-
if (
|
|
131
|
+
if (m.startsWith("text/")) return "index.txt";
|
|
198
132
|
return "index";
|
|
199
133
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (info.isDirectory()) return "directory";
|
|
205
|
-
return "none";
|
|
206
|
-
} catch {
|
|
207
|
-
return "none";
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async function fileStaged(path, options) {
|
|
211
|
-
const fileStat = await (0, import_promises2.stat)(path);
|
|
212
|
-
const manifestPath = options.path ?? (0, import_node_path2.basename)(path);
|
|
213
|
-
return stagedRequest(
|
|
214
|
-
[
|
|
215
|
-
{
|
|
216
|
-
path: manifestPath,
|
|
217
|
-
contentType: options.contentType ?? await detectPathContentType(path),
|
|
218
|
-
sizeBytes: fileStat.size,
|
|
219
|
-
source: { kind: "path", path }
|
|
220
|
-
}
|
|
221
|
-
],
|
|
222
|
-
{ ...options, entry: options.entry ?? manifestPath }
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
async function folderStaged(path, options) {
|
|
226
|
-
const files = (await collectPublishFiles(path, options)).map((file) => ({
|
|
227
|
-
path: file.path,
|
|
228
|
-
contentType: file.contentType,
|
|
229
|
-
sizeBytes: file.sizeBytes,
|
|
230
|
-
source: { kind: "path", path: file.absolutePath }
|
|
231
|
-
}));
|
|
232
|
-
return stagedRequest(files, options);
|
|
233
|
-
}
|
|
234
|
-
async function bytesStaged(bytes, options) {
|
|
235
|
-
return stagedRequest(
|
|
236
|
-
[
|
|
237
|
-
{
|
|
238
|
-
path: options.path ?? "index",
|
|
239
|
-
contentType: options.contentType ?? detectBytesContentType(bytes),
|
|
240
|
-
sizeBytes: bytes.byteLength,
|
|
241
|
-
source: { kind: "bytes", bytes }
|
|
242
|
-
}
|
|
243
|
-
],
|
|
244
|
-
options
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
async function stagedRequest(files, options) {
|
|
248
|
-
const preparedFiles = await Promise.all(
|
|
249
|
-
files.map(async (file) => {
|
|
250
|
-
if (file.sizeBytes <= SINGLE_PUT_CHECKSUM_THRESHOLD_BYTES) return file;
|
|
251
|
-
const checksumSha256 = file.source.kind === "bytes" ? sha256Bytes(file.source.bytes) : await sha256File(file.source.path);
|
|
252
|
-
return { ...file, checksumSha256 };
|
|
253
|
-
})
|
|
254
|
-
);
|
|
255
|
-
const manifestFiles = preparedFiles.map((file) => ({
|
|
256
|
-
path: file.path,
|
|
257
|
-
contentType: file.contentType,
|
|
258
|
-
sizeBytes: file.sizeBytes,
|
|
259
|
-
...file.checksumSha256 ? { checksumSha256: file.checksumSha256 } : {}
|
|
260
|
-
}));
|
|
261
|
-
const prepared = {
|
|
262
|
-
kind: "staged",
|
|
263
|
-
manifest: {
|
|
264
|
-
schemaVersion: 1,
|
|
265
|
-
files: manifestFiles,
|
|
266
|
-
...options.entry ? { entry: options.entry } : {}
|
|
267
|
-
},
|
|
268
|
-
files: preparedFiles,
|
|
269
|
-
options: optionsBody(options)
|
|
270
|
-
};
|
|
271
|
-
if (options.metadata) prepared.metadata = options.metadata;
|
|
272
|
-
return prepared;
|
|
134
|
+
|
|
135
|
+
// src/publish/paths.ts
|
|
136
|
+
function normalizeManifestPath(path) {
|
|
137
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
273
138
|
}
|
|
274
|
-
|
|
275
|
-
if ("
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
139
|
+
function assertValidManifestPath(path) {
|
|
140
|
+
if (path.includes("\\"))
|
|
141
|
+
throw new PublishInputError(
|
|
142
|
+
"invalid_path",
|
|
143
|
+
`Manifest path must use "/": "${path}".`,
|
|
144
|
+
path
|
|
280
145
|
);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
146
|
+
const p = normalizeManifestPath(path);
|
|
147
|
+
if (p === "")
|
|
148
|
+
throw new PublishInputError(
|
|
149
|
+
"invalid_path",
|
|
150
|
+
"Manifest path must not be empty.",
|
|
151
|
+
path
|
|
284
152
|
);
|
|
285
|
-
if ("
|
|
286
|
-
throw new
|
|
287
|
-
"
|
|
153
|
+
if (p.startsWith("/"))
|
|
154
|
+
throw new PublishInputError(
|
|
155
|
+
"invalid_path",
|
|
156
|
+
`Manifest path must be relative: "${path}".`,
|
|
157
|
+
path
|
|
158
|
+
);
|
|
159
|
+
if (p.startsWith("~"))
|
|
160
|
+
throw new PublishInputError(
|
|
161
|
+
"invalid_path",
|
|
162
|
+
`Manifest path must not start with "~": "${path}".`,
|
|
163
|
+
path
|
|
164
|
+
);
|
|
165
|
+
if (p.split("/").includes(".."))
|
|
166
|
+
throw new PublishInputError(
|
|
167
|
+
"invalid_path",
|
|
168
|
+
`Manifest path must not contain "..": "${path}".`,
|
|
169
|
+
path
|
|
288
170
|
);
|
|
289
|
-
return stagedRequest(
|
|
290
|
-
input.files.map((file) => {
|
|
291
|
-
const bytes = explicitFileBytes(file);
|
|
292
|
-
return {
|
|
293
|
-
path: file.path,
|
|
294
|
-
contentType: file.contentType,
|
|
295
|
-
sizeBytes: bytes.byteLength,
|
|
296
|
-
source: { kind: "bytes", bytes }
|
|
297
|
-
};
|
|
298
|
-
}),
|
|
299
|
-
{ ...options, ...input }
|
|
300
|
-
);
|
|
301
171
|
}
|
|
302
|
-
function
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
172
|
+
function assertNoDuplicatePaths(paths) {
|
|
173
|
+
const seen = /* @__PURE__ */ new Set();
|
|
174
|
+
for (const raw of paths) {
|
|
175
|
+
const p = normalizeManifestPath(raw);
|
|
176
|
+
if (seen.has(p))
|
|
177
|
+
throw new PublishInputError(
|
|
178
|
+
"duplicate_path",
|
|
179
|
+
`Duplicate file path after normalization: "${p}".`,
|
|
180
|
+
p,
|
|
181
|
+
"Give each file a unique path; basename mapping for string[] can collide."
|
|
182
|
+
);
|
|
183
|
+
seen.add(p);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function assertNonEmptyBundle(paths) {
|
|
187
|
+
if (paths.length === 0)
|
|
188
|
+
throw new PublishInputError(
|
|
189
|
+
"empty_bundle",
|
|
190
|
+
"Nothing to publish: the bundle has no files.",
|
|
191
|
+
void 0,
|
|
192
|
+
"Pass at least one file, or a directory that contains files."
|
|
193
|
+
);
|
|
308
194
|
}
|
|
195
|
+
|
|
196
|
+
// src/publish/core.ts
|
|
309
197
|
var VALID_VISIBILITIES = ["public", "unlisted"];
|
|
310
198
|
var MAX_TITLE_LENGTH = 500;
|
|
311
199
|
function validatePublishOptions(options) {
|
|
@@ -342,93 +230,125 @@ function optionsBody(options) {
|
|
|
342
230
|
expiresAt: options.expiresAt instanceof Date ? options.expiresAt.toISOString() : options.expiresAt
|
|
343
231
|
};
|
|
344
232
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
...extra.suggestion !== void 0 ? { suggestion: extra.suggestion } : {},
|
|
368
|
-
...extra.retryable !== void 0 ? { retryable: extra.retryable } : {}
|
|
369
|
-
},
|
|
370
|
-
headers: extra.headers ?? {}
|
|
233
|
+
function buildStagedRequest(files, options, entry) {
|
|
234
|
+
assertNonEmptyBundle(files.map((f) => f.path));
|
|
235
|
+
const normalizedPaths = files.map((f) => normalizeManifestPath(f.path));
|
|
236
|
+
assertNoDuplicatePaths(normalizedPaths);
|
|
237
|
+
const manifestFiles = files.map((file) => ({
|
|
238
|
+
path: normalizeManifestPath(file.path),
|
|
239
|
+
contentType: file.contentType,
|
|
240
|
+
sizeBytes: file.sizeBytes,
|
|
241
|
+
...file.checksumSha256 ? { checksumSha256: file.checksumSha256 } : {}
|
|
242
|
+
}));
|
|
243
|
+
const resolvedEntry = entry ?? options.entry;
|
|
244
|
+
if (resolvedEntry !== void 0) assertValidManifestPath(resolvedEntry);
|
|
245
|
+
const manifest = {
|
|
246
|
+
schemaVersion: 1,
|
|
247
|
+
files: manifestFiles,
|
|
248
|
+
...resolvedEntry ? { entry: resolvedEntry } : {}
|
|
249
|
+
};
|
|
250
|
+
const prepared = {
|
|
251
|
+
kind: "staged",
|
|
252
|
+
manifest,
|
|
253
|
+
files,
|
|
254
|
+
options: optionsBody(options)
|
|
371
255
|
};
|
|
256
|
+
if (options.metadata) prepared.metadata = options.metadata;
|
|
257
|
+
return prepared;
|
|
372
258
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
"
|
|
380
|
-
"Multipart upload target did not include a valid part size.",
|
|
381
|
-
null
|
|
259
|
+
function buildSourceRequest(sourceUrl, options) {
|
|
260
|
+
if (!isHttpUrl(sourceUrl)) {
|
|
261
|
+
throw new PublishInputError(
|
|
262
|
+
"invalid_source_url",
|
|
263
|
+
"source_url must be an http(s) URL.",
|
|
264
|
+
sourceUrl,
|
|
265
|
+
"Fetch the content first, then pass it as content/files."
|
|
382
266
|
);
|
|
383
267
|
}
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
268
|
+
const prepared = {
|
|
269
|
+
kind: "source",
|
|
270
|
+
sourceUrl,
|
|
271
|
+
options: optionsBody(options)
|
|
272
|
+
};
|
|
273
|
+
if (options.metadata) prepared.metadata = options.metadata;
|
|
274
|
+
return prepared;
|
|
275
|
+
}
|
|
276
|
+
function decodeBase64(value) {
|
|
277
|
+
const binary = atob(value);
|
|
278
|
+
return Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
279
|
+
}
|
|
280
|
+
function fileBytes(file) {
|
|
281
|
+
if (file.content !== void 0) return new TextEncoder().encode(file.content);
|
|
282
|
+
if (file.contentBase64 !== void 0) return decodeBase64(file.contentBase64);
|
|
283
|
+
if (file.bytes !== void 0) return file.bytes;
|
|
284
|
+
throw new PublishInputError(
|
|
285
|
+
"missing_file_bytes",
|
|
286
|
+
`File "${file.path}" is missing content bytes.`,
|
|
287
|
+
file.path,
|
|
288
|
+
"Provide one of content, contentBase64, or bytes."
|
|
387
289
|
);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
{ body: { fileId, partNumbers: partNumberBatch } }
|
|
398
|
-
);
|
|
399
|
-
if (targetsResult.error) return errorResult(targetsResult);
|
|
400
|
-
for (const target of targetsResult.data.parts) {
|
|
401
|
-
const start = (target.partNumber - 1) * partSize;
|
|
402
|
-
const end = Math.min(start + partSize, bytes.byteLength);
|
|
403
|
-
const uploadResult = await transport.putSignedUrl(
|
|
404
|
-
target.url,
|
|
405
|
-
bytes.slice(start, end),
|
|
406
|
-
target.headers
|
|
407
|
-
);
|
|
408
|
-
if (uploadResult.error) return errorResult(uploadResult);
|
|
409
|
-
if (!uploadResult.data.etag) {
|
|
410
|
-
return createErrorResult(
|
|
411
|
-
"missing_upload_etag",
|
|
412
|
-
"Signed upload response did not include an ETag.",
|
|
413
|
-
null
|
|
414
|
-
);
|
|
290
|
+
}
|
|
291
|
+
function singleStagedFile(path, contentType, bytes, options) {
|
|
292
|
+
return buildStagedRequest(
|
|
293
|
+
[
|
|
294
|
+
{
|
|
295
|
+
path,
|
|
296
|
+
contentType,
|
|
297
|
+
sizeBytes: bytes.byteLength,
|
|
298
|
+
getBody: async () => bytes
|
|
415
299
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
300
|
+
],
|
|
301
|
+
options
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
async function resolveInMemory(input, options = {}) {
|
|
305
|
+
if (input instanceof URL) {
|
|
306
|
+
return buildSourceRequest(input.toString(), options);
|
|
421
307
|
}
|
|
422
|
-
|
|
308
|
+
if (typeof input === "string") {
|
|
309
|
+
if (isHttpUrl(input)) return buildSourceRequest(input, options);
|
|
310
|
+
const contentType = contentTypeForString(input, options.contentType);
|
|
311
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
312
|
+
const path = options.path ?? entryForContentType(contentType);
|
|
313
|
+
const bytes = new TextEncoder().encode(input);
|
|
314
|
+
return singleStagedFile(path, contentType, bytes, options);
|
|
315
|
+
}
|
|
316
|
+
if (input instanceof Uint8Array) {
|
|
317
|
+
const contentType = options.contentType ?? detectBytesContentType(input);
|
|
318
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
319
|
+
const path = options.path ?? entryForContentType(contentType);
|
|
320
|
+
return singleStagedFile(path, contentType, input, options);
|
|
321
|
+
}
|
|
322
|
+
if (input.kind === "content") {
|
|
323
|
+
const contentType = input.contentType ?? options.contentType ?? "text/html";
|
|
324
|
+
if (input.path !== void 0) assertValidManifestPath(input.path);
|
|
325
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
326
|
+
const path = input.path ?? options.path ?? entryForContentType(contentType);
|
|
327
|
+
const bytes = new TextEncoder().encode(input.content);
|
|
328
|
+
return singleStagedFile(path, contentType, bytes, options);
|
|
329
|
+
}
|
|
330
|
+
if (input.kind === "source_url") {
|
|
331
|
+
return buildSourceRequest(input.sourceUrl, options);
|
|
332
|
+
}
|
|
333
|
+
const files = input.files.map((file) => {
|
|
334
|
+
assertValidManifestPath(file.path);
|
|
335
|
+
const bytes = fileBytes(file);
|
|
336
|
+
const contentType = file.contentType ?? detectBytesContentType(bytes);
|
|
337
|
+
return {
|
|
338
|
+
path: file.path,
|
|
339
|
+
contentType,
|
|
340
|
+
sizeBytes: bytes.byteLength,
|
|
341
|
+
getBody: async () => bytes
|
|
342
|
+
};
|
|
343
|
+
});
|
|
344
|
+
return buildStagedRequest(files, options, input.entry);
|
|
423
345
|
}
|
|
424
346
|
function errorResult(result) {
|
|
425
347
|
if (!result.error) throw new Error("Expected an error result");
|
|
426
348
|
return { data: null, error: result.error, headers: result.headers };
|
|
427
349
|
}
|
|
428
|
-
|
|
429
|
-
// src/publish/upload.ts
|
|
430
350
|
async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
431
|
-
const baseKey = options.idempotencyKey ?? `sdk-${
|
|
351
|
+
const baseKey = options.idempotencyKey ?? `sdk-${crypto.randomUUID()}`;
|
|
432
352
|
const createResult = await transport.request(
|
|
433
353
|
"POST",
|
|
434
354
|
"/uploads",
|
|
@@ -437,12 +357,9 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
437
357
|
idempotencyKey: `${baseKey}:create-upload`
|
|
438
358
|
}
|
|
439
359
|
);
|
|
440
|
-
if (createResult.error) return
|
|
441
|
-
const completedFiles = {};
|
|
360
|
+
if (createResult.error) return errorResult(createResult);
|
|
442
361
|
for (const file of prepared.files) {
|
|
443
|
-
const target = createResult.data.files.find(
|
|
444
|
-
(candidate) => candidate.path === file.path
|
|
445
|
-
);
|
|
362
|
+
const target = createResult.data.files.find((f) => f.path === file.path);
|
|
446
363
|
if (!target) {
|
|
447
364
|
return createErrorResult(
|
|
448
365
|
"upload_target_missing",
|
|
@@ -450,36 +367,29 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
450
367
|
null
|
|
451
368
|
);
|
|
452
369
|
}
|
|
453
|
-
if (target.upload.strategy
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
target.fileId,
|
|
459
|
-
bytes2,
|
|
460
|
-
target.upload.partSize
|
|
370
|
+
if (target.upload.strategy !== "single_put") {
|
|
371
|
+
return createErrorResult(
|
|
372
|
+
"unsupported_upload_strategy",
|
|
373
|
+
`Unsupported upload strategy "${target.upload.strategy}" for ${file.path}. This SDK uploads via single PUT only.`,
|
|
374
|
+
null
|
|
461
375
|
);
|
|
462
|
-
if (partsResult.error) return errorResult2(partsResult);
|
|
463
|
-
completedFiles[target.fileId] = { parts: partsResult.data };
|
|
464
|
-
continue;
|
|
465
376
|
}
|
|
466
|
-
const
|
|
467
|
-
const uploadResult = await transport.putSignedUrl(
|
|
377
|
+
const put = await transport.putSignedUrl(
|
|
468
378
|
target.upload.url,
|
|
469
|
-
|
|
379
|
+
await file.getBody(),
|
|
470
380
|
target.upload.headers
|
|
471
381
|
);
|
|
472
|
-
if (
|
|
382
|
+
if (put.error) return errorResult(put);
|
|
473
383
|
}
|
|
474
384
|
const completeResult = await transport.request(
|
|
475
385
|
"POST",
|
|
476
386
|
`/uploads/${encodeURIComponent(createResult.data.uploadId)}/complete`,
|
|
477
387
|
{
|
|
478
|
-
body: { files:
|
|
388
|
+
body: { files: {} },
|
|
479
389
|
idempotencyKey: `${baseKey}:complete-upload`
|
|
480
390
|
}
|
|
481
391
|
);
|
|
482
|
-
if (completeResult.error) return
|
|
392
|
+
if (completeResult.error) return errorResult(completeResult);
|
|
483
393
|
const finalOptions = {
|
|
484
394
|
body: {
|
|
485
395
|
uploadId: createResult.data.uploadId,
|
|
@@ -492,13 +402,184 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
492
402
|
finalOptions.ifRevision = options.ifRevision;
|
|
493
403
|
return transport.request("POST", finalPath, finalOptions);
|
|
494
404
|
}
|
|
495
|
-
async function
|
|
496
|
-
|
|
497
|
-
return (
|
|
405
|
+
async function publishSource(transport, prepared, finalPath, options = {}) {
|
|
406
|
+
const baseKey = options.idempotencyKey ?? `sdk-${crypto.randomUUID()}`;
|
|
407
|
+
return transport.request("POST", finalPath, {
|
|
408
|
+
body: {
|
|
409
|
+
sourceUrl: prepared.sourceUrl,
|
|
410
|
+
options: prepared.options,
|
|
411
|
+
...prepared.metadata ? { metadata: prepared.metadata } : {}
|
|
412
|
+
},
|
|
413
|
+
idempotencyKey: `${baseKey}:publish`,
|
|
414
|
+
...options.ifRevision !== void 0 ? { ifRevision: options.ifRevision } : {}
|
|
415
|
+
});
|
|
498
416
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
417
|
+
|
|
418
|
+
// src/publish/node.ts
|
|
419
|
+
var import_promises2 = require("fs/promises");
|
|
420
|
+
var import_node_path2 = require("path");
|
|
421
|
+
|
|
422
|
+
// src/publish/checksum.ts
|
|
423
|
+
var import_node_crypto = require("crypto");
|
|
424
|
+
var import_node_fs = require("fs");
|
|
425
|
+
async function sha256File(path) {
|
|
426
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
427
|
+
for await (const chunk of (0, import_node_fs.createReadStream)(path)) {
|
|
428
|
+
hash.update(chunk);
|
|
429
|
+
}
|
|
430
|
+
return hash.digest("hex");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/publish/files.ts
|
|
434
|
+
var import_promises = require("fs/promises");
|
|
435
|
+
var import_node_path = require("path");
|
|
436
|
+
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
437
|
+
var import_ignore = __toESM(require("ignore"), 1);
|
|
438
|
+
var import_mime_types = require("mime-types");
|
|
439
|
+
var DEFAULT_IGNORES = [
|
|
440
|
+
".git",
|
|
441
|
+
".git/**",
|
|
442
|
+
"node_modules",
|
|
443
|
+
"node_modules/**",
|
|
444
|
+
".DS_Store",
|
|
445
|
+
".env",
|
|
446
|
+
".env.*",
|
|
447
|
+
".cache",
|
|
448
|
+
".cache/**",
|
|
449
|
+
".tmp",
|
|
450
|
+
".tmp/**",
|
|
451
|
+
"dist/.cache",
|
|
452
|
+
"dist/.cache/**"
|
|
453
|
+
];
|
|
454
|
+
async function collectPublishFiles(inputPath, options = {}) {
|
|
455
|
+
const inputStat = await (0, import_promises.stat)(inputPath);
|
|
456
|
+
if (inputStat.isFile()) {
|
|
457
|
+
return [
|
|
458
|
+
{
|
|
459
|
+
absolutePath: inputPath,
|
|
460
|
+
path: (0, import_node_path.basename)(inputPath),
|
|
461
|
+
contentType: await detectPathContentType(inputPath),
|
|
462
|
+
sizeBytes: inputStat.size
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
}
|
|
466
|
+
if (!inputStat.isDirectory()) {
|
|
467
|
+
throw new Error(`Input is not a file or directory: ${inputPath}`);
|
|
468
|
+
}
|
|
469
|
+
const matcher = (0, import_ignore.default)().add([
|
|
470
|
+
...options.ignoreDefaults === false ? [] : DEFAULT_IGNORES,
|
|
471
|
+
...options.ignore ?? []
|
|
472
|
+
]);
|
|
473
|
+
const entries = await (0, import_fast_glob.default)("**/*", {
|
|
474
|
+
cwd: inputPath,
|
|
475
|
+
onlyFiles: true,
|
|
476
|
+
followSymbolicLinks: false,
|
|
477
|
+
dot: true,
|
|
478
|
+
unique: true
|
|
479
|
+
});
|
|
480
|
+
const paths = entries.map((entry) => entry.split(import_node_path.sep).join("/")).filter((entry) => !matcher.ignores(entry)).sort((a, b) => a.localeCompare(b));
|
|
481
|
+
return Promise.all(
|
|
482
|
+
paths.map(async (path) => {
|
|
483
|
+
const absolutePath = `${inputPath}/${path}`;
|
|
484
|
+
const fileStat = await (0, import_promises.stat)(absolutePath);
|
|
485
|
+
return {
|
|
486
|
+
absolutePath,
|
|
487
|
+
path,
|
|
488
|
+
contentType: await detectPathContentType(absolutePath),
|
|
489
|
+
sizeBytes: fileStat.size
|
|
490
|
+
};
|
|
491
|
+
})
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
async function detectPathContentType(path) {
|
|
495
|
+
const detected = (0, import_mime_types.lookup)(path);
|
|
496
|
+
if (detected) return detected;
|
|
497
|
+
return detectBytesContentType(await (0, import_promises.readFile)(path));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// src/publish/node.ts
|
|
501
|
+
var SINGLE_PUT_CHECKSUM_THRESHOLD = 10 * 1024 * 1024;
|
|
502
|
+
async function resolveInput(input, options = {}) {
|
|
503
|
+
if (input instanceof URL || input instanceof Uint8Array || typeof input === "object" && input !== null && "kind" in input) {
|
|
504
|
+
return resolveInMemory(input, options);
|
|
505
|
+
}
|
|
506
|
+
if (Array.isArray(input)) {
|
|
507
|
+
return resolveBundle(input, options);
|
|
508
|
+
}
|
|
509
|
+
if (typeof input === "string") {
|
|
510
|
+
return resolveString(input, options);
|
|
511
|
+
}
|
|
512
|
+
return resolveInMemory(input, options);
|
|
513
|
+
}
|
|
514
|
+
async function resolveString(value, options) {
|
|
515
|
+
if (isHttpUrl(value)) return resolveInMemory(value, options);
|
|
516
|
+
if (value.includes("\n") || value.length > 4096) {
|
|
517
|
+
return resolveInMemory(value, options);
|
|
518
|
+
}
|
|
519
|
+
let info;
|
|
520
|
+
try {
|
|
521
|
+
info = await (0, import_promises2.stat)(value);
|
|
522
|
+
} catch {
|
|
523
|
+
info = void 0;
|
|
524
|
+
}
|
|
525
|
+
if (info?.isFile()) return fileStaged(value, options);
|
|
526
|
+
if (info?.isDirectory()) return folderStaged(value, options);
|
|
527
|
+
if (isPathShaped(value)) {
|
|
528
|
+
throw new PublishInputError(
|
|
529
|
+
"file_not_found",
|
|
530
|
+
`No file or directory at "${value}".`,
|
|
531
|
+
value,
|
|
532
|
+
'To publish this as inline text, pass { kind: "content", content }.'
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
return resolveInMemory(value, options);
|
|
536
|
+
}
|
|
537
|
+
async function fileStaged(path, options) {
|
|
538
|
+
const fileStat = await (0, import_promises2.stat)(path);
|
|
539
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
540
|
+
const manifestPath = options.path ?? (0, import_node_path2.basename)(path);
|
|
541
|
+
const contentType = options.contentType ?? await detectPathContentType(path);
|
|
542
|
+
const checksumSha256 = fileStat.size > SINGLE_PUT_CHECKSUM_THRESHOLD ? await sha256File(path) : void 0;
|
|
543
|
+
const file = {
|
|
544
|
+
path: manifestPath,
|
|
545
|
+
contentType,
|
|
546
|
+
sizeBytes: fileStat.size,
|
|
547
|
+
...checksumSha256 ? { checksumSha256 } : {},
|
|
548
|
+
getBody: () => (0, import_promises2.readFile)(path)
|
|
549
|
+
};
|
|
550
|
+
return buildStagedRequest([file], options);
|
|
551
|
+
}
|
|
552
|
+
async function folderStaged(path, options) {
|
|
553
|
+
const files = await collectPublishFiles(path, options);
|
|
554
|
+
const preparedFiles = await Promise.all(files.map(toPreparedFile));
|
|
555
|
+
return buildStagedRequest(preparedFiles, options);
|
|
556
|
+
}
|
|
557
|
+
async function resolveBundle(paths, options) {
|
|
558
|
+
const collected = [];
|
|
559
|
+
for (const element of paths) {
|
|
560
|
+
try {
|
|
561
|
+
await (0, import_promises2.stat)(element);
|
|
562
|
+
} catch {
|
|
563
|
+
throw new PublishInputError(
|
|
564
|
+
"file_not_found",
|
|
565
|
+
`No file or directory at "${element}".`,
|
|
566
|
+
element
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
collected.push(...await collectPublishFiles(element, options));
|
|
570
|
+
}
|
|
571
|
+
const preparedFiles = await Promise.all(collected.map(toPreparedFile));
|
|
572
|
+
return buildStagedRequest(preparedFiles, options);
|
|
573
|
+
}
|
|
574
|
+
async function toPreparedFile(pf) {
|
|
575
|
+
const checksumSha256 = pf.sizeBytes > SINGLE_PUT_CHECKSUM_THRESHOLD ? await sha256File(pf.absolutePath) : void 0;
|
|
576
|
+
return {
|
|
577
|
+
path: pf.path,
|
|
578
|
+
contentType: pf.contentType,
|
|
579
|
+
sizeBytes: pf.sizeBytes,
|
|
580
|
+
...checksumSha256 ? { checksumSha256 } : {},
|
|
581
|
+
getBody: () => (0, import_promises2.readFile)(pf.absolutePath)
|
|
582
|
+
};
|
|
502
583
|
}
|
|
503
584
|
|
|
504
585
|
// src/resources/account.ts
|
|
@@ -567,33 +648,6 @@ var DeploymentsResource = class {
|
|
|
567
648
|
this.transport = transport;
|
|
568
649
|
}
|
|
569
650
|
transport;
|
|
570
|
-
create(dropId, body, options = {}) {
|
|
571
|
-
const requestOptions = { body };
|
|
572
|
-
if (options.idempotencyKey)
|
|
573
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
574
|
-
if (options.ifRevision !== void 0)
|
|
575
|
-
requestOptions.ifRevision = options.ifRevision;
|
|
576
|
-
return this.transport.request(
|
|
577
|
-
"POST",
|
|
578
|
-
`/drops/${encodeURIComponent(dropId)}/deployments`,
|
|
579
|
-
requestOptions
|
|
580
|
-
);
|
|
581
|
-
}
|
|
582
|
-
createRaw(dropId, body, options = {}) {
|
|
583
|
-
const requestOptions = {
|
|
584
|
-
body,
|
|
585
|
-
bodyCase: "raw"
|
|
586
|
-
};
|
|
587
|
-
if (options.idempotencyKey)
|
|
588
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
589
|
-
if (options.ifRevision !== void 0)
|
|
590
|
-
requestOptions.ifRevision = options.ifRevision;
|
|
591
|
-
return this.transport.request(
|
|
592
|
-
"POST",
|
|
593
|
-
`/drops/${encodeURIComponent(dropId)}/deployments`,
|
|
594
|
-
requestOptions
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
651
|
list(dropId, params = {}) {
|
|
598
652
|
return this.transport.request(
|
|
599
653
|
"GET",
|
|
@@ -648,21 +702,6 @@ var DropsResource = class {
|
|
|
648
702
|
this.transport = transport;
|
|
649
703
|
}
|
|
650
704
|
transport;
|
|
651
|
-
create(body, options = {}) {
|
|
652
|
-
const requestOptions = { body };
|
|
653
|
-
if (options.idempotencyKey)
|
|
654
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
655
|
-
return this.transport.request("POST", "/drops", requestOptions);
|
|
656
|
-
}
|
|
657
|
-
createRaw(body, options = {}) {
|
|
658
|
-
const requestOptions = {
|
|
659
|
-
body,
|
|
660
|
-
bodyCase: "raw"
|
|
661
|
-
};
|
|
662
|
-
if (options.idempotencyKey)
|
|
663
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
664
|
-
return this.transport.request("POST", "/drops", requestOptions);
|
|
665
|
-
}
|
|
666
705
|
async list(params = {}) {
|
|
667
706
|
const result = await this.transport.request("GET", "/drops", {
|
|
668
707
|
params
|
|
@@ -703,15 +742,22 @@ var DropsResource = class {
|
|
|
703
742
|
);
|
|
704
743
|
}
|
|
705
744
|
};
|
|
745
|
+
var SETTINGS = [
|
|
746
|
+
"title",
|
|
747
|
+
"visibility",
|
|
748
|
+
"password",
|
|
749
|
+
"noindex",
|
|
750
|
+
"expiresAt",
|
|
751
|
+
"slug"
|
|
752
|
+
];
|
|
706
753
|
function updateBody(options) {
|
|
707
|
-
const {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
...
|
|
713
|
-
}
|
|
714
|
-
return { options: dropOptions, metadata };
|
|
754
|
+
const out = {};
|
|
755
|
+
for (const key of SETTINGS)
|
|
756
|
+
if (options[key] !== void 0) out[key] = options[key];
|
|
757
|
+
return {
|
|
758
|
+
options: out,
|
|
759
|
+
...options.metadata !== void 0 ? { metadata: options.metadata } : {}
|
|
760
|
+
};
|
|
715
761
|
}
|
|
716
762
|
|
|
717
763
|
// src/resources/uploads.ts
|
|
@@ -732,13 +778,6 @@ var UploadsResource = class {
|
|
|
732
778
|
`/uploads/${encodeURIComponent(uploadId)}`
|
|
733
779
|
);
|
|
734
780
|
}
|
|
735
|
-
createPartTargets(uploadId, body) {
|
|
736
|
-
return this.transport.request(
|
|
737
|
-
"POST",
|
|
738
|
-
`/uploads/${encodeURIComponent(uploadId)}/parts`,
|
|
739
|
-
{ body }
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
781
|
complete(uploadId, body, options = {}) {
|
|
743
782
|
const requestOptions = { body };
|
|
744
783
|
if (options.idempotencyKey)
|
|
@@ -792,25 +831,24 @@ function toSnakeCase(value) {
|
|
|
792
831
|
|
|
793
832
|
// src/transport.ts
|
|
794
833
|
var DEFAULT_BASE_URL = "https://api.dropthis.app";
|
|
795
|
-
var SDK_VERSION = "0.
|
|
834
|
+
var SDK_VERSION = "0.6.0";
|
|
796
835
|
var Transport = class {
|
|
797
836
|
apiKey;
|
|
798
837
|
baseUrl;
|
|
799
838
|
timeoutMs;
|
|
839
|
+
uploadTimeoutMs;
|
|
800
840
|
fetchImpl;
|
|
801
841
|
constructor(options = {}) {
|
|
802
842
|
const resolved = typeof options === "string" ? { apiKey: options } : options;
|
|
803
|
-
this.apiKey = resolved.apiKey ?? process.env
|
|
843
|
+
this.apiKey = resolved.apiKey ?? (typeof process !== "undefined" ? process.env?.DROPTHIS_API_KEY : void 0);
|
|
804
844
|
this.baseUrl = (resolved.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
805
845
|
this.timeoutMs = resolved.timeoutMs ?? 3e4;
|
|
846
|
+
this.uploadTimeoutMs = resolved.uploadTimeoutMs ?? 12e4;
|
|
806
847
|
this.fetchImpl = resolved.fetch ?? globalThis.fetch;
|
|
807
848
|
}
|
|
808
|
-
multipart(method, path, form, options = {}) {
|
|
809
|
-
return this.request(method, path, { ...options, body: form });
|
|
810
|
-
}
|
|
811
849
|
async putSignedUrl(url, body, headers) {
|
|
812
850
|
const controller = new AbortController();
|
|
813
|
-
const timeout = setTimeout(() => controller.abort(), this.
|
|
851
|
+
const timeout = setTimeout(() => controller.abort(), this.uploadTimeoutMs);
|
|
814
852
|
try {
|
|
815
853
|
const request = {
|
|
816
854
|
method: "PUT",
|
|
@@ -865,7 +903,7 @@ var Transport = class {
|
|
|
865
903
|
if (options.idempotencyKey)
|
|
866
904
|
headers["idempotency-key"] = options.idempotencyKey;
|
|
867
905
|
if (options.ifRevision !== void 0)
|
|
868
|
-
headers["
|
|
906
|
+
headers["if-revision"] = String(options.ifRevision);
|
|
869
907
|
if (options.body !== void 0 && !(options.body instanceof FormData))
|
|
870
908
|
headers["content-type"] = "application/json";
|
|
871
909
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
@@ -897,11 +935,18 @@ var Transport = class {
|
|
|
897
935
|
const parsed = parseJson(text);
|
|
898
936
|
if (!response.ok) {
|
|
899
937
|
const body = parsed && typeof parsed === "object" ? parsed : {};
|
|
900
|
-
const message = stringValue(body.detail) ?? stringValue(body.
|
|
938
|
+
const message = stringValue(body.detail) ?? stringValue(body.title) ?? response.statusText;
|
|
901
939
|
const code = stringValue(body.code) ?? stringValue(body.error_code) ?? `http_${response.status}`;
|
|
902
940
|
const currentRevision = numberValue(body.current_revision);
|
|
941
|
+
const type = stringValue(body.type);
|
|
942
|
+
const title = stringValue(body.title);
|
|
943
|
+
const instance = stringValue(body.instance);
|
|
903
944
|
return createErrorResult(code, message, response.status, {
|
|
904
|
-
|
|
945
|
+
body,
|
|
946
|
+
...type !== null ? { type } : {},
|
|
947
|
+
...title !== null ? { title } : {},
|
|
948
|
+
...instance !== null ? { instance } : {},
|
|
949
|
+
detail: stringValue(body.detail),
|
|
905
950
|
param: stringValue(body.param),
|
|
906
951
|
...currentRevision !== void 0 ? { currentRevision } : {},
|
|
907
952
|
requestId: stringValue(body.request_id) ?? responseHeaders["x-request-id"] ?? null,
|
|
@@ -995,35 +1040,37 @@ var Dropthis = class {
|
|
|
995
1040
|
return this.uploadsResource;
|
|
996
1041
|
}
|
|
997
1042
|
async prepare(input, options = {}) {
|
|
998
|
-
return
|
|
1043
|
+
return resolveInput(input, options);
|
|
999
1044
|
}
|
|
1000
1045
|
async publish(input, options = {}) {
|
|
1001
|
-
|
|
1002
|
-
|
|
1046
|
+
let prepared;
|
|
1047
|
+
try {
|
|
1048
|
+
prepared = await resolveInput(input, options);
|
|
1049
|
+
} catch (e) {
|
|
1050
|
+
return toErrorResult(e);
|
|
1051
|
+
}
|
|
1052
|
+
return prepared.kind === "source" ? publishSource(this.transport, prepared, "/drops", options) : publishStaged(this.transport, prepared, "/drops", options);
|
|
1003
1053
|
}
|
|
1004
1054
|
async deploy(dropId, input, options = {}) {
|
|
1005
|
-
|
|
1055
|
+
let prepared;
|
|
1056
|
+
try {
|
|
1057
|
+
prepared = await resolveInput(input, options);
|
|
1058
|
+
} catch (e) {
|
|
1059
|
+
return toErrorResult(e);
|
|
1060
|
+
}
|
|
1006
1061
|
const path = `/drops/${encodeURIComponent(dropId)}/deployments`;
|
|
1007
|
-
return publishStaged(this.transport, prepared, path, options);
|
|
1062
|
+
return prepared.kind === "source" ? publishSource(this.transport, prepared, path, options) : publishStaged(this.transport, prepared, path, options);
|
|
1008
1063
|
}
|
|
1009
1064
|
async update(dropId, options = {}) {
|
|
1010
1065
|
return this.drops.update(dropId, options);
|
|
1011
1066
|
}
|
|
1012
|
-
request(method, path, options = {}) {
|
|
1013
|
-
return this.transport.request(method, path, {
|
|
1014
|
-
...options,
|
|
1015
|
-
bodyCase: "raw"
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
requestSignedUpload(url, bytes, headers) {
|
|
1019
|
-
return this.transport.putSignedUrl(url, bytes, headers);
|
|
1020
|
-
}
|
|
1021
1067
|
};
|
|
1022
1068
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1023
1069
|
0 && (module.exports = {
|
|
1024
1070
|
CursorPage,
|
|
1025
1071
|
DeploymentsResource,
|
|
1026
1072
|
Dropthis,
|
|
1073
|
+
PublishInputError,
|
|
1027
1074
|
UploadsResource,
|
|
1028
1075
|
createErrorResult,
|
|
1029
1076
|
redactSecrets
|