@dropthis/cli 0.4.0 → 0.4.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 +39 -21
- package/dist/cli.cjs +263 -19
- package/dist/cli.cjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Requires Node.js >= 20.
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
dropthis login
|
|
17
|
-
dropthis
|
|
17
|
+
dropthis ./index.html # publish is the default command
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Authentication
|
|
@@ -47,6 +47,8 @@ Credentials resolve in this order:
|
|
|
47
47
|
2. `DROPTHIS_API_KEY` environment variable
|
|
48
48
|
3. Stored credential from `dropthis login`
|
|
49
49
|
|
|
50
|
+
If you run `dropthis publish` without credentials in an interactive terminal, the CLI prompts you to log in inline — no separate `dropthis login` step needed. Disable with `--no-interactive`.
|
|
51
|
+
|
|
50
52
|
```bash
|
|
51
53
|
dropthis whoami # Check current auth status
|
|
52
54
|
dropthis logout # Remove stored credentials
|
|
@@ -55,21 +57,29 @@ dropthis logout --revoke # Remove and revoke the key on the server
|
|
|
55
57
|
|
|
56
58
|
## Publish
|
|
57
59
|
|
|
60
|
+
`publish` is the default command — you can omit it and pass files directly:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# These are equivalent:
|
|
64
|
+
dropthis ./report.html
|
|
65
|
+
dropthis publish ./report.html
|
|
66
|
+
```
|
|
67
|
+
|
|
58
68
|
```bash
|
|
59
69
|
# HTML file
|
|
60
|
-
dropthis
|
|
70
|
+
dropthis ./report.html
|
|
61
71
|
|
|
62
72
|
# Directory (static site)
|
|
63
|
-
dropthis
|
|
73
|
+
dropthis ./dist
|
|
64
74
|
|
|
65
75
|
# Stdin
|
|
66
76
|
echo "<h1>Hello</h1>" | dropthis publish - --content-type text/html --path index.html
|
|
67
77
|
|
|
68
78
|
# Multiple files bundled into one drop
|
|
69
|
-
dropthis
|
|
79
|
+
dropthis index.html styles.css app.js
|
|
70
80
|
|
|
71
81
|
# Print only the URL (recommended for agents)
|
|
72
|
-
dropthis
|
|
82
|
+
dropthis ./dist --url
|
|
73
83
|
```
|
|
74
84
|
|
|
75
85
|
### Publish options
|
|
@@ -90,9 +100,7 @@ All publish flags:
|
|
|
90
100
|
| `--title <title>` | Drop title |
|
|
91
101
|
| `--visibility <public\|unlisted>` | Drop visibility |
|
|
92
102
|
| `--password <password>` | Set password protection |
|
|
93
|
-
| `--no-password` | Clear password |
|
|
94
103
|
| `--noindex` | Prevent search indexing |
|
|
95
|
-
| `--index` | Allow indexing |
|
|
96
104
|
| `--entry <path>` | Entry file for directories |
|
|
97
105
|
| `--content-type <mime>` | MIME type (required for stdin) |
|
|
98
106
|
| `--path <path>` | Filename (required for stdin) |
|
|
@@ -113,35 +121,39 @@ These flags are inherited by all commands:
|
|
|
113
121
|
|------|-------------|
|
|
114
122
|
| `--api-key <key>` | Override API key for this invocation |
|
|
115
123
|
| `--api-url <url>` | Override API base URL |
|
|
124
|
+
| `--json` | Force JSON output |
|
|
116
125
|
| `-q, --quiet` | Suppress status output and imply JSON |
|
|
126
|
+
| `--no-interactive` | Disable interactive prompts (inline auth, confirmations) |
|
|
117
127
|
|
|
118
128
|
## Update
|
|
119
129
|
|
|
130
|
+
Update an existing drop's content, metadata, or both via `drops update`:
|
|
131
|
+
|
|
120
132
|
```bash
|
|
121
133
|
# Replace content
|
|
122
|
-
dropthis update drop_abc123 ./dist-v2
|
|
134
|
+
dropthis drops update drop_abc123 ./dist-v2
|
|
123
135
|
|
|
124
136
|
# Update metadata only
|
|
125
|
-
dropthis update drop_abc123 --title "New title"
|
|
137
|
+
dropthis drops update drop_abc123 --title "New title"
|
|
126
138
|
|
|
127
139
|
# Optimistic concurrency
|
|
128
|
-
dropthis update drop_abc123 ./dist-v2 --if-revision 1
|
|
140
|
+
dropthis drops update drop_abc123 ./dist-v2 --if-revision 1
|
|
129
141
|
|
|
130
142
|
# Change vanity slug
|
|
131
|
-
dropthis update drop_abc123 --slug new-slug
|
|
143
|
+
dropthis drops update drop_abc123 --slug new-slug
|
|
132
144
|
```
|
|
133
145
|
|
|
134
|
-
|
|
146
|
+
`drops update` supports all publish flags plus `--slug` and `--if-revision`.
|
|
135
147
|
|
|
136
148
|
## Commands
|
|
137
149
|
|
|
138
150
|
```bash
|
|
139
|
-
dropthis
|
|
140
|
-
dropthis
|
|
151
|
+
dropthis [input...] # Publish content (default command)
|
|
152
|
+
dropthis publish [input...] # Same as above, explicit form
|
|
141
153
|
|
|
142
154
|
dropthis drops list # List your drops
|
|
143
155
|
dropthis drops get <drop-id> # Get drop details
|
|
144
|
-
dropthis drops update <drop-id>
|
|
156
|
+
dropthis drops update <drop-id> [input] # Update content or metadata
|
|
145
157
|
dropthis drops delete <drop-id> # Delete a drop
|
|
146
158
|
|
|
147
159
|
dropthis login # Authenticate with email OTP
|
|
@@ -166,10 +178,15 @@ dropthis commands # Machine-readable command metadata
|
|
|
166
178
|
|
|
167
179
|
The CLI is designed for non-interactive use. In non-TTY environments (pipes, CI, agents), output defaults to JSON automatically.
|
|
168
180
|
|
|
169
|
-
**Environment
|
|
181
|
+
**Environment variables:**
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
export DROPTHIS_API_KEY=sk_live_... # API key (same as --api-key)
|
|
185
|
+
export DROPTHIS_API_URL=https://... # Override API base URL (same as --api-url)
|
|
186
|
+
export DROPTHIS_NON_INTERACTIVE=1 # Disable interactive prompts (same as --no-interactive)
|
|
187
|
+
```
|
|
170
188
|
|
|
171
189
|
```bash
|
|
172
|
-
export DROPTHIS_API_KEY=sk_live_...
|
|
173
190
|
dropthis publish ./dist --url
|
|
174
191
|
```
|
|
175
192
|
|
|
@@ -178,6 +195,7 @@ dropthis publish ./dist --url
|
|
|
178
195
|
- Use `--url` to get only the published URL (cleanest for agents)
|
|
179
196
|
- Use `--json` for the full structured response
|
|
180
197
|
- Use `--yes` for destructive commands (`drops delete`, `api-keys delete`)
|
|
198
|
+
- Use `--no-interactive` to disable inline auth prompts
|
|
181
199
|
- All errors write to stderr as JSON with a `next_action` field
|
|
182
200
|
|
|
183
201
|
**Exit codes:**
|
|
@@ -211,18 +229,18 @@ Run diagnostics to verify CLI health:
|
|
|
211
229
|
dropthis doctor
|
|
212
230
|
```
|
|
213
231
|
|
|
214
|
-
Reports CLI version, auth source (`env`, `flag`, `
|
|
232
|
+
Reports CLI version, auth source (`env`, `flag`, `storage`, or `missing`), and credential storage backend (`secure`, `insecure`, or `none`).
|
|
215
233
|
|
|
216
234
|
```json
|
|
217
|
-
{"ok":true,"version":"0.
|
|
235
|
+
{"ok":true,"version":"0.4.1","auth":{"source":"env"},"storage":{"backend":"secure"}}
|
|
218
236
|
```
|
|
219
237
|
|
|
220
238
|
## Agent skills
|
|
221
239
|
|
|
222
|
-
|
|
240
|
+
For AI coding agents (Cursor, Claude Code, Windsurf, etc.), install the [dropthis-skills](https://github.com/dropthis-dev/dropthis-skills) package:
|
|
223
241
|
|
|
224
242
|
```bash
|
|
225
|
-
npx skills add dropthis-dev/dropthis-
|
|
243
|
+
npx skills add dropthis-dev/dropthis-skills
|
|
226
244
|
```
|
|
227
245
|
|
|
228
246
|
## Links
|
package/dist/cli.cjs
CHANGED
|
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
9
16
|
var __copyProps = (to, from, except, desc) => {
|
|
10
17
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
18
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,6 +30,126 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
30
|
mod
|
|
24
31
|
));
|
|
25
32
|
|
|
33
|
+
// src/inline-auth.ts
|
|
34
|
+
var inline_auth_exports = {};
|
|
35
|
+
__export(inline_auth_exports, {
|
|
36
|
+
runInlineAuth: () => runInlineAuth
|
|
37
|
+
});
|
|
38
|
+
async function runInlineAuth(deps) {
|
|
39
|
+
try {
|
|
40
|
+
const prompt = deps.prompt ?? defaultPrompts();
|
|
41
|
+
deps.stderr("\nNot logged in. Let's fix that:\n");
|
|
42
|
+
const emailResult = await prompt.email();
|
|
43
|
+
if (typeof emailResult === "symbol") {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const email = emailResult;
|
|
47
|
+
const otpRequest = await deps.client.auth.requestEmailOtp({ email });
|
|
48
|
+
if (otpRequest.error) {
|
|
49
|
+
deps.stderr(`${otpRequest.error.message}
|
|
50
|
+
`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
deps.stderr("Code sent! Check your inbox.\n");
|
|
54
|
+
const maxAttempts = 3;
|
|
55
|
+
let session = null;
|
|
56
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
57
|
+
const codeResult = await prompt.code(attempt, maxAttempts);
|
|
58
|
+
if (typeof codeResult === "symbol") {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const code = codeResult;
|
|
62
|
+
const verifyResult = await deps.client.auth.verifyEmailOtp({
|
|
63
|
+
email,
|
|
64
|
+
code
|
|
65
|
+
});
|
|
66
|
+
if (!verifyResult.error) {
|
|
67
|
+
session = verifyResult.data;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
if (attempt < maxAttempts) {
|
|
71
|
+
deps.stderr(`${verifyResult.error.message}
|
|
72
|
+
`);
|
|
73
|
+
} else {
|
|
74
|
+
deps.stderr(
|
|
75
|
+
"Too many attempts. Run `dropthis login` to request a new code.\n"
|
|
76
|
+
);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!session) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const authedClient = deps.createClient(session.token);
|
|
84
|
+
const apiKeyResult = await authedClient.apiKeys.create({
|
|
85
|
+
label: `CLI on ${deps.hostname ?? (0, import_node_os2.hostname)()}`
|
|
86
|
+
});
|
|
87
|
+
if (apiKeyResult.error) {
|
|
88
|
+
deps.stderr(`${apiKeyResult.error.message}
|
|
89
|
+
`);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const { id: keyId, key: apiKey, keyLast4, accountId } = apiKeyResult.data;
|
|
93
|
+
try {
|
|
94
|
+
await deps.store.save({
|
|
95
|
+
apiKey,
|
|
96
|
+
keyId,
|
|
97
|
+
keyLast4,
|
|
98
|
+
accountId: accountId ?? session.accountId,
|
|
99
|
+
email,
|
|
100
|
+
storage: "secure"
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
104
|
+
deps.stderr(`Failed to save credentials: ${message}
|
|
105
|
+
`);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
deps.stderr("\u2713 Logged in\n\n");
|
|
109
|
+
return {
|
|
110
|
+
apiKey,
|
|
111
|
+
source: "storage",
|
|
112
|
+
keyId,
|
|
113
|
+
keyLast4,
|
|
114
|
+
accountId: accountId ?? session.accountId,
|
|
115
|
+
email
|
|
116
|
+
};
|
|
117
|
+
} catch (err) {
|
|
118
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
119
|
+
deps.stderr(`Login failed: ${message}
|
|
120
|
+
`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function defaultPrompts() {
|
|
125
|
+
return {
|
|
126
|
+
email: () => readlineQuestion("Email: "),
|
|
127
|
+
code: (attempt) => readlineQuestion(
|
|
128
|
+
attempt === 1 ? "Code: " : "Try again \u2014 enter the code: "
|
|
129
|
+
)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function readlineQuestion(question) {
|
|
133
|
+
const rl = (0, import_node_readline.createInterface)({
|
|
134
|
+
input: process.stdin,
|
|
135
|
+
output: process.stderr
|
|
136
|
+
});
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
rl.question(question, (answer) => {
|
|
139
|
+
rl.close();
|
|
140
|
+
resolve(answer);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
var import_node_os2, import_node_readline;
|
|
145
|
+
var init_inline_auth = __esm({
|
|
146
|
+
"src/inline-auth.ts"() {
|
|
147
|
+
"use strict";
|
|
148
|
+
import_node_os2 = require("os");
|
|
149
|
+
import_node_readline = require("readline");
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
26
153
|
// src/program.ts
|
|
27
154
|
var import_commander = require("commander");
|
|
28
155
|
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
@@ -400,6 +527,7 @@ var COMMAND_CATALOG = [
|
|
|
400
527
|
arguments: ["input"],
|
|
401
528
|
options: ["--json", "--url", "--dry-run", "--title", "--metadata"],
|
|
402
529
|
examples: [
|
|
530
|
+
"dropthis ./file.html",
|
|
403
531
|
"dropthis publish ./site --json",
|
|
404
532
|
"dropthis publish ./site --url",
|
|
405
533
|
"dropthis publish ./dist --dry-run"
|
|
@@ -561,13 +689,13 @@ async function runDoctor(_input, deps) {
|
|
|
561
689
|
const authSource = credential?.source ?? "missing";
|
|
562
690
|
const storageBackend = stored?.storage ?? "none";
|
|
563
691
|
const pairs = [
|
|
564
|
-
["Version", "0.4.
|
|
692
|
+
["Version", "0.4.1"],
|
|
565
693
|
["Auth", authSource],
|
|
566
694
|
["Storage", storageBackend]
|
|
567
695
|
];
|
|
568
696
|
writeKv(deps, pairs, {
|
|
569
697
|
ok: true,
|
|
570
|
-
version: "0.4.
|
|
698
|
+
version: "0.4.1",
|
|
571
699
|
auth: { source: authSource },
|
|
572
700
|
storage: { backend: storageBackend }
|
|
573
701
|
});
|
|
@@ -997,8 +1125,9 @@ async function readJsonObjectFile(path) {
|
|
|
997
1125
|
|
|
998
1126
|
// src/commands/publish.ts
|
|
999
1127
|
async function runPublish(input, raw, deps) {
|
|
1128
|
+
let credential;
|
|
1000
1129
|
try {
|
|
1001
|
-
await
|
|
1130
|
+
credential = await resolveCredential({
|
|
1002
1131
|
...raw.apiKey ?? deps.apiKey ? { apiKey: raw.apiKey ?? deps.apiKey } : {},
|
|
1003
1132
|
env: deps.env,
|
|
1004
1133
|
store: deps.store
|
|
@@ -1006,8 +1135,26 @@ async function runPublish(input, raw, deps) {
|
|
|
1006
1135
|
} catch {
|
|
1007
1136
|
return writeAuthError(deps);
|
|
1008
1137
|
}
|
|
1138
|
+
let didInlineAuth = false;
|
|
1139
|
+
if (!credential) {
|
|
1140
|
+
if (deps.interactive && deps.inlineAuth) {
|
|
1141
|
+
try {
|
|
1142
|
+
credential = await deps.inlineAuth();
|
|
1143
|
+
} catch {
|
|
1144
|
+
return writeAuthError(deps);
|
|
1145
|
+
}
|
|
1146
|
+
if (!credential) return writeAuthError(deps);
|
|
1147
|
+
didInlineAuth = true;
|
|
1148
|
+
} else {
|
|
1149
|
+
return writeAuthError(deps);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
let client = deps.client;
|
|
1153
|
+
if (didInlineAuth && deps.createClient) {
|
|
1154
|
+
client = deps.createClient(credential.apiKey);
|
|
1155
|
+
}
|
|
1009
1156
|
if (raw.dryRun) {
|
|
1010
|
-
return handlePublishDryRun(input, raw, deps);
|
|
1157
|
+
return handlePublishDryRun(input, raw, deps, client);
|
|
1011
1158
|
}
|
|
1012
1159
|
const singleInput = Array.isArray(input) ? input[0] : input;
|
|
1013
1160
|
const spin = shouldSpin(deps.outputMode) ? createSpinner("Publishing\u2026", deps.stderr) : void 0;
|
|
@@ -1016,13 +1163,44 @@ async function runPublish(input, raw, deps) {
|
|
|
1016
1163
|
throw new Error("Use either <input> or --from-json, not both.");
|
|
1017
1164
|
}
|
|
1018
1165
|
const options = withIdempotencyKey(await parseDropOptions(raw), "pub");
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
) : singleInput ? await deps.client.publish(singleInput, options) : (() => {
|
|
1166
|
+
const jsonBody = raw.fromJson ? await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson) : void 0;
|
|
1167
|
+
const idempotencyOpt = options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {};
|
|
1168
|
+
const doPublish = (c) => jsonBody ? c.drops.createRaw(jsonBody, idempotencyOpt) : singleInput ? c.publish(singleInput, options) : (() => {
|
|
1023
1169
|
throw new Error("Publish requires <input> or --from-json.");
|
|
1024
1170
|
})();
|
|
1171
|
+
const result = await doPublish(client);
|
|
1025
1172
|
if (result.error) {
|
|
1173
|
+
if (result.error.statusCode === 401 && deps.interactive && deps.inlineAuth && !didInlineAuth) {
|
|
1174
|
+
spin?.stop();
|
|
1175
|
+
const newCredential = await deps.inlineAuth();
|
|
1176
|
+
if (newCredential && deps.createClient) {
|
|
1177
|
+
client = deps.createClient(newCredential.apiKey);
|
|
1178
|
+
const retrySpin = shouldSpin(deps.outputMode) ? createSpinner("Publishing\u2026", deps.stderr) : void 0;
|
|
1179
|
+
try {
|
|
1180
|
+
const retryResult = await doPublish(client);
|
|
1181
|
+
if (retryResult.error) {
|
|
1182
|
+
retrySpin?.fail();
|
|
1183
|
+
return writeApiError(deps, retryResult.error);
|
|
1184
|
+
}
|
|
1185
|
+
retrySpin?.stop();
|
|
1186
|
+
if (raw.url) deps.stdout(`${retryResult.data.url}
|
|
1187
|
+
`);
|
|
1188
|
+
else
|
|
1189
|
+
writeResult(
|
|
1190
|
+
deps,
|
|
1191
|
+
retryResult.data.url,
|
|
1192
|
+
"Published",
|
|
1193
|
+
retryResult.data
|
|
1194
|
+
);
|
|
1195
|
+
return { exitCode: 0 };
|
|
1196
|
+
} catch (retryError) {
|
|
1197
|
+
retrySpin?.fail();
|
|
1198
|
+
const message = retryError instanceof Error ? retryError.message : "Publish failed.";
|
|
1199
|
+
const code = isFileSystemError(retryError) ? "local_input_error" : "invalid_usage";
|
|
1200
|
+
return writeError(deps, code, message);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1026
1204
|
spin?.fail();
|
|
1027
1205
|
return writeApiError(deps, result.error);
|
|
1028
1206
|
}
|
|
@@ -1038,7 +1216,7 @@ async function runPublish(input, raw, deps) {
|
|
|
1038
1216
|
return writeError(deps, code, message);
|
|
1039
1217
|
}
|
|
1040
1218
|
}
|
|
1041
|
-
async function handlePublishDryRun(input, raw, deps) {
|
|
1219
|
+
async function handlePublishDryRun(input, raw, deps, client) {
|
|
1042
1220
|
if (raw.url) {
|
|
1043
1221
|
return writeError(
|
|
1044
1222
|
deps,
|
|
@@ -1067,10 +1245,10 @@ async function handlePublishDryRun(input, raw, deps) {
|
|
|
1067
1245
|
if (Array.isArray(input)) {
|
|
1068
1246
|
return dryRunMultiFile(input, options, deps);
|
|
1069
1247
|
}
|
|
1070
|
-
if (!
|
|
1248
|
+
if (!client.prepare) {
|
|
1071
1249
|
throw new Error("Client does not support dry-run.");
|
|
1072
1250
|
}
|
|
1073
|
-
const prepared = await
|
|
1251
|
+
const prepared = await client.prepare(input, options);
|
|
1074
1252
|
const output = formatDryRunManifest(prepared);
|
|
1075
1253
|
validateManifestFileCount(
|
|
1076
1254
|
output.manifest.files.length
|
|
@@ -1402,11 +1580,13 @@ async function readJsonFile(path) {
|
|
|
1402
1580
|
}
|
|
1403
1581
|
async function writeCredentialFile(path, credential) {
|
|
1404
1582
|
await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
|
|
1405
|
-
|
|
1583
|
+
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
1584
|
+
await (0, import_promises4.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
|
|
1406
1585
|
`, {
|
|
1407
1586
|
mode: 384
|
|
1408
1587
|
});
|
|
1409
|
-
await (0, import_promises4.chmod)(
|
|
1588
|
+
await (0, import_promises4.chmod)(tmpPath, 384);
|
|
1589
|
+
await (0, import_promises4.rename)(tmpPath, path);
|
|
1410
1590
|
}
|
|
1411
1591
|
|
|
1412
1592
|
// src/program.ts
|
|
@@ -1421,7 +1601,7 @@ function buildProgram(options = {}) {
|
|
|
1421
1601
|
` ${import_picocolors4.default.cyan("dropthis login")}`,
|
|
1422
1602
|
` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
|
|
1423
1603
|
].join("\n")
|
|
1424
|
-
).version("0.4.
|
|
1604
|
+
).version("0.4.1").configureHelp({
|
|
1425
1605
|
subcommandTerm(cmd) {
|
|
1426
1606
|
const args = cmd.registeredArguments.map((a) => {
|
|
1427
1607
|
const name = a.name();
|
|
@@ -1439,7 +1619,8 @@ function buildProgram(options = {}) {
|
|
|
1439
1619
|
program.option("--api-url <url>", "Override API base URL");
|
|
1440
1620
|
program.option("--json", "Force JSON output");
|
|
1441
1621
|
program.option("-q, --quiet", "Suppress status output and imply JSON");
|
|
1442
|
-
program.
|
|
1622
|
+
program.option("--no-interactive", "Disable interactive prompts");
|
|
1623
|
+
program.command("publish [input...]", { isDefault: true }).description(
|
|
1443
1624
|
"Publish files, folders, URLs, strings, or stdin.\nMultiple files are bundled into one drop.\nUse - to read stdin explicitly, or pipe without args."
|
|
1444
1625
|
).option("--title <title>", "Drop title").option("--visibility <v>", "public or unlisted (default: public)").option("--password <password>", "Require password to view").option("--noindex", "Prevent search-engine indexing").option("--expires-at <datetime>", "Auto-delete after this ISO 8601 date").option(
|
|
1445
1626
|
"--content-type <mime>",
|
|
@@ -1454,8 +1635,18 @@ function buildProgram(options = {}) {
|
|
|
1454
1635
|
"--idempotency-key <key>",
|
|
1455
1636
|
"Prevent duplicate publishes on retry (auto-generated)"
|
|
1456
1637
|
).action(async (inputs, commandOptions) => {
|
|
1457
|
-
const deps = await commandDeps(program, options, store, commandOptions);
|
|
1458
1638
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
1639
|
+
if (inputs.length === 0 && stdinIsTTY && !commandOptions.fromJson) {
|
|
1640
|
+
program.outputHelp();
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
const { deps } = await buildPublishDeps(
|
|
1644
|
+
program,
|
|
1645
|
+
options,
|
|
1646
|
+
store,
|
|
1647
|
+
commandOptions,
|
|
1648
|
+
stdinIsTTY
|
|
1649
|
+
);
|
|
1459
1650
|
let publishInput;
|
|
1460
1651
|
try {
|
|
1461
1652
|
if (commandOptions.dryRun && inputs.length > 1) {
|
|
@@ -1544,10 +1735,15 @@ function buildProgram(options = {}) {
|
|
|
1544
1735
|
);
|
|
1545
1736
|
drops.command("delete <dropId>").description("Delete a drop").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
|
|
1546
1737
|
async (dropId, commandOptions) => {
|
|
1738
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
1739
|
+
const global = globalOptions(program, commandOptions);
|
|
1547
1740
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
1548
1741
|
const result = await runDropsDelete(
|
|
1549
1742
|
dropId,
|
|
1550
|
-
{
|
|
1743
|
+
{
|
|
1744
|
+
...commandOptions,
|
|
1745
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
1746
|
+
},
|
|
1551
1747
|
deps
|
|
1552
1748
|
);
|
|
1553
1749
|
process.exitCode = result.exitCode;
|
|
@@ -1566,10 +1762,15 @@ function buildProgram(options = {}) {
|
|
|
1566
1762
|
});
|
|
1567
1763
|
apiKeys.command("delete <keyId>").description("Delete an API key").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
|
|
1568
1764
|
async (keyId, commandOptions) => {
|
|
1765
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
1766
|
+
const global = globalOptions(program, commandOptions);
|
|
1569
1767
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
1570
1768
|
const result = await runApiKeysDelete(
|
|
1571
1769
|
keyId,
|
|
1572
|
-
{
|
|
1770
|
+
{
|
|
1771
|
+
...commandOptions,
|
|
1772
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
1773
|
+
},
|
|
1573
1774
|
deps
|
|
1574
1775
|
);
|
|
1575
1776
|
process.exitCode = result.exitCode;
|
|
@@ -1714,13 +1915,56 @@ async function commandDeps(program, options, store, commandOptions) {
|
|
|
1714
1915
|
outputMode: context.output.mode
|
|
1715
1916
|
};
|
|
1716
1917
|
}
|
|
1918
|
+
async function buildPublishDeps(program, options, store, commandOptions, stdinIsTTY) {
|
|
1919
|
+
const global = globalOptions(program, commandOptions);
|
|
1920
|
+
const context = createContext({
|
|
1921
|
+
global,
|
|
1922
|
+
...options.env !== void 0 ? { env: options.env } : {},
|
|
1923
|
+
...options.stdout !== void 0 ? { stdout: options.stdout } : {},
|
|
1924
|
+
...options.stderr !== void 0 ? { stderr: options.stderr } : {},
|
|
1925
|
+
...options.stdoutIsTTY !== void 0 ? { stdoutIsTTY: options.stdoutIsTTY } : {}
|
|
1926
|
+
});
|
|
1927
|
+
const credential = await resolveCredential({
|
|
1928
|
+
...global.apiKey ? { apiKey: global.apiKey } : {},
|
|
1929
|
+
env: context.env,
|
|
1930
|
+
store
|
|
1931
|
+
});
|
|
1932
|
+
const interactive = isInteractive(stdinIsTTY, context.env, global);
|
|
1933
|
+
const inlineAuth = async () => {
|
|
1934
|
+
const { runInlineAuth: runInlineAuth2 } = await Promise.resolve().then(() => (init_inline_auth(), inline_auth_exports));
|
|
1935
|
+
return runInlineAuth2({
|
|
1936
|
+
client: context.createClient(),
|
|
1937
|
+
createClient: (apiKey) => context.createClient(apiKey),
|
|
1938
|
+
store,
|
|
1939
|
+
stderr: context.stderr
|
|
1940
|
+
});
|
|
1941
|
+
};
|
|
1942
|
+
return {
|
|
1943
|
+
deps: {
|
|
1944
|
+
store,
|
|
1945
|
+
client: options.client ?? context.createClient(credential?.apiKey),
|
|
1946
|
+
...global.apiKey ? { apiKey: global.apiKey } : {},
|
|
1947
|
+
env: context.env,
|
|
1948
|
+
stdout: context.stdout,
|
|
1949
|
+
stderr: context.stderr,
|
|
1950
|
+
outputMode: context.output.mode,
|
|
1951
|
+
interactive,
|
|
1952
|
+
inlineAuth,
|
|
1953
|
+
createClient: (apiKey) => context.createClient(apiKey)
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
function isInteractive(stdinIsTTY, env, global) {
|
|
1958
|
+
return stdinIsTTY && !env.CI && !env.DROPTHIS_NON_INTERACTIVE && global.interactive !== false;
|
|
1959
|
+
}
|
|
1717
1960
|
function globalOptions(program, commandOptions) {
|
|
1718
1961
|
const opts = program.opts();
|
|
1719
1962
|
return {
|
|
1720
1963
|
...opts.apiKey ? { apiKey: opts.apiKey } : {},
|
|
1721
1964
|
...opts.apiUrl ? { apiUrl: opts.apiUrl } : {},
|
|
1722
1965
|
...commandOptions.json !== void 0 ? { json: commandOptions.json } : opts.json !== void 0 ? { json: opts.json } : {},
|
|
1723
|
-
...commandOptions.quiet !== void 0 ? { quiet: commandOptions.quiet } : opts.quiet !== void 0 ? { quiet: opts.quiet } : {}
|
|
1966
|
+
...commandOptions.quiet !== void 0 ? { quiet: commandOptions.quiet } : opts.quiet !== void 0 ? { quiet: opts.quiet } : {},
|
|
1967
|
+
...opts.interactive !== void 0 ? { interactive: opts.interactive } : {}
|
|
1724
1968
|
};
|
|
1725
1969
|
}
|
|
1726
1970
|
function toDropOptions(options) {
|