@dropthis/cli 0.9.2 → 0.10.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/README.md +69 -30
- package/dist/cli.cjs +147 -17
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +99 -7
- package/node_modules/@dropthis/node/dist/{drops-BWA0D1IW.d.cts → drops-D0MLPPF9.d.cts} +106 -15
- package/node_modules/@dropthis/node/dist/{drops-BWA0D1IW.d.ts → drops-D0MLPPF9.d.ts} +106 -15
- package/node_modules/@dropthis/node/dist/edge.cjs +219 -38
- package/node_modules/@dropthis/node/dist/edge.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.cts +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.ts +1 -1
- package/node_modules/@dropthis/node/dist/edge.mjs +219 -38
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +226 -40
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +10 -7
- package/node_modules/@dropthis/node/dist/index.d.ts +10 -7
- package/node_modules/@dropthis/node/dist/index.mjs +226 -40
- 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
package/README.md
CHANGED
|
@@ -88,18 +88,19 @@ dropthis ./dist --url
|
|
|
88
88
|
dropthis publish ./dist \
|
|
89
89
|
--title "Launch page" \
|
|
90
90
|
--visibility unlisted \
|
|
91
|
-
--password s3cret \
|
|
92
91
|
--entry index.html \
|
|
93
92
|
--expires-at 2026-12-31T00:00:00Z
|
|
94
93
|
```
|
|
95
94
|
|
|
95
|
+
`publish` always creates a NEW drop with a new URL. To change a drop you already published, use `update-content` or `update-settings` with its `drop_…` id — never publish again.
|
|
96
|
+
|
|
96
97
|
All publish flags:
|
|
97
98
|
|
|
98
99
|
| Flag | Description |
|
|
99
100
|
|------|-------------|
|
|
100
101
|
| `--title <title>` | Drop title |
|
|
101
102
|
| `--visibility <public\|unlisted>` | Drop visibility |
|
|
102
|
-
| `--password <password>` | Set password protection |
|
|
103
|
+
| `--password <password>` | Set password protection (ships with Pro; not enabled on any tier yet) |
|
|
103
104
|
| `--noindex` | Prevent search indexing |
|
|
104
105
|
| `--entry <path>` | Entry file for directories |
|
|
105
106
|
| `--content-type <mime>` | MIME type (required for stdin) |
|
|
@@ -126,48 +127,78 @@ These flags are inherited by all commands:
|
|
|
126
127
|
|
|
127
128
|
## Update
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
Change an existing drop without creating a new URL. Content and settings are **separate** operations — pass the full `drop_…` id (not the slug):
|
|
130
131
|
|
|
131
132
|
```bash
|
|
132
|
-
# Replace content
|
|
133
|
-
dropthis
|
|
133
|
+
# Replace the content at the same URL (ships a new deployment)
|
|
134
|
+
dropthis update-content drop_abc123 ./dist-v2
|
|
135
|
+
|
|
136
|
+
# Change settings only — title, visibility, password, expiry, metadata
|
|
137
|
+
dropthis update-settings drop_abc123 --title "New title"
|
|
138
|
+
|
|
139
|
+
# Optimistic concurrency (both accept --if-revision)
|
|
140
|
+
dropthis update-content drop_abc123 ./dist-v2 --if-revision 1
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`update-content` replaces the files at the URL; `update-settings` changes title, visibility, password, noindex, expiry, or metadata. Creating a new drop is always `publish` — neither update command makes a new URL.
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
dropthis drops update drop_abc123 --title "New title"
|
|
145
|
+
With `--if-revision`, a concurrent edit fails with a 409 instead of clobbering. The error shows the drop's `current_revision` and how to retry:
|
|
137
146
|
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
```text
|
|
148
|
+
✗ Revision mismatch
|
|
149
|
+
The drop changed since it was last read. Re-read it with GET /v1/drops/{drop_id} and retry with if_revision: 2 (sent as the If-Revision header).
|
|
150
|
+
Current revision: 2 — retry with --if-revision 2
|
|
140
151
|
```
|
|
141
152
|
|
|
142
|
-
|
|
153
|
+
In JSON mode the same error carries `current_revision` and a `next_action` field.
|
|
154
|
+
|
|
155
|
+
## Pull (read back)
|
|
156
|
+
|
|
157
|
+
Download what a drop is serving — by `drop_…` id, drop URL, or slug. URLs and slugs are resolved to your own drops; the local copy is also the rollback path (pull an old state, then `update-content` it back):
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# By id, into ./drop_abc123/
|
|
161
|
+
dropthis pull drop_abc123
|
|
162
|
+
|
|
163
|
+
# By URL — resolves the slug to your drop, writes into ./abc123/
|
|
164
|
+
dropthis pull https://abc123.dropthis.app
|
|
165
|
+
|
|
166
|
+
# Choose the output directory
|
|
167
|
+
dropthis pull drop_abc123 -o ./site
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Pull fetches the current deployment's file manifest and writes every file into the output directory. It is owner-side read-back via the API — it works regardless of any viewer password. Custom-domain URLs are not resolvable yet; use the `drop_…` id instead.
|
|
143
171
|
|
|
144
172
|
## Commands
|
|
145
173
|
|
|
146
174
|
```bash
|
|
147
|
-
dropthis [input...]
|
|
148
|
-
dropthis publish [input...]
|
|
175
|
+
dropthis [input...] # Publish content (default command)
|
|
176
|
+
dropthis publish [input...] # Same as above, explicit form
|
|
149
177
|
|
|
150
|
-
dropthis
|
|
151
|
-
dropthis
|
|
152
|
-
dropthis
|
|
153
|
-
dropthis
|
|
178
|
+
dropthis update-content <drop-id> [input] # Replace a drop's content (same URL)
|
|
179
|
+
dropthis update-settings <drop-id> # Change title/visibility/password/expiry/metadata
|
|
180
|
+
dropthis pull <id|url> [-o <dir>] # Download a drop's files to a local directory
|
|
181
|
+
dropthis get <drop-id> # Show drop details
|
|
182
|
+
dropthis list # List your drops
|
|
183
|
+
dropthis delete <drop-id> # Delete a drop (--yes to confirm)
|
|
154
184
|
|
|
155
|
-
dropthis
|
|
156
|
-
dropthis login request --email <email> # Request OTP (non-interactive)
|
|
157
|
-
dropthis login verify --email <email> --otp <code> # Verify OTP
|
|
158
|
-
dropthis logout # Remove stored credentials
|
|
159
|
-
dropthis whoami # Show current auth status
|
|
160
|
-
dropthis account # Account details
|
|
185
|
+
dropthis deployments # View deployment history
|
|
161
186
|
|
|
162
|
-
dropthis
|
|
163
|
-
dropthis
|
|
164
|
-
dropthis
|
|
187
|
+
dropthis login # Authenticate with email OTP
|
|
188
|
+
dropthis login request --email <email> # Request OTP (non-interactive)
|
|
189
|
+
dropthis login verify --email <email> --otp <code> # Verify OTP
|
|
190
|
+
dropthis logout # Remove stored credentials
|
|
191
|
+
dropthis whoami # Show current auth status
|
|
165
192
|
|
|
166
|
-
dropthis
|
|
167
|
-
dropthis
|
|
193
|
+
dropthis account # Show account details
|
|
194
|
+
dropthis account update --display-name <name> # Update your display name
|
|
168
195
|
|
|
169
|
-
dropthis
|
|
170
|
-
dropthis
|
|
196
|
+
dropthis api-keys create # Create an API key
|
|
197
|
+
dropthis api-keys list # List API keys
|
|
198
|
+
dropthis api-keys delete <key-id> # Delete an API key (--yes to confirm)
|
|
199
|
+
|
|
200
|
+
dropthis doctor # CLI diagnostics
|
|
201
|
+
dropthis commands # Machine-readable command metadata
|
|
171
202
|
```
|
|
172
203
|
|
|
173
204
|
## Agent & CI/CD usage
|
|
@@ -190,7 +221,7 @@ dropthis publish ./dist --url
|
|
|
190
221
|
|
|
191
222
|
- Use `--url` to get only the published URL (cleanest for agents)
|
|
192
223
|
- Use `--json` for the full structured response
|
|
193
|
-
- Use `--yes` for destructive commands (`
|
|
224
|
+
- Use `--yes` for destructive commands (`delete`, `api-keys delete`, `account delete`)
|
|
194
225
|
- Use `--no-interactive` to disable inline auth prompts
|
|
195
226
|
- All errors write to stderr as JSON with a `next_action` field
|
|
196
227
|
|
|
@@ -231,6 +262,14 @@ Reports CLI version, auth source (`env`, `flag`, `storage`, or `missing`), and c
|
|
|
231
262
|
{"ok":true,"version":"0.4.1","auth":{"source":"env"},"storage":{"backend":"secure"}}
|
|
232
263
|
```
|
|
233
264
|
|
|
265
|
+
## Pricing tiers
|
|
266
|
+
|
|
267
|
+
- **Free ($0)** — drops expire after 7 days, 5 MB per drop, dropthis badge.
|
|
268
|
+
- **Personal ($5/mo)** — drops stay live while subscribed (no expiry), no badge, 100 MB per drop, 2 GB account storage.
|
|
269
|
+
- **Pro ($19/mo)** — everything in Personal plus password protection, custom domains, and analytics.
|
|
270
|
+
|
|
271
|
+
`dropthis account` shows your active tier and its limits. Note: password protection ships with Pro and is not enabled on any tier yet — the API rejects the `--password` option until then.
|
|
272
|
+
|
|
234
273
|
## Agent skills
|
|
235
274
|
|
|
236
275
|
For AI coding agents (Cursor, Claude Code, Windsurf, etc.), install the [dropthis-skills](https://github.com/dropthis-dev/dropthis-skills) package:
|
package/dist/cli.cjs
CHANGED
|
@@ -135,10 +135,10 @@ function readlineQuestion(question) {
|
|
|
135
135
|
input: process.stdin,
|
|
136
136
|
output: process.stderr
|
|
137
137
|
});
|
|
138
|
-
return new Promise((
|
|
138
|
+
return new Promise((resolve2) => {
|
|
139
139
|
rl.question(question, (answer) => {
|
|
140
140
|
rl.close();
|
|
141
|
-
|
|
141
|
+
resolve2(answer);
|
|
142
142
|
});
|
|
143
143
|
});
|
|
144
144
|
}
|
|
@@ -207,7 +207,7 @@ function nextActionForApiError(error2) {
|
|
|
207
207
|
const uploadNextAction = error2.code ? UPLOAD_NEXT_ACTIONS[error2.code] : void 0;
|
|
208
208
|
if (uploadNextAction) return uploadNextAction;
|
|
209
209
|
if (error2.code === "revision_conflict") {
|
|
210
|
-
return "
|
|
210
|
+
return "Re-read the drop with dropthis get <drop-id>, merge your changes, and retry with --if-revision set to the current revision.";
|
|
211
211
|
}
|
|
212
212
|
if (error2.statusCode === 404 || error2.code === "not_found") {
|
|
213
213
|
return "Check the drop id or slug and retry; list your drops with dropthis list.";
|
|
@@ -371,6 +371,11 @@ function writeApiError(deps, details) {
|
|
|
371
371
|
const nextAction = nextActionForApiError(details);
|
|
372
372
|
if (nextAction) deps.stderr(`${hint(nextAction)}
|
|
373
373
|
`);
|
|
374
|
+
if (details.currentRevision !== void 0)
|
|
375
|
+
deps.stderr(
|
|
376
|
+
`${hint(`Current revision: ${details.currentRevision} \u2014 retry with --if-revision ${details.currentRevision}`)}
|
|
377
|
+
`
|
|
378
|
+
);
|
|
374
379
|
if (details.requestId)
|
|
375
380
|
deps.stderr(`${import_picocolors2.default.dim(`Request ID: ${details.requestId}`)}
|
|
376
381
|
`);
|
|
@@ -605,6 +610,13 @@ var COMMAND_ANNOTATIONS = {
|
|
|
605
610
|
auth: "required",
|
|
606
611
|
examples: ["dropthis update-settings drop_abc --title 'Launch' --json"]
|
|
607
612
|
},
|
|
613
|
+
pull: {
|
|
614
|
+
auth: "required",
|
|
615
|
+
examples: [
|
|
616
|
+
"dropthis pull drop_abc -o ./site",
|
|
617
|
+
"dropthis pull https://abc123.dropthis.app"
|
|
618
|
+
]
|
|
619
|
+
},
|
|
608
620
|
get: {
|
|
609
621
|
auth: "required",
|
|
610
622
|
examples: ["dropthis get drop_abc --json"]
|
|
@@ -769,13 +781,13 @@ async function runDoctor(_input, deps) {
|
|
|
769
781
|
const authSource = credential?.source ?? "missing";
|
|
770
782
|
const storageBackend = stored?.storage ?? "none";
|
|
771
783
|
const pairs = [
|
|
772
|
-
["Version", "0.
|
|
784
|
+
["Version", "0.10.0"],
|
|
773
785
|
["Auth", authSource],
|
|
774
786
|
["Storage", storageBackend]
|
|
775
787
|
];
|
|
776
788
|
writeKv(deps, pairs, {
|
|
777
789
|
ok: true,
|
|
778
|
-
version: "0.
|
|
790
|
+
version: "0.10.0",
|
|
779
791
|
auth: { source: authSource },
|
|
780
792
|
storage: { backend: storageBackend }
|
|
781
793
|
});
|
|
@@ -1274,6 +1286,110 @@ async function handlePublishDryRun(input, raw, deps, client) {
|
|
|
1274
1286
|
}
|
|
1275
1287
|
}
|
|
1276
1288
|
|
|
1289
|
+
// src/commands/pull.ts
|
|
1290
|
+
var import_promises2 = require("fs/promises");
|
|
1291
|
+
var import_node_path = require("path");
|
|
1292
|
+
async function runPull(target, input, deps) {
|
|
1293
|
+
try {
|
|
1294
|
+
await requireCredential({
|
|
1295
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1296
|
+
env: deps.env,
|
|
1297
|
+
store: deps.store
|
|
1298
|
+
});
|
|
1299
|
+
} catch {
|
|
1300
|
+
return writeAuthError(deps);
|
|
1301
|
+
}
|
|
1302
|
+
let dropId;
|
|
1303
|
+
let defaultDirName;
|
|
1304
|
+
if (target.startsWith("drop_")) {
|
|
1305
|
+
dropId = target;
|
|
1306
|
+
defaultDirName = target;
|
|
1307
|
+
} else {
|
|
1308
|
+
const resolved = await deps.client.drops.resolve(target);
|
|
1309
|
+
if (resolved.error) return writeApiError(deps, resolved.error);
|
|
1310
|
+
if (resolved.data === null) {
|
|
1311
|
+
return writeApiError(deps, {
|
|
1312
|
+
code: "not_found",
|
|
1313
|
+
message: `No drop matching "${target}" found in your account.`,
|
|
1314
|
+
suggestion: "It may belong to another account or have been deleted. Run dropthis list to see your drops, or pass the full drop_\u2026 id."
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
dropId = resolved.data.id;
|
|
1318
|
+
defaultDirName = resolved.data.slug || resolved.data.id;
|
|
1319
|
+
}
|
|
1320
|
+
const spin = shouldSpin(deps.outputMode) ? createSpinner("Pulling content\u2026", deps.stderr) : void 0;
|
|
1321
|
+
const manifestResult = await deps.client.drops.getContent(dropId);
|
|
1322
|
+
if (manifestResult.error) {
|
|
1323
|
+
spin?.fail();
|
|
1324
|
+
return writeApiError(deps, manifestResult.error);
|
|
1325
|
+
}
|
|
1326
|
+
const manifest = manifestResult.data;
|
|
1327
|
+
const outDir = (0, import_node_path.resolve)(
|
|
1328
|
+
deps.cwd ?? process.cwd(),
|
|
1329
|
+
input.output ?? defaultDirName
|
|
1330
|
+
);
|
|
1331
|
+
let destinations;
|
|
1332
|
+
try {
|
|
1333
|
+
destinations = manifest.files.map((file) => ({
|
|
1334
|
+
path: file.path,
|
|
1335
|
+
dest: safeDestination(outDir, file.path)
|
|
1336
|
+
}));
|
|
1337
|
+
} catch (error2) {
|
|
1338
|
+
spin?.fail();
|
|
1339
|
+
const message = error2 instanceof Error ? error2.message : "Invalid manifest path.";
|
|
1340
|
+
return writeError(deps, "local_input_error", message);
|
|
1341
|
+
}
|
|
1342
|
+
try {
|
|
1343
|
+
await (0, import_promises2.mkdir)(outDir, { recursive: true });
|
|
1344
|
+
for (const { path, dest } of destinations) {
|
|
1345
|
+
const fileResult = await deps.client.drops.getContent(dropId, { path });
|
|
1346
|
+
if (fileResult.error) {
|
|
1347
|
+
spin?.fail();
|
|
1348
|
+
return writeApiError(deps, {
|
|
1349
|
+
...fileResult.error,
|
|
1350
|
+
message: `${path}: ${fileResult.error.message}`
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
const file = fileResult.data;
|
|
1354
|
+
await (0, import_promises2.mkdir)((0, import_node_path.dirname)(dest), { recursive: true });
|
|
1355
|
+
await (0, import_promises2.writeFile)(dest, file.bytes);
|
|
1356
|
+
}
|
|
1357
|
+
} catch (error2) {
|
|
1358
|
+
spin?.fail();
|
|
1359
|
+
const message = error2 instanceof Error ? error2.message : "Failed to write files.";
|
|
1360
|
+
return writeError(deps, "local_input_error", message);
|
|
1361
|
+
}
|
|
1362
|
+
spin?.stop();
|
|
1363
|
+
const count = manifest.files.length;
|
|
1364
|
+
writeHumanOrJson(
|
|
1365
|
+
deps,
|
|
1366
|
+
success(`Pulled ${count} ${count === 1 ? "file" : "files"} to ${outDir}`),
|
|
1367
|
+
{
|
|
1368
|
+
ok: true,
|
|
1369
|
+
pulled: {
|
|
1370
|
+
dropId: manifest.dropId,
|
|
1371
|
+
deploymentId: manifest.deploymentId,
|
|
1372
|
+
revision: manifest.revision,
|
|
1373
|
+
...manifest.entry !== void 0 ? { entry: manifest.entry } : {},
|
|
1374
|
+
dir: outDir,
|
|
1375
|
+
files: manifest.files
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
);
|
|
1379
|
+
return { exitCode: 0 };
|
|
1380
|
+
}
|
|
1381
|
+
function safeDestination(outDir, filePath) {
|
|
1382
|
+
if (!filePath || (0, import_node_path.isAbsolute)(filePath)) {
|
|
1383
|
+
throw new Error(`Unsafe file path in content manifest: "${filePath}"`);
|
|
1384
|
+
}
|
|
1385
|
+
const dest = (0, import_node_path.join)(outDir, filePath);
|
|
1386
|
+
const rel = (0, import_node_path.relative)(outDir, dest);
|
|
1387
|
+
if (rel.startsWith("..") || (0, import_node_path.isAbsolute)(rel)) {
|
|
1388
|
+
throw new Error(`Unsafe file path in content manifest: "${filePath}"`);
|
|
1389
|
+
}
|
|
1390
|
+
return dest;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1277
1393
|
// src/commands/update-content.ts
|
|
1278
1394
|
var NO_CONTENT_MESSAGE = "update-content requires content. Provide a file, folder, URL, or text to ship a new deployment.";
|
|
1279
1395
|
var NO_CONTENT_NEXT_ACTION = "Pass an input, e.g. dropthis update-content <dropId> ./dist. To change title, visibility, password, expiry, or metadata, use dropthis update-settings <dropId> instead.";
|
|
@@ -1691,9 +1807,9 @@ function createContext(input) {
|
|
|
1691
1807
|
}
|
|
1692
1808
|
|
|
1693
1809
|
// src/storage.ts
|
|
1694
|
-
var
|
|
1810
|
+
var import_promises3 = require("fs/promises");
|
|
1695
1811
|
var import_node_os = require("os");
|
|
1696
|
-
var
|
|
1812
|
+
var import_node_path2 = require("path");
|
|
1697
1813
|
var import_keyring = require("@napi-rs/keyring");
|
|
1698
1814
|
var MemoryCredentialStore = class {
|
|
1699
1815
|
credential = null;
|
|
@@ -1725,7 +1841,7 @@ var InsecureFileCredentialStore = class {
|
|
|
1725
1841
|
});
|
|
1726
1842
|
}
|
|
1727
1843
|
async clear() {
|
|
1728
|
-
await (0,
|
|
1844
|
+
await (0, import_promises3.rm)(this.filePath, { force: true });
|
|
1729
1845
|
}
|
|
1730
1846
|
};
|
|
1731
1847
|
var KeyringCredentialStore = class {
|
|
@@ -1752,7 +1868,7 @@ var KeyringCredentialStore = class {
|
|
|
1752
1868
|
}
|
|
1753
1869
|
async clear() {
|
|
1754
1870
|
await this.keyring.deletePassword();
|
|
1755
|
-
await (0,
|
|
1871
|
+
await (0, import_promises3.rm)(this.filePath, { force: true });
|
|
1756
1872
|
}
|
|
1757
1873
|
};
|
|
1758
1874
|
function createCredentialStore(options = {}) {
|
|
@@ -1770,14 +1886,14 @@ function defaultKeyringAdapter() {
|
|
|
1770
1886
|
};
|
|
1771
1887
|
}
|
|
1772
1888
|
function credentialPath(configDir) {
|
|
1773
|
-
return (0,
|
|
1774
|
-
configDir ?? (0,
|
|
1889
|
+
return (0, import_node_path2.join)(
|
|
1890
|
+
configDir ?? (0, import_node_path2.join)((0, import_node_os.homedir)(), ".config", "dropthis"),
|
|
1775
1891
|
"credentials.json"
|
|
1776
1892
|
);
|
|
1777
1893
|
}
|
|
1778
1894
|
async function readJsonFile(path) {
|
|
1779
1895
|
try {
|
|
1780
|
-
return JSON.parse(await (0,
|
|
1896
|
+
return JSON.parse(await (0, import_promises3.readFile)(path, "utf8"));
|
|
1781
1897
|
} catch (error2) {
|
|
1782
1898
|
if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
|
|
1783
1899
|
return null;
|
|
@@ -1786,14 +1902,14 @@ async function readJsonFile(path) {
|
|
|
1786
1902
|
}
|
|
1787
1903
|
}
|
|
1788
1904
|
async function writeCredentialFile(path, credential) {
|
|
1789
|
-
await (0,
|
|
1905
|
+
await (0, import_promises3.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
1790
1906
|
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
1791
|
-
await (0,
|
|
1907
|
+
await (0, import_promises3.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
|
|
1792
1908
|
`, {
|
|
1793
1909
|
mode: 384
|
|
1794
1910
|
});
|
|
1795
|
-
await (0,
|
|
1796
|
-
await (0,
|
|
1911
|
+
await (0, import_promises3.chmod)(tmpPath, 384);
|
|
1912
|
+
await (0, import_promises3.rename)(tmpPath, path);
|
|
1797
1913
|
}
|
|
1798
1914
|
|
|
1799
1915
|
// src/program.ts
|
|
@@ -1822,7 +1938,7 @@ function buildProgram(options = {}) {
|
|
|
1822
1938
|
` ${import_picocolors4.default.cyan("dropthis login")}`,
|
|
1823
1939
|
` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
|
|
1824
1940
|
].join("\n")
|
|
1825
|
-
).version("0.
|
|
1941
|
+
).version("0.10.0").configureHelp({
|
|
1826
1942
|
subcommandTerm(cmd) {
|
|
1827
1943
|
const args = cmd.registeredArguments.map((a) => {
|
|
1828
1944
|
const name = a.name();
|
|
@@ -1984,6 +2100,20 @@ function buildProgram(options = {}) {
|
|
|
1984
2100
|
process.exitCode = result.exitCode;
|
|
1985
2101
|
}
|
|
1986
2102
|
);
|
|
2103
|
+
program.command("pull <target>").description(
|
|
2104
|
+
"Download a drop's files into a local directory (accepts the drop_\u2026 id, the drop URL, or its slug).\nFetches the current deployment's file manifest and writes every file. Pull, edit, then update-content to ship the changes back to the same URL \u2014 also the rollback path."
|
|
2105
|
+
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--json", "Force JSON output").action(
|
|
2106
|
+
async (target, commandOptions) => {
|
|
2107
|
+
const deps = await commandDeps(
|
|
2108
|
+
program,
|
|
2109
|
+
options,
|
|
2110
|
+
store,
|
|
2111
|
+
commandOptions
|
|
2112
|
+
);
|
|
2113
|
+
const result = await runPull(target, commandOptions, deps);
|
|
2114
|
+
process.exitCode = result.exitCode;
|
|
2115
|
+
}
|
|
2116
|
+
);
|
|
1987
2117
|
program.command("get <dropId>").description("Show drop details (pass the full drop_\u2026 id)").option("--json", "Force JSON output").action(async (dropId, commandOptions) => {
|
|
1988
2118
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
1989
2119
|
const result = await runDropsGet(dropId, commandOptions, deps);
|