@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
|
@@ -1,19 +1,52 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// src/publish/checksum.ts
|
|
6
|
-
import { createHash } from "crypto";
|
|
7
|
-
import { createReadStream } from "fs";
|
|
8
|
-
function sha256Bytes(bytes) {
|
|
9
|
-
return createHash("sha256").update(bytes).digest("hex");
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var API_KEY_RE = /sk_[A-Za-z0-9_-]+/g;
|
|
3
|
+
function redactSecrets(message) {
|
|
4
|
+
return message.replace(API_KEY_RE, "sk_[redacted]");
|
|
10
5
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
function createErrorResult(code, message, statusCode, extra = {}) {
|
|
7
|
+
return {
|
|
8
|
+
data: null,
|
|
9
|
+
error: {
|
|
10
|
+
code,
|
|
11
|
+
message: redactSecrets(message),
|
|
12
|
+
statusCode,
|
|
13
|
+
...extra.type ? { type: extra.type } : {},
|
|
14
|
+
...extra.title !== void 0 ? { title: extra.title } : {},
|
|
15
|
+
...extra.detail !== void 0 ? { detail: extra.detail } : {},
|
|
16
|
+
...extra.instance !== void 0 ? { instance: extra.instance } : {},
|
|
17
|
+
...extra.param !== void 0 ? { param: extra.param } : {},
|
|
18
|
+
...extra.currentRevision !== void 0 ? { currentRevision: extra.currentRevision } : {},
|
|
19
|
+
...extra.requestId !== void 0 ? { requestId: extra.requestId } : {},
|
|
20
|
+
...extra.suggestion !== void 0 ? { suggestion: extra.suggestion } : {},
|
|
21
|
+
...extra.retryable !== void 0 ? { retryable: extra.retryable } : {},
|
|
22
|
+
...extra.body !== void 0 ? { body: extra.body } : {}
|
|
23
|
+
},
|
|
24
|
+
headers: extra.headers ?? {}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
var PublishInputError = class extends Error {
|
|
28
|
+
constructor(code, message, param, suggestion) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.param = param;
|
|
32
|
+
this.suggestion = suggestion;
|
|
33
|
+
this.name = "PublishInputError";
|
|
34
|
+
}
|
|
35
|
+
code;
|
|
36
|
+
param;
|
|
37
|
+
suggestion;
|
|
38
|
+
};
|
|
39
|
+
function toErrorResult(err) {
|
|
40
|
+
if (err instanceof PublishInputError)
|
|
41
|
+
return createErrorResult(err.code, err.message, null, {
|
|
42
|
+
param: err.param ?? null,
|
|
43
|
+
suggestion: err.suggestion ?? null
|
|
44
|
+
});
|
|
45
|
+
return createErrorResult(
|
|
46
|
+
"sdk_error",
|
|
47
|
+
err instanceof Error ? err.message : "Unknown SDK error",
|
|
48
|
+
null
|
|
49
|
+
);
|
|
17
50
|
}
|
|
18
51
|
|
|
19
52
|
// src/publish/detect.ts
|
|
@@ -25,246 +58,100 @@ function isHttpUrl(value) {
|
|
|
25
58
|
return false;
|
|
26
59
|
}
|
|
27
60
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
return trimmed.startsWith("<!doctype html") || trimmed.startsWith("<html") || /^<[a-z][a-z0-9:-]*(\s|>)/.test(trimmed);
|
|
61
|
+
function containsHtmlTag(value) {
|
|
62
|
+
return /<[a-z!/][^>]*>/i.test(value);
|
|
31
63
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
64
|
+
var FILE_EXT = /\.[A-Za-z0-9]{1,8}([?#].*)?$/;
|
|
65
|
+
function isPathShaped(value) {
|
|
66
|
+
if (value.length === 0 || value.length > 4096 || value.includes("\n"))
|
|
67
|
+
return false;
|
|
68
|
+
if (containsHtmlTag(value)) return false;
|
|
69
|
+
if (value.includes("/") || value.includes("\\")) return true;
|
|
70
|
+
if (/^[A-Za-z]:[\\/]/.test(value)) return true;
|
|
71
|
+
return FILE_EXT.test(value);
|
|
72
|
+
}
|
|
73
|
+
function contentTypeForString(value, override) {
|
|
74
|
+
if (override) return override;
|
|
75
|
+
return containsHtmlTag(value) ? "text/html" : "text/plain; charset=utf-8";
|
|
38
76
|
}
|
|
39
77
|
function detectBytesContentType(bytes) {
|
|
40
|
-
const text =
|
|
78
|
+
const text = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
41
79
|
if (text.includes("\uFFFD")) return "application/octet-stream";
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// src/publish/files.ts
|
|
46
|
-
import { readFile, stat } from "fs/promises";
|
|
47
|
-
import { basename, sep } from "path";
|
|
48
|
-
import fg from "fast-glob";
|
|
49
|
-
import ignore from "ignore";
|
|
50
|
-
import { lookup } from "mime-types";
|
|
51
|
-
var DEFAULT_IGNORES = [
|
|
52
|
-
".git",
|
|
53
|
-
".git/**",
|
|
54
|
-
"node_modules",
|
|
55
|
-
"node_modules/**",
|
|
56
|
-
".DS_Store",
|
|
57
|
-
".env",
|
|
58
|
-
".env.*",
|
|
59
|
-
".cache",
|
|
60
|
-
".cache/**",
|
|
61
|
-
".tmp",
|
|
62
|
-
".tmp/**",
|
|
63
|
-
"dist/.cache",
|
|
64
|
-
"dist/.cache/**"
|
|
65
|
-
];
|
|
66
|
-
async function collectPublishFiles(inputPath, options = {}) {
|
|
67
|
-
const inputStat = await stat(inputPath);
|
|
68
|
-
if (inputStat.isFile()) {
|
|
69
|
-
return [
|
|
70
|
-
{
|
|
71
|
-
absolutePath: inputPath,
|
|
72
|
-
path: basename(inputPath),
|
|
73
|
-
contentType: await detectPathContentType(inputPath),
|
|
74
|
-
sizeBytes: inputStat.size
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
}
|
|
78
|
-
if (!inputStat.isDirectory()) {
|
|
79
|
-
throw new Error(`Input is not a file or directory: ${inputPath}`);
|
|
80
|
-
}
|
|
81
|
-
const matcher = ignore().add([
|
|
82
|
-
...options.ignoreDefaults === false ? [] : DEFAULT_IGNORES,
|
|
83
|
-
...options.ignore ?? []
|
|
84
|
-
]);
|
|
85
|
-
const entries = await fg("**/*", {
|
|
86
|
-
cwd: inputPath,
|
|
87
|
-
onlyFiles: true,
|
|
88
|
-
followSymbolicLinks: false,
|
|
89
|
-
dot: true,
|
|
90
|
-
unique: true
|
|
91
|
-
});
|
|
92
|
-
const paths = entries.map((entry) => entry.split(sep).join("/")).filter((entry) => !matcher.ignores(entry)).sort((a, b) => a.localeCompare(b));
|
|
93
|
-
return Promise.all(
|
|
94
|
-
paths.map(async (path) => {
|
|
95
|
-
const absolutePath = `${inputPath}/${path}`;
|
|
96
|
-
const fileStat = await stat(absolutePath);
|
|
97
|
-
return {
|
|
98
|
-
absolutePath,
|
|
99
|
-
path,
|
|
100
|
-
contentType: await detectPathContentType(absolutePath),
|
|
101
|
-
sizeBytes: fileStat.size
|
|
102
|
-
};
|
|
103
|
-
})
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
async function detectPathContentType(path) {
|
|
107
|
-
const detected = lookup(path);
|
|
108
|
-
if (detected) return detected;
|
|
109
|
-
return detectBytesContentType(await readFile(path));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// src/publish/prepare.ts
|
|
113
|
-
var SINGLE_PUT_CHECKSUM_THRESHOLD_BYTES = 10 * 1024 * 1024;
|
|
114
|
-
async function preparePublishRequest(input, options = {}) {
|
|
115
|
-
if (input instanceof URL) {
|
|
116
|
-
throw new Error(
|
|
117
|
-
"URL inputs are not supported. Fetch the content first, then pass it as a string or file."
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
if (typeof input === "string") {
|
|
121
|
-
const local = await localKind(input);
|
|
122
|
-
if (local === "file") {
|
|
123
|
-
return fileStaged(input, options);
|
|
124
|
-
}
|
|
125
|
-
if (local === "directory") {
|
|
126
|
-
return folderStaged(input, options);
|
|
127
|
-
}
|
|
128
|
-
const detection = detectStringInput(input);
|
|
129
|
-
if (detection.mode === "sourceUrl")
|
|
130
|
-
throw new Error(
|
|
131
|
-
"URL inputs are not supported. Fetch the content first, then pass it as a string or file."
|
|
132
|
-
);
|
|
133
|
-
return stringContent(input, options, detection.contentType);
|
|
134
|
-
}
|
|
135
|
-
if (input instanceof Uint8Array || Buffer.isBuffer(input)) {
|
|
136
|
-
return bytesStaged(input, options);
|
|
137
|
-
}
|
|
138
|
-
return explicitInput(input, options);
|
|
139
|
-
}
|
|
140
|
-
async function stringContent(content, options, detectedContentType) {
|
|
141
|
-
const contentType = options.contentType ?? detectedContentType;
|
|
142
|
-
return bytesStaged(Buffer.from(content), {
|
|
143
|
-
...options,
|
|
144
|
-
path: options.path ?? entryForContentType(contentType),
|
|
145
|
-
contentType
|
|
146
|
-
});
|
|
80
|
+
return containsHtmlTag(text) ? "text/html" : "text/plain; charset=utf-8";
|
|
147
81
|
}
|
|
148
82
|
function entryForContentType(contentType) {
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
if (
|
|
154
|
-
if (normalized === "text/javascript" || normalized === "application/javascript")
|
|
83
|
+
const m = contentType.toLowerCase().split(";", 1)[0]?.trim() ?? "";
|
|
84
|
+
if (m === "text/html" || m === "application/xhtml+xml") return "index.html";
|
|
85
|
+
if (m === "application/json") return "index.json";
|
|
86
|
+
if (m === "text/css") return "index.css";
|
|
87
|
+
if (m === "text/javascript" || m === "application/javascript")
|
|
155
88
|
return "index.js";
|
|
156
|
-
if (
|
|
89
|
+
if (m.startsWith("text/")) return "index.txt";
|
|
157
90
|
return "index";
|
|
158
91
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (info.isDirectory()) return "directory";
|
|
164
|
-
return "none";
|
|
165
|
-
} catch {
|
|
166
|
-
return "none";
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
async function fileStaged(path, options) {
|
|
170
|
-
const fileStat = await stat2(path);
|
|
171
|
-
const manifestPath = options.path ?? basename2(path);
|
|
172
|
-
return stagedRequest(
|
|
173
|
-
[
|
|
174
|
-
{
|
|
175
|
-
path: manifestPath,
|
|
176
|
-
contentType: options.contentType ?? await detectPathContentType(path),
|
|
177
|
-
sizeBytes: fileStat.size,
|
|
178
|
-
source: { kind: "path", path }
|
|
179
|
-
}
|
|
180
|
-
],
|
|
181
|
-
{ ...options, entry: options.entry ?? manifestPath }
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
async function folderStaged(path, options) {
|
|
185
|
-
const files = (await collectPublishFiles(path, options)).map((file) => ({
|
|
186
|
-
path: file.path,
|
|
187
|
-
contentType: file.contentType,
|
|
188
|
-
sizeBytes: file.sizeBytes,
|
|
189
|
-
source: { kind: "path", path: file.absolutePath }
|
|
190
|
-
}));
|
|
191
|
-
return stagedRequest(files, options);
|
|
192
|
-
}
|
|
193
|
-
async function bytesStaged(bytes, options) {
|
|
194
|
-
return stagedRequest(
|
|
195
|
-
[
|
|
196
|
-
{
|
|
197
|
-
path: options.path ?? "index",
|
|
198
|
-
contentType: options.contentType ?? detectBytesContentType(bytes),
|
|
199
|
-
sizeBytes: bytes.byteLength,
|
|
200
|
-
source: { kind: "bytes", bytes }
|
|
201
|
-
}
|
|
202
|
-
],
|
|
203
|
-
options
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
async function stagedRequest(files, options) {
|
|
207
|
-
const preparedFiles = await Promise.all(
|
|
208
|
-
files.map(async (file) => {
|
|
209
|
-
if (file.sizeBytes <= SINGLE_PUT_CHECKSUM_THRESHOLD_BYTES) return file;
|
|
210
|
-
const checksumSha256 = file.source.kind === "bytes" ? sha256Bytes(file.source.bytes) : await sha256File(file.source.path);
|
|
211
|
-
return { ...file, checksumSha256 };
|
|
212
|
-
})
|
|
213
|
-
);
|
|
214
|
-
const manifestFiles = preparedFiles.map((file) => ({
|
|
215
|
-
path: file.path,
|
|
216
|
-
contentType: file.contentType,
|
|
217
|
-
sizeBytes: file.sizeBytes,
|
|
218
|
-
...file.checksumSha256 ? { checksumSha256: file.checksumSha256 } : {}
|
|
219
|
-
}));
|
|
220
|
-
const prepared = {
|
|
221
|
-
kind: "staged",
|
|
222
|
-
manifest: {
|
|
223
|
-
schemaVersion: 1,
|
|
224
|
-
files: manifestFiles,
|
|
225
|
-
...options.entry ? { entry: options.entry } : {}
|
|
226
|
-
},
|
|
227
|
-
files: preparedFiles,
|
|
228
|
-
options: optionsBody(options)
|
|
229
|
-
};
|
|
230
|
-
if (options.metadata) prepared.metadata = options.metadata;
|
|
231
|
-
return prepared;
|
|
92
|
+
|
|
93
|
+
// src/publish/paths.ts
|
|
94
|
+
function normalizeManifestPath(path) {
|
|
95
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
232
96
|
}
|
|
233
|
-
|
|
234
|
-
if ("
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
97
|
+
function assertValidManifestPath(path) {
|
|
98
|
+
if (path.includes("\\"))
|
|
99
|
+
throw new PublishInputError(
|
|
100
|
+
"invalid_path",
|
|
101
|
+
`Manifest path must use "/": "${path}".`,
|
|
102
|
+
path
|
|
239
103
|
);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
104
|
+
const p = normalizeManifestPath(path);
|
|
105
|
+
if (p === "")
|
|
106
|
+
throw new PublishInputError(
|
|
107
|
+
"invalid_path",
|
|
108
|
+
"Manifest path must not be empty.",
|
|
109
|
+
path
|
|
243
110
|
);
|
|
244
|
-
if ("
|
|
245
|
-
throw new
|
|
246
|
-
"
|
|
111
|
+
if (p.startsWith("/"))
|
|
112
|
+
throw new PublishInputError(
|
|
113
|
+
"invalid_path",
|
|
114
|
+
`Manifest path must be relative: "${path}".`,
|
|
115
|
+
path
|
|
116
|
+
);
|
|
117
|
+
if (p.startsWith("~"))
|
|
118
|
+
throw new PublishInputError(
|
|
119
|
+
"invalid_path",
|
|
120
|
+
`Manifest path must not start with "~": "${path}".`,
|
|
121
|
+
path
|
|
122
|
+
);
|
|
123
|
+
if (p.split("/").includes(".."))
|
|
124
|
+
throw new PublishInputError(
|
|
125
|
+
"invalid_path",
|
|
126
|
+
`Manifest path must not contain "..": "${path}".`,
|
|
127
|
+
path
|
|
247
128
|
);
|
|
248
|
-
return stagedRequest(
|
|
249
|
-
input.files.map((file) => {
|
|
250
|
-
const bytes = explicitFileBytes(file);
|
|
251
|
-
return {
|
|
252
|
-
path: file.path,
|
|
253
|
-
contentType: file.contentType,
|
|
254
|
-
sizeBytes: bytes.byteLength,
|
|
255
|
-
source: { kind: "bytes", bytes }
|
|
256
|
-
};
|
|
257
|
-
}),
|
|
258
|
-
{ ...options, ...input }
|
|
259
|
-
);
|
|
260
129
|
}
|
|
261
|
-
function
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
130
|
+
function assertNoDuplicatePaths(paths) {
|
|
131
|
+
const seen = /* @__PURE__ */ new Set();
|
|
132
|
+
for (const raw of paths) {
|
|
133
|
+
const p = normalizeManifestPath(raw);
|
|
134
|
+
if (seen.has(p))
|
|
135
|
+
throw new PublishInputError(
|
|
136
|
+
"duplicate_path",
|
|
137
|
+
`Duplicate file path after normalization: "${p}".`,
|
|
138
|
+
p,
|
|
139
|
+
"Give each file a unique path; basename mapping for string[] can collide."
|
|
140
|
+
);
|
|
141
|
+
seen.add(p);
|
|
142
|
+
}
|
|
267
143
|
}
|
|
144
|
+
function assertNonEmptyBundle(paths) {
|
|
145
|
+
if (paths.length === 0)
|
|
146
|
+
throw new PublishInputError(
|
|
147
|
+
"empty_bundle",
|
|
148
|
+
"Nothing to publish: the bundle has no files.",
|
|
149
|
+
void 0,
|
|
150
|
+
"Pass at least one file, or a directory that contains files."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/publish/core.ts
|
|
268
155
|
var VALID_VISIBILITIES = ["public", "unlisted"];
|
|
269
156
|
var MAX_TITLE_LENGTH = 500;
|
|
270
157
|
function validatePublishOptions(options) {
|
|
@@ -301,93 +188,125 @@ function optionsBody(options) {
|
|
|
301
188
|
expiresAt: options.expiresAt instanceof Date ? options.expiresAt.toISOString() : options.expiresAt
|
|
302
189
|
};
|
|
303
190
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
...extra.suggestion !== void 0 ? { suggestion: extra.suggestion } : {},
|
|
327
|
-
...extra.retryable !== void 0 ? { retryable: extra.retryable } : {}
|
|
328
|
-
},
|
|
329
|
-
headers: extra.headers ?? {}
|
|
191
|
+
function buildStagedRequest(files, options, entry) {
|
|
192
|
+
assertNonEmptyBundle(files.map((f) => f.path));
|
|
193
|
+
const normalizedPaths = files.map((f) => normalizeManifestPath(f.path));
|
|
194
|
+
assertNoDuplicatePaths(normalizedPaths);
|
|
195
|
+
const manifestFiles = files.map((file) => ({
|
|
196
|
+
path: normalizeManifestPath(file.path),
|
|
197
|
+
contentType: file.contentType,
|
|
198
|
+
sizeBytes: file.sizeBytes,
|
|
199
|
+
...file.checksumSha256 ? { checksumSha256: file.checksumSha256 } : {}
|
|
200
|
+
}));
|
|
201
|
+
const resolvedEntry = entry ?? options.entry;
|
|
202
|
+
if (resolvedEntry !== void 0) assertValidManifestPath(resolvedEntry);
|
|
203
|
+
const manifest = {
|
|
204
|
+
schemaVersion: 1,
|
|
205
|
+
files: manifestFiles,
|
|
206
|
+
...resolvedEntry ? { entry: resolvedEntry } : {}
|
|
207
|
+
};
|
|
208
|
+
const prepared = {
|
|
209
|
+
kind: "staged",
|
|
210
|
+
manifest,
|
|
211
|
+
files,
|
|
212
|
+
options: optionsBody(options)
|
|
330
213
|
};
|
|
214
|
+
if (options.metadata) prepared.metadata = options.metadata;
|
|
215
|
+
return prepared;
|
|
331
216
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
"
|
|
339
|
-
"Multipart upload target did not include a valid part size.",
|
|
340
|
-
null
|
|
217
|
+
function buildSourceRequest(sourceUrl, options) {
|
|
218
|
+
if (!isHttpUrl(sourceUrl)) {
|
|
219
|
+
throw new PublishInputError(
|
|
220
|
+
"invalid_source_url",
|
|
221
|
+
"source_url must be an http(s) URL.",
|
|
222
|
+
sourceUrl,
|
|
223
|
+
"Fetch the content first, then pass it as content/files."
|
|
341
224
|
);
|
|
342
225
|
}
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
226
|
+
const prepared = {
|
|
227
|
+
kind: "source",
|
|
228
|
+
sourceUrl,
|
|
229
|
+
options: optionsBody(options)
|
|
230
|
+
};
|
|
231
|
+
if (options.metadata) prepared.metadata = options.metadata;
|
|
232
|
+
return prepared;
|
|
233
|
+
}
|
|
234
|
+
function decodeBase64(value) {
|
|
235
|
+
const binary = atob(value);
|
|
236
|
+
return Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
237
|
+
}
|
|
238
|
+
function fileBytes(file) {
|
|
239
|
+
if (file.content !== void 0) return new TextEncoder().encode(file.content);
|
|
240
|
+
if (file.contentBase64 !== void 0) return decodeBase64(file.contentBase64);
|
|
241
|
+
if (file.bytes !== void 0) return file.bytes;
|
|
242
|
+
throw new PublishInputError(
|
|
243
|
+
"missing_file_bytes",
|
|
244
|
+
`File "${file.path}" is missing content bytes.`,
|
|
245
|
+
file.path,
|
|
246
|
+
"Provide one of content, contentBase64, or bytes."
|
|
346
247
|
);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
{ body: { fileId, partNumbers: partNumberBatch } }
|
|
357
|
-
);
|
|
358
|
-
if (targetsResult.error) return errorResult(targetsResult);
|
|
359
|
-
for (const target of targetsResult.data.parts) {
|
|
360
|
-
const start = (target.partNumber - 1) * partSize;
|
|
361
|
-
const end = Math.min(start + partSize, bytes.byteLength);
|
|
362
|
-
const uploadResult = await transport.putSignedUrl(
|
|
363
|
-
target.url,
|
|
364
|
-
bytes.slice(start, end),
|
|
365
|
-
target.headers
|
|
366
|
-
);
|
|
367
|
-
if (uploadResult.error) return errorResult(uploadResult);
|
|
368
|
-
if (!uploadResult.data.etag) {
|
|
369
|
-
return createErrorResult(
|
|
370
|
-
"missing_upload_etag",
|
|
371
|
-
"Signed upload response did not include an ETag.",
|
|
372
|
-
null
|
|
373
|
-
);
|
|
248
|
+
}
|
|
249
|
+
function singleStagedFile(path, contentType, bytes, options) {
|
|
250
|
+
return buildStagedRequest(
|
|
251
|
+
[
|
|
252
|
+
{
|
|
253
|
+
path,
|
|
254
|
+
contentType,
|
|
255
|
+
sizeBytes: bytes.byteLength,
|
|
256
|
+
getBody: async () => bytes
|
|
374
257
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
258
|
+
],
|
|
259
|
+
options
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
async function resolveInMemory(input, options = {}) {
|
|
263
|
+
if (input instanceof URL) {
|
|
264
|
+
return buildSourceRequest(input.toString(), options);
|
|
380
265
|
}
|
|
381
|
-
|
|
266
|
+
if (typeof input === "string") {
|
|
267
|
+
if (isHttpUrl(input)) return buildSourceRequest(input, options);
|
|
268
|
+
const contentType = contentTypeForString(input, options.contentType);
|
|
269
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
270
|
+
const path = options.path ?? entryForContentType(contentType);
|
|
271
|
+
const bytes = new TextEncoder().encode(input);
|
|
272
|
+
return singleStagedFile(path, contentType, bytes, options);
|
|
273
|
+
}
|
|
274
|
+
if (input instanceof Uint8Array) {
|
|
275
|
+
const contentType = options.contentType ?? detectBytesContentType(input);
|
|
276
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
277
|
+
const path = options.path ?? entryForContentType(contentType);
|
|
278
|
+
return singleStagedFile(path, contentType, input, options);
|
|
279
|
+
}
|
|
280
|
+
if (input.kind === "content") {
|
|
281
|
+
const contentType = input.contentType ?? options.contentType ?? "text/html";
|
|
282
|
+
if (input.path !== void 0) assertValidManifestPath(input.path);
|
|
283
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
284
|
+
const path = input.path ?? options.path ?? entryForContentType(contentType);
|
|
285
|
+
const bytes = new TextEncoder().encode(input.content);
|
|
286
|
+
return singleStagedFile(path, contentType, bytes, options);
|
|
287
|
+
}
|
|
288
|
+
if (input.kind === "source_url") {
|
|
289
|
+
return buildSourceRequest(input.sourceUrl, options);
|
|
290
|
+
}
|
|
291
|
+
const files = input.files.map((file) => {
|
|
292
|
+
assertValidManifestPath(file.path);
|
|
293
|
+
const bytes = fileBytes(file);
|
|
294
|
+
const contentType = file.contentType ?? detectBytesContentType(bytes);
|
|
295
|
+
return {
|
|
296
|
+
path: file.path,
|
|
297
|
+
contentType,
|
|
298
|
+
sizeBytes: bytes.byteLength,
|
|
299
|
+
getBody: async () => bytes
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
return buildStagedRequest(files, options, input.entry);
|
|
382
303
|
}
|
|
383
304
|
function errorResult(result) {
|
|
384
305
|
if (!result.error) throw new Error("Expected an error result");
|
|
385
306
|
return { data: null, error: result.error, headers: result.headers };
|
|
386
307
|
}
|
|
387
|
-
|
|
388
|
-
// src/publish/upload.ts
|
|
389
308
|
async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
390
|
-
const baseKey = options.idempotencyKey ?? `sdk-${randomUUID()}`;
|
|
309
|
+
const baseKey = options.idempotencyKey ?? `sdk-${crypto.randomUUID()}`;
|
|
391
310
|
const createResult = await transport.request(
|
|
392
311
|
"POST",
|
|
393
312
|
"/uploads",
|
|
@@ -396,12 +315,9 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
396
315
|
idempotencyKey: `${baseKey}:create-upload`
|
|
397
316
|
}
|
|
398
317
|
);
|
|
399
|
-
if (createResult.error) return
|
|
400
|
-
const completedFiles = {};
|
|
318
|
+
if (createResult.error) return errorResult(createResult);
|
|
401
319
|
for (const file of prepared.files) {
|
|
402
|
-
const target = createResult.data.files.find(
|
|
403
|
-
(candidate) => candidate.path === file.path
|
|
404
|
-
);
|
|
320
|
+
const target = createResult.data.files.find((f) => f.path === file.path);
|
|
405
321
|
if (!target) {
|
|
406
322
|
return createErrorResult(
|
|
407
323
|
"upload_target_missing",
|
|
@@ -409,36 +325,29 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
409
325
|
null
|
|
410
326
|
);
|
|
411
327
|
}
|
|
412
|
-
if (target.upload.strategy
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
target.fileId,
|
|
418
|
-
bytes2,
|
|
419
|
-
target.upload.partSize
|
|
328
|
+
if (target.upload.strategy !== "single_put") {
|
|
329
|
+
return createErrorResult(
|
|
330
|
+
"unsupported_upload_strategy",
|
|
331
|
+
`Unsupported upload strategy "${target.upload.strategy}" for ${file.path}. This SDK uploads via single PUT only.`,
|
|
332
|
+
null
|
|
420
333
|
);
|
|
421
|
-
if (partsResult.error) return errorResult2(partsResult);
|
|
422
|
-
completedFiles[target.fileId] = { parts: partsResult.data };
|
|
423
|
-
continue;
|
|
424
334
|
}
|
|
425
|
-
const
|
|
426
|
-
const uploadResult = await transport.putSignedUrl(
|
|
335
|
+
const put = await transport.putSignedUrl(
|
|
427
336
|
target.upload.url,
|
|
428
|
-
|
|
337
|
+
await file.getBody(),
|
|
429
338
|
target.upload.headers
|
|
430
339
|
);
|
|
431
|
-
if (
|
|
340
|
+
if (put.error) return errorResult(put);
|
|
432
341
|
}
|
|
433
342
|
const completeResult = await transport.request(
|
|
434
343
|
"POST",
|
|
435
344
|
`/uploads/${encodeURIComponent(createResult.data.uploadId)}/complete`,
|
|
436
345
|
{
|
|
437
|
-
body: { files:
|
|
346
|
+
body: { files: {} },
|
|
438
347
|
idempotencyKey: `${baseKey}:complete-upload`
|
|
439
348
|
}
|
|
440
349
|
);
|
|
441
|
-
if (completeResult.error) return
|
|
350
|
+
if (completeResult.error) return errorResult(completeResult);
|
|
442
351
|
const finalOptions = {
|
|
443
352
|
body: {
|
|
444
353
|
uploadId: createResult.data.uploadId,
|
|
@@ -451,13 +360,184 @@ async function publishStaged(transport, prepared, finalPath, options = {}) {
|
|
|
451
360
|
finalOptions.ifRevision = options.ifRevision;
|
|
452
361
|
return transport.request("POST", finalPath, finalOptions);
|
|
453
362
|
}
|
|
454
|
-
async function
|
|
455
|
-
|
|
456
|
-
return
|
|
363
|
+
async function publishSource(transport, prepared, finalPath, options = {}) {
|
|
364
|
+
const baseKey = options.idempotencyKey ?? `sdk-${crypto.randomUUID()}`;
|
|
365
|
+
return transport.request("POST", finalPath, {
|
|
366
|
+
body: {
|
|
367
|
+
sourceUrl: prepared.sourceUrl,
|
|
368
|
+
options: prepared.options,
|
|
369
|
+
...prepared.metadata ? { metadata: prepared.metadata } : {}
|
|
370
|
+
},
|
|
371
|
+
idempotencyKey: `${baseKey}:publish`,
|
|
372
|
+
...options.ifRevision !== void 0 ? { ifRevision: options.ifRevision } : {}
|
|
373
|
+
});
|
|
457
374
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
375
|
+
|
|
376
|
+
// src/publish/node.ts
|
|
377
|
+
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
378
|
+
import { basename as basename2 } from "path";
|
|
379
|
+
|
|
380
|
+
// src/publish/checksum.ts
|
|
381
|
+
import { createHash } from "crypto";
|
|
382
|
+
import { createReadStream } from "fs";
|
|
383
|
+
async function sha256File(path) {
|
|
384
|
+
const hash = createHash("sha256");
|
|
385
|
+
for await (const chunk of createReadStream(path)) {
|
|
386
|
+
hash.update(chunk);
|
|
387
|
+
}
|
|
388
|
+
return hash.digest("hex");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/publish/files.ts
|
|
392
|
+
import { readFile, stat } from "fs/promises";
|
|
393
|
+
import { basename, sep } from "path";
|
|
394
|
+
import fg from "fast-glob";
|
|
395
|
+
import ignore from "ignore";
|
|
396
|
+
import { lookup } from "mime-types";
|
|
397
|
+
var DEFAULT_IGNORES = [
|
|
398
|
+
".git",
|
|
399
|
+
".git/**",
|
|
400
|
+
"node_modules",
|
|
401
|
+
"node_modules/**",
|
|
402
|
+
".DS_Store",
|
|
403
|
+
".env",
|
|
404
|
+
".env.*",
|
|
405
|
+
".cache",
|
|
406
|
+
".cache/**",
|
|
407
|
+
".tmp",
|
|
408
|
+
".tmp/**",
|
|
409
|
+
"dist/.cache",
|
|
410
|
+
"dist/.cache/**"
|
|
411
|
+
];
|
|
412
|
+
async function collectPublishFiles(inputPath, options = {}) {
|
|
413
|
+
const inputStat = await stat(inputPath);
|
|
414
|
+
if (inputStat.isFile()) {
|
|
415
|
+
return [
|
|
416
|
+
{
|
|
417
|
+
absolutePath: inputPath,
|
|
418
|
+
path: basename(inputPath),
|
|
419
|
+
contentType: await detectPathContentType(inputPath),
|
|
420
|
+
sizeBytes: inputStat.size
|
|
421
|
+
}
|
|
422
|
+
];
|
|
423
|
+
}
|
|
424
|
+
if (!inputStat.isDirectory()) {
|
|
425
|
+
throw new Error(`Input is not a file or directory: ${inputPath}`);
|
|
426
|
+
}
|
|
427
|
+
const matcher = ignore().add([
|
|
428
|
+
...options.ignoreDefaults === false ? [] : DEFAULT_IGNORES,
|
|
429
|
+
...options.ignore ?? []
|
|
430
|
+
]);
|
|
431
|
+
const entries = await fg("**/*", {
|
|
432
|
+
cwd: inputPath,
|
|
433
|
+
onlyFiles: true,
|
|
434
|
+
followSymbolicLinks: false,
|
|
435
|
+
dot: true,
|
|
436
|
+
unique: true
|
|
437
|
+
});
|
|
438
|
+
const paths = entries.map((entry) => entry.split(sep).join("/")).filter((entry) => !matcher.ignores(entry)).sort((a, b) => a.localeCompare(b));
|
|
439
|
+
return Promise.all(
|
|
440
|
+
paths.map(async (path) => {
|
|
441
|
+
const absolutePath = `${inputPath}/${path}`;
|
|
442
|
+
const fileStat = await stat(absolutePath);
|
|
443
|
+
return {
|
|
444
|
+
absolutePath,
|
|
445
|
+
path,
|
|
446
|
+
contentType: await detectPathContentType(absolutePath),
|
|
447
|
+
sizeBytes: fileStat.size
|
|
448
|
+
};
|
|
449
|
+
})
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
async function detectPathContentType(path) {
|
|
453
|
+
const detected = lookup(path);
|
|
454
|
+
if (detected) return detected;
|
|
455
|
+
return detectBytesContentType(await readFile(path));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/publish/node.ts
|
|
459
|
+
var SINGLE_PUT_CHECKSUM_THRESHOLD = 10 * 1024 * 1024;
|
|
460
|
+
async function resolveInput(input, options = {}) {
|
|
461
|
+
if (input instanceof URL || input instanceof Uint8Array || typeof input === "object" && input !== null && "kind" in input) {
|
|
462
|
+
return resolveInMemory(input, options);
|
|
463
|
+
}
|
|
464
|
+
if (Array.isArray(input)) {
|
|
465
|
+
return resolveBundle(input, options);
|
|
466
|
+
}
|
|
467
|
+
if (typeof input === "string") {
|
|
468
|
+
return resolveString(input, options);
|
|
469
|
+
}
|
|
470
|
+
return resolveInMemory(input, options);
|
|
471
|
+
}
|
|
472
|
+
async function resolveString(value, options) {
|
|
473
|
+
if (isHttpUrl(value)) return resolveInMemory(value, options);
|
|
474
|
+
if (value.includes("\n") || value.length > 4096) {
|
|
475
|
+
return resolveInMemory(value, options);
|
|
476
|
+
}
|
|
477
|
+
let info;
|
|
478
|
+
try {
|
|
479
|
+
info = await stat2(value);
|
|
480
|
+
} catch {
|
|
481
|
+
info = void 0;
|
|
482
|
+
}
|
|
483
|
+
if (info?.isFile()) return fileStaged(value, options);
|
|
484
|
+
if (info?.isDirectory()) return folderStaged(value, options);
|
|
485
|
+
if (isPathShaped(value)) {
|
|
486
|
+
throw new PublishInputError(
|
|
487
|
+
"file_not_found",
|
|
488
|
+
`No file or directory at "${value}".`,
|
|
489
|
+
value,
|
|
490
|
+
'To publish this as inline text, pass { kind: "content", content }.'
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
return resolveInMemory(value, options);
|
|
494
|
+
}
|
|
495
|
+
async function fileStaged(path, options) {
|
|
496
|
+
const fileStat = await stat2(path);
|
|
497
|
+
if (options.path !== void 0) assertValidManifestPath(options.path);
|
|
498
|
+
const manifestPath = options.path ?? basename2(path);
|
|
499
|
+
const contentType = options.contentType ?? await detectPathContentType(path);
|
|
500
|
+
const checksumSha256 = fileStat.size > SINGLE_PUT_CHECKSUM_THRESHOLD ? await sha256File(path) : void 0;
|
|
501
|
+
const file = {
|
|
502
|
+
path: manifestPath,
|
|
503
|
+
contentType,
|
|
504
|
+
sizeBytes: fileStat.size,
|
|
505
|
+
...checksumSha256 ? { checksumSha256 } : {},
|
|
506
|
+
getBody: () => readFile2(path)
|
|
507
|
+
};
|
|
508
|
+
return buildStagedRequest([file], options);
|
|
509
|
+
}
|
|
510
|
+
async function folderStaged(path, options) {
|
|
511
|
+
const files = await collectPublishFiles(path, options);
|
|
512
|
+
const preparedFiles = await Promise.all(files.map(toPreparedFile));
|
|
513
|
+
return buildStagedRequest(preparedFiles, options);
|
|
514
|
+
}
|
|
515
|
+
async function resolveBundle(paths, options) {
|
|
516
|
+
const collected = [];
|
|
517
|
+
for (const element of paths) {
|
|
518
|
+
try {
|
|
519
|
+
await stat2(element);
|
|
520
|
+
} catch {
|
|
521
|
+
throw new PublishInputError(
|
|
522
|
+
"file_not_found",
|
|
523
|
+
`No file or directory at "${element}".`,
|
|
524
|
+
element
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
collected.push(...await collectPublishFiles(element, options));
|
|
528
|
+
}
|
|
529
|
+
const preparedFiles = await Promise.all(collected.map(toPreparedFile));
|
|
530
|
+
return buildStagedRequest(preparedFiles, options);
|
|
531
|
+
}
|
|
532
|
+
async function toPreparedFile(pf) {
|
|
533
|
+
const checksumSha256 = pf.sizeBytes > SINGLE_PUT_CHECKSUM_THRESHOLD ? await sha256File(pf.absolutePath) : void 0;
|
|
534
|
+
return {
|
|
535
|
+
path: pf.path,
|
|
536
|
+
contentType: pf.contentType,
|
|
537
|
+
sizeBytes: pf.sizeBytes,
|
|
538
|
+
...checksumSha256 ? { checksumSha256 } : {},
|
|
539
|
+
getBody: () => readFile2(pf.absolutePath)
|
|
540
|
+
};
|
|
461
541
|
}
|
|
462
542
|
|
|
463
543
|
// src/resources/account.ts
|
|
@@ -526,33 +606,6 @@ var DeploymentsResource = class {
|
|
|
526
606
|
this.transport = transport;
|
|
527
607
|
}
|
|
528
608
|
transport;
|
|
529
|
-
create(dropId, body, options = {}) {
|
|
530
|
-
const requestOptions = { body };
|
|
531
|
-
if (options.idempotencyKey)
|
|
532
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
533
|
-
if (options.ifRevision !== void 0)
|
|
534
|
-
requestOptions.ifRevision = options.ifRevision;
|
|
535
|
-
return this.transport.request(
|
|
536
|
-
"POST",
|
|
537
|
-
`/drops/${encodeURIComponent(dropId)}/deployments`,
|
|
538
|
-
requestOptions
|
|
539
|
-
);
|
|
540
|
-
}
|
|
541
|
-
createRaw(dropId, body, options = {}) {
|
|
542
|
-
const requestOptions = {
|
|
543
|
-
body,
|
|
544
|
-
bodyCase: "raw"
|
|
545
|
-
};
|
|
546
|
-
if (options.idempotencyKey)
|
|
547
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
548
|
-
if (options.ifRevision !== void 0)
|
|
549
|
-
requestOptions.ifRevision = options.ifRevision;
|
|
550
|
-
return this.transport.request(
|
|
551
|
-
"POST",
|
|
552
|
-
`/drops/${encodeURIComponent(dropId)}/deployments`,
|
|
553
|
-
requestOptions
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
609
|
list(dropId, params = {}) {
|
|
557
610
|
return this.transport.request(
|
|
558
611
|
"GET",
|
|
@@ -607,21 +660,6 @@ var DropsResource = class {
|
|
|
607
660
|
this.transport = transport;
|
|
608
661
|
}
|
|
609
662
|
transport;
|
|
610
|
-
create(body, options = {}) {
|
|
611
|
-
const requestOptions = { body };
|
|
612
|
-
if (options.idempotencyKey)
|
|
613
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
614
|
-
return this.transport.request("POST", "/drops", requestOptions);
|
|
615
|
-
}
|
|
616
|
-
createRaw(body, options = {}) {
|
|
617
|
-
const requestOptions = {
|
|
618
|
-
body,
|
|
619
|
-
bodyCase: "raw"
|
|
620
|
-
};
|
|
621
|
-
if (options.idempotencyKey)
|
|
622
|
-
requestOptions.idempotencyKey = options.idempotencyKey;
|
|
623
|
-
return this.transport.request("POST", "/drops", requestOptions);
|
|
624
|
-
}
|
|
625
663
|
async list(params = {}) {
|
|
626
664
|
const result = await this.transport.request("GET", "/drops", {
|
|
627
665
|
params
|
|
@@ -662,15 +700,22 @@ var DropsResource = class {
|
|
|
662
700
|
);
|
|
663
701
|
}
|
|
664
702
|
};
|
|
703
|
+
var SETTINGS = [
|
|
704
|
+
"title",
|
|
705
|
+
"visibility",
|
|
706
|
+
"password",
|
|
707
|
+
"noindex",
|
|
708
|
+
"expiresAt",
|
|
709
|
+
"slug"
|
|
710
|
+
];
|
|
665
711
|
function updateBody(options) {
|
|
666
|
-
const {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
...
|
|
672
|
-
}
|
|
673
|
-
return { options: dropOptions, metadata };
|
|
712
|
+
const out = {};
|
|
713
|
+
for (const key of SETTINGS)
|
|
714
|
+
if (options[key] !== void 0) out[key] = options[key];
|
|
715
|
+
return {
|
|
716
|
+
options: out,
|
|
717
|
+
...options.metadata !== void 0 ? { metadata: options.metadata } : {}
|
|
718
|
+
};
|
|
674
719
|
}
|
|
675
720
|
|
|
676
721
|
// src/resources/uploads.ts
|
|
@@ -691,13 +736,6 @@ var UploadsResource = class {
|
|
|
691
736
|
`/uploads/${encodeURIComponent(uploadId)}`
|
|
692
737
|
);
|
|
693
738
|
}
|
|
694
|
-
createPartTargets(uploadId, body) {
|
|
695
|
-
return this.transport.request(
|
|
696
|
-
"POST",
|
|
697
|
-
`/uploads/${encodeURIComponent(uploadId)}/parts`,
|
|
698
|
-
{ body }
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
739
|
complete(uploadId, body, options = {}) {
|
|
702
740
|
const requestOptions = { body };
|
|
703
741
|
if (options.idempotencyKey)
|
|
@@ -751,25 +789,24 @@ function toSnakeCase(value) {
|
|
|
751
789
|
|
|
752
790
|
// src/transport.ts
|
|
753
791
|
var DEFAULT_BASE_URL = "https://api.dropthis.app";
|
|
754
|
-
var SDK_VERSION = "0.
|
|
792
|
+
var SDK_VERSION = "0.6.0";
|
|
755
793
|
var Transport = class {
|
|
756
794
|
apiKey;
|
|
757
795
|
baseUrl;
|
|
758
796
|
timeoutMs;
|
|
797
|
+
uploadTimeoutMs;
|
|
759
798
|
fetchImpl;
|
|
760
799
|
constructor(options = {}) {
|
|
761
800
|
const resolved = typeof options === "string" ? { apiKey: options } : options;
|
|
762
|
-
this.apiKey = resolved.apiKey ?? process.env
|
|
801
|
+
this.apiKey = resolved.apiKey ?? (typeof process !== "undefined" ? process.env?.DROPTHIS_API_KEY : void 0);
|
|
763
802
|
this.baseUrl = (resolved.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
764
803
|
this.timeoutMs = resolved.timeoutMs ?? 3e4;
|
|
804
|
+
this.uploadTimeoutMs = resolved.uploadTimeoutMs ?? 12e4;
|
|
765
805
|
this.fetchImpl = resolved.fetch ?? globalThis.fetch;
|
|
766
806
|
}
|
|
767
|
-
multipart(method, path, form, options = {}) {
|
|
768
|
-
return this.request(method, path, { ...options, body: form });
|
|
769
|
-
}
|
|
770
807
|
async putSignedUrl(url, body, headers) {
|
|
771
808
|
const controller = new AbortController();
|
|
772
|
-
const timeout = setTimeout(() => controller.abort(), this.
|
|
809
|
+
const timeout = setTimeout(() => controller.abort(), this.uploadTimeoutMs);
|
|
773
810
|
try {
|
|
774
811
|
const request = {
|
|
775
812
|
method: "PUT",
|
|
@@ -824,7 +861,7 @@ var Transport = class {
|
|
|
824
861
|
if (options.idempotencyKey)
|
|
825
862
|
headers["idempotency-key"] = options.idempotencyKey;
|
|
826
863
|
if (options.ifRevision !== void 0)
|
|
827
|
-
headers["
|
|
864
|
+
headers["if-revision"] = String(options.ifRevision);
|
|
828
865
|
if (options.body !== void 0 && !(options.body instanceof FormData))
|
|
829
866
|
headers["content-type"] = "application/json";
|
|
830
867
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
@@ -856,11 +893,18 @@ var Transport = class {
|
|
|
856
893
|
const parsed = parseJson(text);
|
|
857
894
|
if (!response.ok) {
|
|
858
895
|
const body = parsed && typeof parsed === "object" ? parsed : {};
|
|
859
|
-
const message = stringValue(body.detail) ?? stringValue(body.
|
|
896
|
+
const message = stringValue(body.detail) ?? stringValue(body.title) ?? response.statusText;
|
|
860
897
|
const code = stringValue(body.code) ?? stringValue(body.error_code) ?? `http_${response.status}`;
|
|
861
898
|
const currentRevision = numberValue(body.current_revision);
|
|
899
|
+
const type = stringValue(body.type);
|
|
900
|
+
const title = stringValue(body.title);
|
|
901
|
+
const instance = stringValue(body.instance);
|
|
862
902
|
return createErrorResult(code, message, response.status, {
|
|
863
|
-
|
|
903
|
+
body,
|
|
904
|
+
...type !== null ? { type } : {},
|
|
905
|
+
...title !== null ? { title } : {},
|
|
906
|
+
...instance !== null ? { instance } : {},
|
|
907
|
+
detail: stringValue(body.detail),
|
|
864
908
|
param: stringValue(body.param),
|
|
865
909
|
...currentRevision !== void 0 ? { currentRevision } : {},
|
|
866
910
|
requestId: stringValue(body.request_id) ?? responseHeaders["x-request-id"] ?? null,
|
|
@@ -954,34 +998,36 @@ var Dropthis = class {
|
|
|
954
998
|
return this.uploadsResource;
|
|
955
999
|
}
|
|
956
1000
|
async prepare(input, options = {}) {
|
|
957
|
-
return
|
|
1001
|
+
return resolveInput(input, options);
|
|
958
1002
|
}
|
|
959
1003
|
async publish(input, options = {}) {
|
|
960
|
-
|
|
961
|
-
|
|
1004
|
+
let prepared;
|
|
1005
|
+
try {
|
|
1006
|
+
prepared = await resolveInput(input, options);
|
|
1007
|
+
} catch (e) {
|
|
1008
|
+
return toErrorResult(e);
|
|
1009
|
+
}
|
|
1010
|
+
return prepared.kind === "source" ? publishSource(this.transport, prepared, "/drops", options) : publishStaged(this.transport, prepared, "/drops", options);
|
|
962
1011
|
}
|
|
963
1012
|
async deploy(dropId, input, options = {}) {
|
|
964
|
-
|
|
1013
|
+
let prepared;
|
|
1014
|
+
try {
|
|
1015
|
+
prepared = await resolveInput(input, options);
|
|
1016
|
+
} catch (e) {
|
|
1017
|
+
return toErrorResult(e);
|
|
1018
|
+
}
|
|
965
1019
|
const path = `/drops/${encodeURIComponent(dropId)}/deployments`;
|
|
966
|
-
return publishStaged(this.transport, prepared, path, options);
|
|
1020
|
+
return prepared.kind === "source" ? publishSource(this.transport, prepared, path, options) : publishStaged(this.transport, prepared, path, options);
|
|
967
1021
|
}
|
|
968
1022
|
async update(dropId, options = {}) {
|
|
969
1023
|
return this.drops.update(dropId, options);
|
|
970
1024
|
}
|
|
971
|
-
request(method, path, options = {}) {
|
|
972
|
-
return this.transport.request(method, path, {
|
|
973
|
-
...options,
|
|
974
|
-
bodyCase: "raw"
|
|
975
|
-
});
|
|
976
|
-
}
|
|
977
|
-
requestSignedUpload(url, bytes, headers) {
|
|
978
|
-
return this.transport.putSignedUrl(url, bytes, headers);
|
|
979
|
-
}
|
|
980
1025
|
};
|
|
981
1026
|
export {
|
|
982
1027
|
CursorPage,
|
|
983
1028
|
DeploymentsResource,
|
|
984
1029
|
Dropthis,
|
|
1030
|
+
PublishInputError,
|
|
985
1031
|
UploadsResource,
|
|
986
1032
|
createErrorResult,
|
|
987
1033
|
redactSecrets
|