@dropthis/cli 0.5.0 → 0.6.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/README.md +0 -1
- package/dist/cli.cjs +330 -346
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +88 -20
- package/node_modules/@dropthis/node/dist/{drops-fK63OCk6.d.cts → drops-BPdmUPCT.d.cts} +65 -56
- package/node_modules/@dropthis/node/dist/{drops-fK63OCk6.d.ts → drops-BPdmUPCT.d.ts} +65 -56
- package/node_modules/@dropthis/node/dist/edge.cjs +389 -168
- package/node_modules/@dropthis/node/dist/edge.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.cts +4 -32
- package/node_modules/@dropthis/node/dist/edge.d.ts +4 -32
- package/node_modules/@dropthis/node/dist/edge.mjs +389 -168
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +449 -429
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +13 -39
- package/node_modules/@dropthis/node/dist/index.d.ts +13 -39
- package/node_modules/@dropthis/node/dist/index.mjs +448 -429
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/package.json +1 -1
- package/package.json +2 -2
|
@@ -33,6 +33,7 @@ __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
|
|
@@ -52,33 +53,42 @@ function createErrorResult(code, message, statusCode, extra = {}) {
|
|
|
52
53
|
message: redactSecrets(message),
|
|
53
54
|
statusCode,
|
|
54
55
|
...extra.type ? { type: extra.type } : {},
|
|
56
|
+
...extra.title !== void 0 ? { title: extra.title } : {},
|
|
55
57
|
...extra.detail !== void 0 ? { detail: extra.detail } : {},
|
|
58
|
+
...extra.instance !== void 0 ? { instance: extra.instance } : {},
|
|
56
59
|
...extra.param !== void 0 ? { param: extra.param } : {},
|
|
57
60
|
...extra.currentRevision !== void 0 ? { currentRevision: extra.currentRevision } : {},
|
|
58
61
|
...extra.requestId !== void 0 ? { requestId: extra.requestId } : {},
|
|
59
62
|
...extra.suggestion !== void 0 ? { suggestion: extra.suggestion } : {},
|
|
60
|
-
...extra.retryable !== void 0 ? { retryable: extra.retryable } : {}
|
|
63
|
+
...extra.retryable !== void 0 ? { retryable: extra.retryable } : {},
|
|
64
|
+
...extra.body !== void 0 ? { body: extra.body } : {}
|
|
61
65
|
},
|
|
62
66
|
headers: extra.headers ?? {}
|
|
63
67
|
};
|
|
64
68
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
+
);
|
|
82
92
|
}
|
|
83
93
|
|
|
84
94
|
// src/publish/detect.ts
|
|
@@ -90,253 +100,100 @@ function isHttpUrl(value) {
|
|
|
90
100
|
return false;
|
|
91
101
|
}
|
|
92
102
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
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);
|
|
96
105
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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";
|
|
103
118
|
}
|
|
104
119
|
function detectBytesContentType(bytes) {
|
|
105
|
-
const text =
|
|
120
|
+
const text = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
106
121
|
if (text.includes("\uFFFD")) return "application/octet-stream";
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// src/publish/files.ts
|
|
111
|
-
var import_promises = require("fs/promises");
|
|
112
|
-
var import_node_path = require("path");
|
|
113
|
-
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
114
|
-
var import_ignore = __toESM(require("ignore"), 1);
|
|
115
|
-
var import_mime_types = require("mime-types");
|
|
116
|
-
var DEFAULT_IGNORES = [
|
|
117
|
-
".git",
|
|
118
|
-
".git/**",
|
|
119
|
-
"node_modules",
|
|
120
|
-
"node_modules/**",
|
|
121
|
-
".DS_Store",
|
|
122
|
-
".env",
|
|
123
|
-
".env.*",
|
|
124
|
-
".cache",
|
|
125
|
-
".cache/**",
|
|
126
|
-
".tmp",
|
|
127
|
-
".tmp/**",
|
|
128
|
-
"dist/.cache",
|
|
129
|
-
"dist/.cache/**"
|
|
130
|
-
];
|
|
131
|
-
async function collectPublishFiles(inputPath, options = {}) {
|
|
132
|
-
const inputStat = await (0, import_promises.stat)(inputPath);
|
|
133
|
-
if (inputStat.isFile()) {
|
|
134
|
-
return [
|
|
135
|
-
{
|
|
136
|
-
absolutePath: inputPath,
|
|
137
|
-
path: (0, import_node_path.basename)(inputPath),
|
|
138
|
-
contentType: await detectPathContentType(inputPath),
|
|
139
|
-
sizeBytes: inputStat.size
|
|
140
|
-
}
|
|
141
|
-
];
|
|
142
|
-
}
|
|
143
|
-
if (!inputStat.isDirectory()) {
|
|
144
|
-
throw new Error(`Input is not a file or directory: ${inputPath}`);
|
|
145
|
-
}
|
|
146
|
-
const matcher = (0, import_ignore.default)().add([
|
|
147
|
-
...options.ignoreDefaults === false ? [] : DEFAULT_IGNORES,
|
|
148
|
-
...options.ignore ?? []
|
|
149
|
-
]);
|
|
150
|
-
const entries = await (0, import_fast_glob.default)("**/*", {
|
|
151
|
-
cwd: inputPath,
|
|
152
|
-
onlyFiles: true,
|
|
153
|
-
followSymbolicLinks: false,
|
|
154
|
-
dot: true,
|
|
155
|
-
unique: true
|
|
156
|
-
});
|
|
157
|
-
const paths = entries.map((entry) => entry.split(import_node_path.sep).join("/")).filter((entry) => !matcher.ignores(entry)).sort((a, b) => a.localeCompare(b));
|
|
158
|
-
return Promise.all(
|
|
159
|
-
paths.map(async (path) => {
|
|
160
|
-
const absolutePath = `${inputPath}/${path}`;
|
|
161
|
-
const fileStat = await (0, import_promises.stat)(absolutePath);
|
|
162
|
-
return {
|
|
163
|
-
absolutePath,
|
|
164
|
-
path,
|
|
165
|
-
contentType: await detectPathContentType(absolutePath),
|
|
166
|
-
sizeBytes: fileStat.size
|
|
167
|
-
};
|
|
168
|
-
})
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
async function detectPathContentType(path) {
|
|
172
|
-
const detected = (0, import_mime_types.lookup)(path);
|
|
173
|
-
if (detected) return detected;
|
|
174
|
-
return detectBytesContentType(await (0, import_promises.readFile)(path));
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// src/publish/prepare.ts
|
|
178
|
-
var SINGLE_PUT_CHECKSUM_THRESHOLD_BYTES = 10 * 1024 * 1024;
|
|
179
|
-
async function preparePublishRequest(input, options = {}) {
|
|
180
|
-
if (input instanceof URL) {
|
|
181
|
-
return sourceRequest(input.toString(), options);
|
|
182
|
-
}
|
|
183
|
-
if (typeof input === "string") {
|
|
184
|
-
const local = await localKind(input);
|
|
185
|
-
if (local === "file") {
|
|
186
|
-
return fileStaged(input, options);
|
|
187
|
-
}
|
|
188
|
-
if (local === "directory") {
|
|
189
|
-
return folderStaged(input, options);
|
|
190
|
-
}
|
|
191
|
-
const detection = detectStringInput(input);
|
|
192
|
-
if (detection.mode === "sourceUrl") return sourceRequest(input, options);
|
|
193
|
-
return stringContent(input, options, detection.contentType);
|
|
194
|
-
}
|
|
195
|
-
if (input instanceof Uint8Array || Buffer.isBuffer(input)) {
|
|
196
|
-
return bytesStaged(input, options);
|
|
197
|
-
}
|
|
198
|
-
return explicitInput(input, options);
|
|
199
|
-
}
|
|
200
|
-
async function stringContent(content, options, detectedContentType) {
|
|
201
|
-
const contentType = options.contentType ?? detectedContentType;
|
|
202
|
-
return bytesStaged(Buffer.from(content), {
|
|
203
|
-
...options,
|
|
204
|
-
path: options.path ?? entryForContentType(contentType),
|
|
205
|
-
contentType
|
|
206
|
-
});
|
|
122
|
+
return containsHtmlTag(text) ? "text/html" : "text/plain; charset=utf-8";
|
|
207
123
|
}
|
|
208
124
|
function entryForContentType(contentType) {
|
|
209
|
-
const
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
if (
|
|
213
|
-
if (
|
|
214
|
-
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")
|
|
215
130
|
return "index.js";
|
|
216
|
-
if (
|
|
131
|
+
if (m.startsWith("text/")) return "index.txt";
|
|
217
132
|
return "index";
|
|
218
133
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (info.isDirectory()) return "directory";
|
|
224
|
-
return "none";
|
|
225
|
-
} catch {
|
|
226
|
-
return "none";
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
async function fileStaged(path, options) {
|
|
230
|
-
const fileStat = await (0, import_promises2.stat)(path);
|
|
231
|
-
const manifestPath = options.path ?? (0, import_node_path2.basename)(path);
|
|
232
|
-
return stagedRequest(
|
|
233
|
-
[
|
|
234
|
-
{
|
|
235
|
-
path: manifestPath,
|
|
236
|
-
contentType: options.contentType ?? await detectPathContentType(path),
|
|
237
|
-
sizeBytes: fileStat.size,
|
|
238
|
-
source: { kind: "path", path }
|
|
239
|
-
}
|
|
240
|
-
],
|
|
241
|
-
{ ...options, entry: options.entry ?? manifestPath }
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
async function folderStaged(path, options) {
|
|
245
|
-
const files = (await collectPublishFiles(path, options)).map((file) => ({
|
|
246
|
-
path: file.path,
|
|
247
|
-
contentType: file.contentType,
|
|
248
|
-
sizeBytes: file.sizeBytes,
|
|
249
|
-
source: { kind: "path", path: file.absolutePath }
|
|
250
|
-
}));
|
|
251
|
-
return stagedRequest(files, options);
|
|
252
|
-
}
|
|
253
|
-
async function bytesStaged(bytes, options) {
|
|
254
|
-
return stagedRequest(
|
|
255
|
-
[
|
|
256
|
-
{
|
|
257
|
-
path: options.path ?? "index",
|
|
258
|
-
contentType: options.contentType ?? detectBytesContentType(bytes),
|
|
259
|
-
sizeBytes: bytes.byteLength,
|
|
260
|
-
source: { kind: "bytes", bytes }
|
|
261
|
-
}
|
|
262
|
-
],
|
|
263
|
-
options
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
async function stagedRequest(files, options) {
|
|
267
|
-
const preparedFiles = await Promise.all(
|
|
268
|
-
files.map(async (file) => {
|
|
269
|
-
if (file.sizeBytes <= SINGLE_PUT_CHECKSUM_THRESHOLD_BYTES) return file;
|
|
270
|
-
const checksumSha256 = file.source.kind === "bytes" ? sha256Bytes(file.source.bytes) : await sha256File(file.source.path);
|
|
271
|
-
return { ...file, checksumSha256 };
|
|
272
|
-
})
|
|
273
|
-
);
|
|
274
|
-
const manifestFiles = preparedFiles.map((file) => ({
|
|
275
|
-
path: file.path,
|
|
276
|
-
contentType: file.contentType,
|
|
277
|
-
sizeBytes: file.sizeBytes,
|
|
278
|
-
...file.checksumSha256 ? { checksumSha256: file.checksumSha256 } : {}
|
|
279
|
-
}));
|
|
280
|
-
const prepared = {
|
|
281
|
-
kind: "staged",
|
|
282
|
-
manifest: {
|
|
283
|
-
schemaVersion: 1,
|
|
284
|
-
files: manifestFiles,
|
|
285
|
-
...options.entry ? { entry: options.entry } : {}
|
|
286
|
-
},
|
|
287
|
-
files: preparedFiles,
|
|
288
|
-
options: optionsBody(options)
|
|
289
|
-
};
|
|
290
|
-
if (options.metadata) prepared.metadata = options.metadata;
|
|
291
|
-
return prepared;
|
|
134
|
+
|
|
135
|
+
// src/publish/paths.ts
|
|
136
|
+
function normalizeManifestPath(path) {
|
|
137
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
292
138
|
}
|
|
293
|
-
function
|
|
294
|
-
if (
|
|
295
|
-
throw new
|
|
296
|
-
"
|
|
139
|
+
function assertValidManifestPath(path) {
|
|
140
|
+
if (path.includes("\\"))
|
|
141
|
+
throw new PublishInputError(
|
|
142
|
+
"invalid_path",
|
|
143
|
+
`Manifest path must use "/": "${path}".`,
|
|
144
|
+
path
|
|
297
145
|
);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (options.metadata) prepared.metadata = options.metadata;
|
|
305
|
-
return prepared;
|
|
306
|
-
}
|
|
307
|
-
async function explicitInput(input, options) {
|
|
308
|
-
if ("content" in input)
|
|
309
|
-
return stringContent(
|
|
310
|
-
input.content,
|
|
311
|
-
{ ...options, ...input },
|
|
312
|
-
input.contentType ?? options.contentType ?? "text/html"
|
|
146
|
+
const p = normalizeManifestPath(path);
|
|
147
|
+
if (p === "")
|
|
148
|
+
throw new PublishInputError(
|
|
149
|
+
"invalid_path",
|
|
150
|
+
"Manifest path must not be empty.",
|
|
151
|
+
path
|
|
313
152
|
);
|
|
314
|
-
if ("
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
|
319
170
|
);
|
|
320
|
-
return stagedRequest(
|
|
321
|
-
input.files.map((file) => {
|
|
322
|
-
const bytes = explicitFileBytes(file);
|
|
323
|
-
return {
|
|
324
|
-
path: file.path,
|
|
325
|
-
contentType: file.contentType,
|
|
326
|
-
sizeBytes: bytes.byteLength,
|
|
327
|
-
source: { kind: "bytes", bytes }
|
|
328
|
-
};
|
|
329
|
-
}),
|
|
330
|
-
{ ...options, ...input }
|
|
331
|
-
);
|
|
332
171
|
}
|
|
333
|
-
function
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
+
}
|
|
339
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
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/publish/core.ts
|
|
340
197
|
var VALID_VISIBILITIES = ["public", "unlisted"];
|
|
341
198
|
var MAX_TITLE_LENGTH = 500;
|
|
342
199
|
function validatePublishOptions(options) {
|
|
@@ -373,69 +230,125 @@ function optionsBody(options) {
|
|
|
373
230
|
expiresAt: options.expiresAt instanceof Date ? options.expiresAt.toISOString() : options.expiresAt
|
|
374
231
|
};
|
|
375
232
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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)
|
|
255
|
+
};
|
|
256
|
+
if (options.metadata) prepared.metadata = options.metadata;
|
|
257
|
+
return prepared;
|
|
258
|
+
}
|
|
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."
|
|
389
266
|
);
|
|
390
267
|
}
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
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."
|
|
394
289
|
);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
{ body: { fileId, partNumbers: partNumberBatch } }
|
|
405
|
-
);
|
|
406
|
-
if (targetsResult.error) return errorResult(targetsResult);
|
|
407
|
-
for (const target of targetsResult.data.parts) {
|
|
408
|
-
const start = (target.partNumber - 1) * partSize;
|
|
409
|
-
const end = Math.min(start + partSize, bytes.byteLength);
|
|
410
|
-
const uploadResult = await transport.putSignedUrl(
|
|
411
|
-
target.url,
|
|
412
|
-
bytes.slice(start, end),
|
|
413
|
-
target.headers
|
|
414
|
-
);
|
|
415
|
-
if (uploadResult.error) return errorResult(uploadResult);
|
|
416
|
-
if (!uploadResult.data.etag) {
|
|
417
|
-
return createErrorResult(
|
|
418
|
-
"missing_upload_etag",
|
|
419
|
-
"Signed upload response did not include an ETag.",
|
|
420
|
-
null
|
|
421
|
-
);
|
|
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
|
|
422
299
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
300
|
+
],
|
|
301
|
+
options
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
async function resolveInMemory(input, options = {}) {
|
|
305
|
+
if (input instanceof URL) {
|
|
306
|
+
return buildSourceRequest(input.toString(), options);
|
|
428
307
|
}
|
|
429
|
-
|
|
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);
|
|
430
345
|
}
|
|
431
346
|
function errorResult(result) {
|
|
432
347
|
if (!result.error) throw new Error("Expected an error result");
|
|
433
348
|
return { data: null, error: result.error, headers: result.headers };
|
|
434
349
|
}
|
|
435
|
-
|
|
436
|
-
// src/publish/upload.ts
|
|
437
350
|
async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
438
|
-
const baseKey = options.idempotencyKey ?? `sdk-${
|
|
351
|
+
const baseKey = options.idempotencyKey ?? `sdk-${crypto.randomUUID()}`;
|
|
439
352
|
const createResult = await transport.request(
|
|
440
353
|
"POST",
|
|
441
354
|
"/uploads",
|
|
@@ -444,12 +357,9 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
444
357
|
idempotencyKey: `${baseKey}:create-upload`
|
|
445
358
|
}
|
|
446
359
|
);
|
|
447
|
-
if (createResult.error) return
|
|
448
|
-
const completedFiles = {};
|
|
360
|
+
if (createResult.error) return errorResult(createResult);
|
|
449
361
|
for (const file of prepared.files) {
|
|
450
|
-
const target = createResult.data.files.find(
|
|
451
|
-
(candidate) => candidate.path === file.path
|
|
452
|
-
);
|
|
362
|
+
const target = createResult.data.files.find((f) => f.path === file.path);
|
|
453
363
|
if (!target) {
|
|
454
364
|
return createErrorResult(
|
|
455
365
|
"upload_target_missing",
|
|
@@ -457,36 +367,29 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
457
367
|
null
|
|
458
368
|
);
|
|
459
369
|
}
|
|
460
|
-
if (target.upload.strategy
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
target.fileId,
|
|
466
|
-
bytes2,
|
|
467
|
-
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
|
|
468
375
|
);
|
|
469
|
-
if (partsResult.error) return errorResult2(partsResult);
|
|
470
|
-
completedFiles[target.fileId] = { parts: partsResult.data };
|
|
471
|
-
continue;
|
|
472
376
|
}
|
|
473
|
-
const
|
|
474
|
-
const uploadResult = await transport.putSignedUrl(
|
|
377
|
+
const put = await transport.putSignedUrl(
|
|
475
378
|
target.upload.url,
|
|
476
|
-
|
|
379
|
+
await file.getBody(),
|
|
477
380
|
target.upload.headers
|
|
478
381
|
);
|
|
479
|
-
if (
|
|
382
|
+
if (put.error) return errorResult(put);
|
|
480
383
|
}
|
|
481
384
|
const completeResult = await transport.request(
|
|
482
385
|
"POST",
|
|
483
386
|
`/uploads/${encodeURIComponent(createResult.data.uploadId)}/complete`,
|
|
484
387
|
{
|
|
485
|
-
body: { files:
|
|
388
|
+
body: { files: {} },
|
|
486
389
|
idempotencyKey: `${baseKey}:complete-upload`
|
|
487
390
|
}
|
|
488
391
|
);
|
|
489
|
-
if (completeResult.error) return
|
|
392
|
+
if (completeResult.error) return errorResult(completeResult);
|
|
490
393
|
const finalOptions = {
|
|
491
394
|
body: {
|
|
492
395
|
uploadId: createResult.data.uploadId,
|
|
@@ -499,13 +402,184 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
499
402
|
finalOptions.ifRevision = options.ifRevision;
|
|
500
403
|
return transport.request("POST", finalPath, finalOptions);
|
|
501
404
|
}
|
|
502
|
-
async function
|
|
503
|
-
|
|
504
|
-
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
|
+
});
|
|
416
|
+
}
|
|
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");
|
|
505
431
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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
|
+
};
|
|
509
583
|
}
|
|
510
584
|
|
|
511
585
|
// src/resources/account.ts
|
|
@@ -574,33 +648,6 @@ var DeploymentsResource = class {
|
|
|
574
648
|
this.transport = transport;
|
|
575
649
|
}
|
|
576
650
|
transport;
|
|
577
|
-
create(dropId, body, options = {}) {
|
|
578
|
-
const requestOptions = { body };
|
|
579
|
-
if (options.idempotencyKey)
|
|
580
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
581
|
-
if (options.ifRevision !== void 0)
|
|
582
|
-
requestOptions.ifRevision = options.ifRevision;
|
|
583
|
-
return this.transport.request(
|
|
584
|
-
"POST",
|
|
585
|
-
`/drops/${encodeURIComponent(dropId)}/deployments`,
|
|
586
|
-
requestOptions
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
createRaw(dropId, body, options = {}) {
|
|
590
|
-
const requestOptions = {
|
|
591
|
-
body,
|
|
592
|
-
bodyCase: "raw"
|
|
593
|
-
};
|
|
594
|
-
if (options.idempotencyKey)
|
|
595
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
596
|
-
if (options.ifRevision !== void 0)
|
|
597
|
-
requestOptions.ifRevision = options.ifRevision;
|
|
598
|
-
return this.transport.request(
|
|
599
|
-
"POST",
|
|
600
|
-
`/drops/${encodeURIComponent(dropId)}/deployments`,
|
|
601
|
-
requestOptions
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
651
|
list(dropId, params = {}) {
|
|
605
652
|
return this.transport.request(
|
|
606
653
|
"GET",
|
|
@@ -655,21 +702,6 @@ var DropsResource = class {
|
|
|
655
702
|
this.transport = transport;
|
|
656
703
|
}
|
|
657
704
|
transport;
|
|
658
|
-
create(body, options = {}) {
|
|
659
|
-
const requestOptions = { body };
|
|
660
|
-
if (options.idempotencyKey)
|
|
661
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
662
|
-
return this.transport.request("POST", "/drops", requestOptions);
|
|
663
|
-
}
|
|
664
|
-
createRaw(body, options = {}) {
|
|
665
|
-
const requestOptions = {
|
|
666
|
-
body,
|
|
667
|
-
bodyCase: "raw"
|
|
668
|
-
};
|
|
669
|
-
if (options.idempotencyKey)
|
|
670
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
671
|
-
return this.transport.request("POST", "/drops", requestOptions);
|
|
672
|
-
}
|
|
673
705
|
async list(params = {}) {
|
|
674
706
|
const result = await this.transport.request("GET", "/drops", {
|
|
675
707
|
params
|
|
@@ -710,15 +742,22 @@ var DropsResource = class {
|
|
|
710
742
|
);
|
|
711
743
|
}
|
|
712
744
|
};
|
|
745
|
+
var SETTINGS = [
|
|
746
|
+
"title",
|
|
747
|
+
"visibility",
|
|
748
|
+
"password",
|
|
749
|
+
"noindex",
|
|
750
|
+
"expiresAt",
|
|
751
|
+
"slug"
|
|
752
|
+
];
|
|
713
753
|
function updateBody(options) {
|
|
714
|
-
const {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
...
|
|
720
|
-
}
|
|
721
|
-
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
|
+
};
|
|
722
761
|
}
|
|
723
762
|
|
|
724
763
|
// src/resources/uploads.ts
|
|
@@ -739,13 +778,6 @@ var UploadsResource = class {
|
|
|
739
778
|
`/uploads/${encodeURIComponent(uploadId)}`
|
|
740
779
|
);
|
|
741
780
|
}
|
|
742
|
-
createPartTargets(uploadId, body) {
|
|
743
|
-
return this.transport.request(
|
|
744
|
-
"POST",
|
|
745
|
-
`/uploads/${encodeURIComponent(uploadId)}/parts`,
|
|
746
|
-
{ body }
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
781
|
complete(uploadId, body, options = {}) {
|
|
750
782
|
const requestOptions = { body };
|
|
751
783
|
if (options.idempotencyKey)
|
|
@@ -799,25 +831,24 @@ function toSnakeCase(value) {
|
|
|
799
831
|
|
|
800
832
|
// src/transport.ts
|
|
801
833
|
var DEFAULT_BASE_URL = "https://api.dropthis.app";
|
|
802
|
-
var SDK_VERSION = "0.
|
|
834
|
+
var SDK_VERSION = "0.6.0";
|
|
803
835
|
var Transport = class {
|
|
804
836
|
apiKey;
|
|
805
837
|
baseUrl;
|
|
806
838
|
timeoutMs;
|
|
839
|
+
uploadTimeoutMs;
|
|
807
840
|
fetchImpl;
|
|
808
841
|
constructor(options = {}) {
|
|
809
842
|
const resolved = typeof options === "string" ? { apiKey: options } : options;
|
|
810
843
|
this.apiKey = resolved.apiKey ?? (typeof process !== "undefined" ? process.env?.DROPTHIS_API_KEY : void 0);
|
|
811
844
|
this.baseUrl = (resolved.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
812
845
|
this.timeoutMs = resolved.timeoutMs ?? 3e4;
|
|
846
|
+
this.uploadTimeoutMs = resolved.uploadTimeoutMs ?? 12e4;
|
|
813
847
|
this.fetchImpl = resolved.fetch ?? globalThis.fetch;
|
|
814
848
|
}
|
|
815
|
-
multipart(method, path, form, options = {}) {
|
|
816
|
-
return this.request(method, path, { ...options, body: form });
|
|
817
|
-
}
|
|
818
849
|
async putSignedUrl(url, body, headers) {
|
|
819
850
|
const controller = new AbortController();
|
|
820
|
-
const timeout = setTimeout(() => controller.abort(), this.
|
|
851
|
+
const timeout = setTimeout(() => controller.abort(), this.uploadTimeoutMs);
|
|
821
852
|
try {
|
|
822
853
|
const request = {
|
|
823
854
|
method: "PUT",
|
|
@@ -872,7 +903,7 @@ var Transport = class {
|
|
|
872
903
|
if (options.idempotencyKey)
|
|
873
904
|
headers["idempotency-key"] = options.idempotencyKey;
|
|
874
905
|
if (options.ifRevision !== void 0)
|
|
875
|
-
headers["
|
|
906
|
+
headers["if-revision"] = String(options.ifRevision);
|
|
876
907
|
if (options.body !== void 0 && !(options.body instanceof FormData))
|
|
877
908
|
headers["content-type"] = "application/json";
|
|
878
909
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
@@ -904,11 +935,18 @@ var Transport = class {
|
|
|
904
935
|
const parsed = parseJson(text);
|
|
905
936
|
if (!response.ok) {
|
|
906
937
|
const body = parsed && typeof parsed === "object" ? parsed : {};
|
|
907
|
-
const message = stringValue(body.detail) ?? stringValue(body.
|
|
938
|
+
const message = stringValue(body.detail) ?? stringValue(body.title) ?? response.statusText;
|
|
908
939
|
const code = stringValue(body.code) ?? stringValue(body.error_code) ?? `http_${response.status}`;
|
|
909
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);
|
|
910
944
|
return createErrorResult(code, message, response.status, {
|
|
911
|
-
|
|
945
|
+
body,
|
|
946
|
+
...type !== null ? { type } : {},
|
|
947
|
+
...title !== null ? { title } : {},
|
|
948
|
+
...instance !== null ? { instance } : {},
|
|
949
|
+
detail: stringValue(body.detail),
|
|
912
950
|
param: stringValue(body.param),
|
|
913
951
|
...currentRevision !== void 0 ? { currentRevision } : {},
|
|
914
952
|
requestId: stringValue(body.request_id) ?? responseHeaders["x-request-id"] ?? null,
|
|
@@ -1002,55 +1040,37 @@ var Dropthis = class {
|
|
|
1002
1040
|
return this.uploadsResource;
|
|
1003
1041
|
}
|
|
1004
1042
|
async prepare(input, options = {}) {
|
|
1005
|
-
return
|
|
1043
|
+
return resolveInput(input, options);
|
|
1006
1044
|
}
|
|
1007
1045
|
async publish(input, options = {}) {
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
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);
|
|
1012
1053
|
}
|
|
1013
1054
|
async deploy(dropId, input, options = {}) {
|
|
1014
|
-
|
|
1055
|
+
let prepared;
|
|
1056
|
+
try {
|
|
1057
|
+
prepared = await resolveInput(input, options);
|
|
1058
|
+
} catch (e) {
|
|
1059
|
+
return toErrorResult(e);
|
|
1060
|
+
}
|
|
1015
1061
|
const path = `/drops/${encodeURIComponent(dropId)}/deployments`;
|
|
1016
|
-
|
|
1017
|
-
return createErrorResult(
|
|
1018
|
-
"source_url_unsupported_for_deployment",
|
|
1019
|
-
"Publishing a deployment from a source_url is not supported yet. Fetch the content first, then pass it as a string or file.",
|
|
1020
|
-
null
|
|
1021
|
-
);
|
|
1022
|
-
return publishStaged(this.transport, prepared, path, options);
|
|
1023
|
-
}
|
|
1024
|
-
publishSource(prepared, path, options) {
|
|
1025
|
-
const body = {
|
|
1026
|
-
sourceUrl: prepared.sourceUrl,
|
|
1027
|
-
options: prepared.options
|
|
1028
|
-
};
|
|
1029
|
-
if (prepared.metadata) body.metadata = prepared.metadata;
|
|
1030
|
-
const baseKey = options.idempotencyKey ?? `sdk-${crypto.randomUUID()}`;
|
|
1031
|
-
return this.transport.request("POST", path, {
|
|
1032
|
-
body,
|
|
1033
|
-
idempotencyKey: `${baseKey}:publish`
|
|
1034
|
-
});
|
|
1062
|
+
return prepared.kind === "source" ? publishSource(this.transport, prepared, path, options) : publishStaged(this.transport, prepared, path, options);
|
|
1035
1063
|
}
|
|
1036
1064
|
async update(dropId, options = {}) {
|
|
1037
1065
|
return this.drops.update(dropId, options);
|
|
1038
1066
|
}
|
|
1039
|
-
request(method, path, options = {}) {
|
|
1040
|
-
return this.transport.request(method, path, {
|
|
1041
|
-
...options,
|
|
1042
|
-
bodyCase: "raw"
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
requestSignedUpload(url, bytes, headers) {
|
|
1046
|
-
return this.transport.putSignedUrl(url, bytes, headers);
|
|
1047
|
-
}
|
|
1048
1067
|
};
|
|
1049
1068
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1050
1069
|
0 && (module.exports = {
|
|
1051
1070
|
CursorPage,
|
|
1052
1071
|
DeploymentsResource,
|
|
1053
1072
|
Dropthis,
|
|
1073
|
+
PublishInputError,
|
|
1054
1074
|
UploadsResource,
|
|
1055
1075
|
createErrorResult,
|
|
1056
1076
|
redactSecrets
|