@dropthis/cli 0.19.0 → 0.21.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 +55 -0
- package/dist/cli.cjs +183 -49
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +20 -2
- package/node_modules/@dropthis/node/dist/{drops-DmTdQTnd.d.cts → drops-CSahv_jA.d.cts} +76 -4
- package/node_modules/@dropthis/node/dist/{drops-DmTdQTnd.d.ts → drops-CSahv_jA.d.ts} +76 -4
- package/node_modules/@dropthis/node/dist/edge.cjs +76 -19
- 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 +76 -19
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +76 -19
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +2 -2
- package/node_modules/@dropthis/node/dist/index.d.ts +2 -2
- package/node_modules/@dropthis/node/dist/index.mjs +76 -19
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/package.json +1 -1
- package/package.json +49 -49
package/README.md
CHANGED
|
@@ -94,6 +94,57 @@ dropthis publish ./dist \
|
|
|
94
94
|
|
|
95
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
|
+
### Canonical vs raw URLs
|
|
98
|
+
|
|
99
|
+
Every drop has a canonical `url` — an always-branded human view (badge guaranteed). For a single non-HTML file (`.pdf`, `.png`, `.json`, a URL you asked the server to fetch, etc.), publish also prints a `Raw:` line: the file's exact bytes at a natural path, no wrapper. Hand the canonical `url` to people; hand the raw URL to agents or downstream tooling that needs the real bytes.
|
|
100
|
+
|
|
101
|
+
### Publishing a bundle with remote assets (`--manifest`)
|
|
102
|
+
|
|
103
|
+
When an AI agent generates an HTML page that references external images or other files, use `--manifest` to publish everything as one drop without base64-encoding the assets. The server fetches remote files during publish so bytes never pass through your process.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
dropthis publish --manifest bundle.json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`bundle.json` shape:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"files": [
|
|
114
|
+
{
|
|
115
|
+
"path": "index.html",
|
|
116
|
+
"content": "<html>...</html>"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"path": "hero.jpg",
|
|
120
|
+
"source_url": "https://cdn.example.com/hero.jpg"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"path": "data.json",
|
|
124
|
+
"content_base64": "eyJrZXkiOiJ2YWx1ZSJ9"
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Each file entry must have a `path` and exactly one content key:
|
|
131
|
+
|
|
132
|
+
| Key | Description |
|
|
133
|
+
|-----|-------------|
|
|
134
|
+
| `content` | UTF-8 text content (HTML, CSS, JSON, markdown, …) |
|
|
135
|
+
| `source_url` | Public `https://` URL — the server fetches the bytes server-side. Use this for images and other binary assets instead of base64-encoding them. |
|
|
136
|
+
| `content_base64` | Base64-encoded bytes (for binary files you already have in memory) |
|
|
137
|
+
|
|
138
|
+
Optional per-file keys: `content_type` (MIME type override).
|
|
139
|
+
|
|
140
|
+
The `--manifest` flag also works on `update-content`:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
dropthis update-content drop_abc123 --manifest bundle-v2.json
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Cannot be combined with a positional file/folder/URL argument.
|
|
147
|
+
|
|
97
148
|
All publish flags:
|
|
98
149
|
|
|
99
150
|
| Flag | Description |
|
|
@@ -105,6 +156,7 @@ All publish flags:
|
|
|
105
156
|
| `--entry <path>` | Entry file for directories |
|
|
106
157
|
| `--content-type <mime>` | MIME type (required for stdin) |
|
|
107
158
|
| `--path <path>` | Filename (required for stdin) |
|
|
159
|
+
| `--manifest <file>` | Multi-file bundle JSON (see above) |
|
|
108
160
|
| `--expires-at <datetime>` | Expiration datetime |
|
|
109
161
|
| `--metadata <json>` | Metadata as JSON string |
|
|
110
162
|
| `--metadata-file <path>` | Metadata from a JSON file |
|
|
@@ -133,6 +185,9 @@ Change an existing drop without creating a new URL. Content and settings are **s
|
|
|
133
185
|
# Replace the content at the same URL (ships a new deployment)
|
|
134
186
|
dropthis update-content drop_abc123 ./dist-v2
|
|
135
187
|
|
|
188
|
+
# Update from a manifest bundle (same --manifest format as publish)
|
|
189
|
+
dropthis update-content drop_abc123 --manifest bundle-v2.json
|
|
190
|
+
|
|
136
191
|
# Change settings only — title, visibility, password, expiry, metadata
|
|
137
192
|
dropthis update-settings drop_abc123 --title "New title"
|
|
138
193
|
|
package/dist/cli.cjs
CHANGED
|
@@ -916,13 +916,13 @@ async function runDoctor(_input, deps) {
|
|
|
916
916
|
const authSource = credential?.source ?? "missing";
|
|
917
917
|
const storageBackend = stored?.storage ?? "none";
|
|
918
918
|
const pairs = [
|
|
919
|
-
["Version", "0.
|
|
919
|
+
["Version", "0.21.0"],
|
|
920
920
|
["Auth", authSource],
|
|
921
921
|
["Storage", storageBackend]
|
|
922
922
|
];
|
|
923
923
|
writeKv(deps, pairs, {
|
|
924
924
|
ok: true,
|
|
925
|
-
version: "0.
|
|
925
|
+
version: "0.21.0",
|
|
926
926
|
auth: { source: authSource },
|
|
927
927
|
storage: { backend: storageBackend }
|
|
928
928
|
});
|
|
@@ -997,6 +997,14 @@ function printNextHints(deps, hints, hostname, dns) {
|
|
|
997
997
|
`);
|
|
998
998
|
}
|
|
999
999
|
}
|
|
1000
|
+
function printConsoleHandoff(deps, domain) {
|
|
1001
|
+
if (domain.status === "live" || !domain.consoleUrl) return;
|
|
1002
|
+
deps.stdout(
|
|
1003
|
+
`
|
|
1004
|
+
${hint(`Or finish it in the console: ${domain.consoleUrl}`)}
|
|
1005
|
+
`
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1000
1008
|
function computeSleepMs(records, elapsedMs, timeoutMs) {
|
|
1001
1009
|
const maxRetryAfter = records.reduce(
|
|
1002
1010
|
(max, r) => Math.max(max, r.retryAfter ?? 0),
|
|
@@ -1031,6 +1039,7 @@ async function runDomainsConnect(input, deps) {
|
|
|
1031
1039
|
`);
|
|
1032
1040
|
}
|
|
1033
1041
|
printNextHints(deps, domain.next, domain.hostname, domain.dns);
|
|
1042
|
+
printConsoleHandoff(deps, domain);
|
|
1034
1043
|
} else {
|
|
1035
1044
|
writeJson(deps, { ok: true, domain });
|
|
1036
1045
|
}
|
|
@@ -1111,6 +1120,7 @@ async function runDomainsStatus(idOrHostname, _input, deps) {
|
|
|
1111
1120
|
`);
|
|
1112
1121
|
}
|
|
1113
1122
|
printNextHints(deps, domain.next, domain.hostname, domain.dns);
|
|
1123
|
+
printConsoleHandoff(deps, domain);
|
|
1114
1124
|
} else {
|
|
1115
1125
|
writeJson(deps, { ok: true, domain });
|
|
1116
1126
|
}
|
|
@@ -1144,6 +1154,7 @@ async function runDomainsVerify(idOrHostname, input, deps, sleep = defaultSleep)
|
|
|
1144
1154
|
`);
|
|
1145
1155
|
}
|
|
1146
1156
|
printNextHints(deps, domain.next, domain.hostname, domain.dns);
|
|
1157
|
+
printConsoleHandoff(deps, domain);
|
|
1147
1158
|
} else {
|
|
1148
1159
|
writeJson(deps, { ok: true, domain });
|
|
1149
1160
|
}
|
|
@@ -1604,6 +1615,7 @@ async function runLogout(input, deps) {
|
|
|
1604
1615
|
|
|
1605
1616
|
// src/drop-operations.ts
|
|
1606
1617
|
var import_node_crypto = require("crypto");
|
|
1618
|
+
var import_promises = require("fs/promises");
|
|
1607
1619
|
var MAX_BUNDLE_FILE_COUNT = 200;
|
|
1608
1620
|
function isFileSystemError(error2) {
|
|
1609
1621
|
if (!(error2 instanceof Error)) return false;
|
|
@@ -1623,6 +1635,70 @@ function validateManifestFileCount(count) {
|
|
|
1623
1635
|
);
|
|
1624
1636
|
}
|
|
1625
1637
|
}
|
|
1638
|
+
async function loadManifestFile(manifestPath) {
|
|
1639
|
+
let raw;
|
|
1640
|
+
try {
|
|
1641
|
+
raw = JSON.parse(await (0, import_promises.readFile)(manifestPath, "utf8"));
|
|
1642
|
+
} catch (err) {
|
|
1643
|
+
const msg = err instanceof Error ? err.message : "Could not read manifest file.";
|
|
1644
|
+
throw new Error(`Failed to read manifest file: ${msg}`);
|
|
1645
|
+
}
|
|
1646
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1647
|
+
throw new Error("Manifest must be a JSON object with a 'files' array.");
|
|
1648
|
+
}
|
|
1649
|
+
const obj = raw;
|
|
1650
|
+
if (!Array.isArray(obj.files)) {
|
|
1651
|
+
throw new Error("Manifest must have a 'files' array.");
|
|
1652
|
+
}
|
|
1653
|
+
const files = obj.files.map(
|
|
1654
|
+
(entry, i) => {
|
|
1655
|
+
if (!entry || typeof entry !== "object") {
|
|
1656
|
+
throw new Error(`Manifest files[${i}] must be an object.`);
|
|
1657
|
+
}
|
|
1658
|
+
const {
|
|
1659
|
+
path,
|
|
1660
|
+
content,
|
|
1661
|
+
content_base64,
|
|
1662
|
+
source_url,
|
|
1663
|
+
content_type,
|
|
1664
|
+
size_bytes,
|
|
1665
|
+
checksum_sha256
|
|
1666
|
+
} = entry;
|
|
1667
|
+
if (!path || typeof path !== "string") {
|
|
1668
|
+
throw new Error(`Manifest files[${i}] must have a 'path' string.`);
|
|
1669
|
+
}
|
|
1670
|
+
const contentKeys = [content, content_base64, source_url].filter(
|
|
1671
|
+
(v) => v !== void 0
|
|
1672
|
+
);
|
|
1673
|
+
if (contentKeys.length === 0) {
|
|
1674
|
+
throw new Error(
|
|
1675
|
+
`Manifest files[${i}] (path: "${path}") must have exactly one of: content, content_base64, source_url.`
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
if (contentKeys.length > 1) {
|
|
1679
|
+
throw new Error(
|
|
1680
|
+
`Manifest files[${i}] (path: "${path}") must have only one of: content, content_base64, source_url.`
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
if (source_url !== void 0 && !source_url.startsWith("http://") && !source_url.startsWith("https://")) {
|
|
1684
|
+
throw new Error(
|
|
1685
|
+
`Manifest files[${i}] (path: "${path}") has an invalid source_url "${source_url}": source_url must be an http(s) URL.`
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
const file = { path };
|
|
1689
|
+
if (content !== void 0) file.content = content;
|
|
1690
|
+
if (content_base64 !== void 0) file.contentBase64 = content_base64;
|
|
1691
|
+
if (source_url !== void 0) file.sourceUrl = source_url;
|
|
1692
|
+
if (content_type !== void 0) file.contentType = content_type;
|
|
1693
|
+
if (size_bytes !== void 0)
|
|
1694
|
+
file.sizeBytes = size_bytes;
|
|
1695
|
+
if (checksum_sha256 !== void 0)
|
|
1696
|
+
file.checksumSha256 = checksum_sha256;
|
|
1697
|
+
return file;
|
|
1698
|
+
}
|
|
1699
|
+
);
|
|
1700
|
+
return { kind: "files", files };
|
|
1701
|
+
}
|
|
1626
1702
|
function formatDryRunManifest(prepared, extra) {
|
|
1627
1703
|
if (prepared.kind === "source") {
|
|
1628
1704
|
return {
|
|
@@ -1635,8 +1711,11 @@ function formatDryRunManifest(prepared, extra) {
|
|
|
1635
1711
|
...prepared.metadata ? { metadata: prepared.metadata } : {}
|
|
1636
1712
|
};
|
|
1637
1713
|
}
|
|
1714
|
+
const remoteFileCount = prepared.manifest.files.filter(
|
|
1715
|
+
(f) => typeof f.sizeBytes !== "number"
|
|
1716
|
+
).length;
|
|
1638
1717
|
const totalBytes = prepared.manifest.files.reduce(
|
|
1639
|
-
(sum, f) => sum + f.sizeBytes,
|
|
1718
|
+
(sum, f) => sum + (typeof f.sizeBytes === "number" ? f.sizeBytes : 0),
|
|
1640
1719
|
0
|
|
1641
1720
|
);
|
|
1642
1721
|
return {
|
|
@@ -1650,12 +1729,15 @@ function formatDryRunManifest(prepared, extra) {
|
|
|
1650
1729
|
},
|
|
1651
1730
|
options: prepared.options,
|
|
1652
1731
|
...prepared.metadata ? { metadata: prepared.metadata } : {},
|
|
1653
|
-
totalBytes
|
|
1732
|
+
totalBytes,
|
|
1733
|
+
// Only include remoteFileCount when there are remote files, to preserve
|
|
1734
|
+
// the existing output shape for all-inline bundles.
|
|
1735
|
+
...remoteFileCount > 0 ? { remoteFileCount } : {}
|
|
1654
1736
|
};
|
|
1655
1737
|
}
|
|
1656
1738
|
|
|
1657
1739
|
// src/options.ts
|
|
1658
|
-
var
|
|
1740
|
+
var import_promises2 = require("fs/promises");
|
|
1659
1741
|
var import_node = require("@dropthis/node");
|
|
1660
1742
|
async function parseDropOptions(raw) {
|
|
1661
1743
|
if (raw.metadata && raw.metadataFile) {
|
|
@@ -1684,7 +1766,7 @@ async function parseDropOptions(raw) {
|
|
|
1684
1766
|
}
|
|
1685
1767
|
}
|
|
1686
1768
|
const metadata = raw.metadata ? parseJsonObject(raw.metadata, "--metadata") : raw.metadataFile ? parseJsonObject(
|
|
1687
|
-
await (0,
|
|
1769
|
+
await (0, import_promises2.readFile)(raw.metadataFile, "utf8"),
|
|
1688
1770
|
"--metadata-file"
|
|
1689
1771
|
) : void 0;
|
|
1690
1772
|
return {
|
|
@@ -1766,6 +1848,25 @@ async function runPublish(input, raw, deps) {
|
|
|
1766
1848
|
if (didInlineAuth && deps.createClient) {
|
|
1767
1849
|
client = deps.createClient(credential.apiKey);
|
|
1768
1850
|
}
|
|
1851
|
+
if (raw.manifest) {
|
|
1852
|
+
const hasInput2 = Array.isArray(input) ? input.length > 0 : input !== void 0;
|
|
1853
|
+
if (hasInput2) {
|
|
1854
|
+
return writeError(
|
|
1855
|
+
deps,
|
|
1856
|
+
"invalid_usage",
|
|
1857
|
+
"--manifest cannot be combined with a positional input.",
|
|
1858
|
+
"Remove the positional argument, or omit --manifest and pass your files directly."
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
let manifestInput;
|
|
1862
|
+
try {
|
|
1863
|
+
manifestInput = await loadManifestFile(raw.manifest);
|
|
1864
|
+
} catch (err) {
|
|
1865
|
+
const msg = err instanceof Error ? err.message : "Invalid manifest.";
|
|
1866
|
+
return writeError(deps, "invalid_usage", msg);
|
|
1867
|
+
}
|
|
1868
|
+
input = manifestInput;
|
|
1869
|
+
}
|
|
1769
1870
|
if (raw.dryRun) {
|
|
1770
1871
|
return handlePublishDryRun(input, raw, deps, client);
|
|
1771
1872
|
}
|
|
@@ -1834,7 +1935,8 @@ async function handlePublishDryRun(input, raw, deps, client) {
|
|
|
1834
1935
|
);
|
|
1835
1936
|
}
|
|
1836
1937
|
try {
|
|
1837
|
-
|
|
1938
|
+
const hasInput = Array.isArray(input) ? input.length > 0 : input !== void 0;
|
|
1939
|
+
if (!hasInput) {
|
|
1838
1940
|
throw new Error("Publish requires <input>.");
|
|
1839
1941
|
}
|
|
1840
1942
|
const options = await parseDropOptions(raw);
|
|
@@ -1857,7 +1959,7 @@ async function handlePublishDryRun(input, raw, deps, client) {
|
|
|
1857
1959
|
}
|
|
1858
1960
|
|
|
1859
1961
|
// src/commands/pull.ts
|
|
1860
|
-
var
|
|
1962
|
+
var import_promises3 = require("fs/promises");
|
|
1861
1963
|
var import_node_path = require("path");
|
|
1862
1964
|
async function runPull(target, input, deps) {
|
|
1863
1965
|
try {
|
|
@@ -1897,7 +1999,7 @@ async function runPull(target, input, deps) {
|
|
|
1897
1999
|
return writeError(deps, "local_input_error", message);
|
|
1898
2000
|
}
|
|
1899
2001
|
try {
|
|
1900
|
-
await (0,
|
|
2002
|
+
await (0, import_promises3.mkdir)(outDir, { recursive: true });
|
|
1901
2003
|
for (const { path, dest } of destinations) {
|
|
1902
2004
|
const fileResult = await deps.client.drops.getContent(dropId, { path });
|
|
1903
2005
|
if (fileResult.error) {
|
|
@@ -1908,8 +2010,8 @@ async function runPull(target, input, deps) {
|
|
|
1908
2010
|
});
|
|
1909
2011
|
}
|
|
1910
2012
|
const file = fileResult.data;
|
|
1911
|
-
await (0,
|
|
1912
|
-
await (0,
|
|
2013
|
+
await (0, import_promises3.mkdir)((0, import_node_path.dirname)(dest), { recursive: true });
|
|
2014
|
+
await (0, import_promises3.writeFile)(dest, file.bytes);
|
|
1913
2015
|
}
|
|
1914
2016
|
} catch (error2) {
|
|
1915
2017
|
spin?.fail();
|
|
@@ -1975,6 +2077,23 @@ async function runUpdateContent(target, input, raw, deps) {
|
|
|
1975
2077
|
const resolved = await resolveDropTarget(target, resolveDeps);
|
|
1976
2078
|
if (!resolved.ok) return { exitCode: resolved.exitCode };
|
|
1977
2079
|
const dropId = resolved.dropId;
|
|
2080
|
+
if (raw.manifest) {
|
|
2081
|
+
const hasInput = Array.isArray(input) ? input.length > 0 : input !== void 0;
|
|
2082
|
+
if (hasInput) {
|
|
2083
|
+
return writeError(
|
|
2084
|
+
deps,
|
|
2085
|
+
"invalid_usage",
|
|
2086
|
+
"--manifest cannot be combined with a positional input.",
|
|
2087
|
+
"Remove the positional argument, or omit --manifest and pass your files directly."
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
try {
|
|
2091
|
+
input = await loadManifestFile(raw.manifest);
|
|
2092
|
+
} catch (err) {
|
|
2093
|
+
const msg = err instanceof Error ? err.message : "Invalid manifest.";
|
|
2094
|
+
return writeError(deps, "invalid_usage", msg);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
1978
2097
|
if (raw.dryRun) {
|
|
1979
2098
|
return handleDryRun(dropId, input, raw, deps);
|
|
1980
2099
|
}
|
|
@@ -2467,7 +2586,7 @@ function createContext(input) {
|
|
|
2467
2586
|
}
|
|
2468
2587
|
|
|
2469
2588
|
// src/storage.ts
|
|
2470
|
-
var
|
|
2589
|
+
var import_promises4 = require("fs/promises");
|
|
2471
2590
|
var import_node_os = require("os");
|
|
2472
2591
|
var import_node_path2 = require("path");
|
|
2473
2592
|
var import_keyring = require("@napi-rs/keyring");
|
|
@@ -2501,7 +2620,7 @@ var InsecureFileCredentialStore = class {
|
|
|
2501
2620
|
});
|
|
2502
2621
|
}
|
|
2503
2622
|
async clear() {
|
|
2504
|
-
await (0,
|
|
2623
|
+
await (0, import_promises4.rm)(this.filePath, { force: true });
|
|
2505
2624
|
}
|
|
2506
2625
|
};
|
|
2507
2626
|
var KeyringCredentialStore = class {
|
|
@@ -2528,7 +2647,7 @@ var KeyringCredentialStore = class {
|
|
|
2528
2647
|
}
|
|
2529
2648
|
async clear() {
|
|
2530
2649
|
await this.keyring.deletePassword();
|
|
2531
|
-
await (0,
|
|
2650
|
+
await (0, import_promises4.rm)(this.filePath, { force: true });
|
|
2532
2651
|
}
|
|
2533
2652
|
};
|
|
2534
2653
|
function createCredentialStore(options = {}) {
|
|
@@ -2553,7 +2672,7 @@ function credentialPath(configDir) {
|
|
|
2553
2672
|
}
|
|
2554
2673
|
async function readJsonFile(path) {
|
|
2555
2674
|
try {
|
|
2556
|
-
return JSON.parse(await (0,
|
|
2675
|
+
return JSON.parse(await (0, import_promises4.readFile)(path, "utf8"));
|
|
2557
2676
|
} catch (error2) {
|
|
2558
2677
|
if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
|
|
2559
2678
|
return null;
|
|
@@ -2562,18 +2681,18 @@ async function readJsonFile(path) {
|
|
|
2562
2681
|
}
|
|
2563
2682
|
}
|
|
2564
2683
|
async function writeCredentialFile(path, credential) {
|
|
2565
|
-
await (0,
|
|
2684
|
+
await (0, import_promises4.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
2566
2685
|
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
2567
|
-
await (0,
|
|
2686
|
+
await (0, import_promises4.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
|
|
2568
2687
|
`, {
|
|
2569
2688
|
mode: 384
|
|
2570
2689
|
});
|
|
2571
|
-
await (0,
|
|
2572
|
-
await (0,
|
|
2690
|
+
await (0, import_promises4.chmod)(tmpPath, 384);
|
|
2691
|
+
await (0, import_promises4.rename)(tmpPath, path);
|
|
2573
2692
|
}
|
|
2574
2693
|
|
|
2575
2694
|
// src/typo-guard.ts
|
|
2576
|
-
var
|
|
2695
|
+
var import_promises5 = require("fs/promises");
|
|
2577
2696
|
function levenshtein(a, b) {
|
|
2578
2697
|
if (a === b) return 0;
|
|
2579
2698
|
if (a.length === 0) return b.length;
|
|
@@ -2614,7 +2733,7 @@ function isBareWordToken(token) {
|
|
|
2614
2733
|
}
|
|
2615
2734
|
async function pathExists(path) {
|
|
2616
2735
|
try {
|
|
2617
|
-
await (0,
|
|
2736
|
+
await (0, import_promises5.stat)(path);
|
|
2618
2737
|
return true;
|
|
2619
2738
|
} catch {
|
|
2620
2739
|
return false;
|
|
@@ -2648,7 +2767,7 @@ function buildProgram(options = {}) {
|
|
|
2648
2767
|
` ${import_picocolors6.default.cyan("dropthis login")}`,
|
|
2649
2768
|
` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
|
|
2650
2769
|
].join("\n")
|
|
2651
|
-
).version("0.
|
|
2770
|
+
).version("0.21.0").configureHelp({
|
|
2652
2771
|
subcommandTerm(cmd) {
|
|
2653
2772
|
const args = cmd.registeredArguments.map((a) => {
|
|
2654
2773
|
const name = a.name();
|
|
@@ -2699,6 +2818,9 @@ ${lines.map((l) => ` ${l}`).join("\n")}
|
|
|
2699
2818
|
).option(
|
|
2700
2819
|
"--slug <vanity-slug>",
|
|
2701
2820
|
"Vanity slug for path-mode custom domains (1\u201363 lowercase letters/digits/hyphens). Auto-suffixed if taken. Only valid with --domain on a path-mode domain."
|
|
2821
|
+
).option(
|
|
2822
|
+
"--manifest <file>",
|
|
2823
|
+
"Publish a multi-file bundle defined in a JSON file (path, content/source_url/content_base64 per file). Cannot combine with a positional input."
|
|
2702
2824
|
).option("--url", "Print only the published URL (no JSON envelope)").option(
|
|
2703
2825
|
"--dry-run",
|
|
2704
2826
|
"Show what would be published without publishing (JSON; cannot combine with --url)"
|
|
@@ -2729,7 +2851,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2729
2851
|
].join("\n")
|
|
2730
2852
|
).action(async (inputs, commandOptions) => {
|
|
2731
2853
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2732
|
-
if (inputs.length === 0 && stdinIsTTY) {
|
|
2854
|
+
if (inputs.length === 0 && stdinIsTTY && !commandOptions.manifest) {
|
|
2733
2855
|
program.outputHelp();
|
|
2734
2856
|
return;
|
|
2735
2857
|
}
|
|
@@ -2741,16 +2863,22 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2741
2863
|
stdinIsTTY
|
|
2742
2864
|
);
|
|
2743
2865
|
let publishInput;
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2866
|
+
if (inputs.length > 0 || !commandOptions.manifest) {
|
|
2867
|
+
try {
|
|
2868
|
+
publishInput = await resolvePublishInputs(
|
|
2869
|
+
inputs,
|
|
2870
|
+
options.stdin,
|
|
2871
|
+
stdinIsTTY
|
|
2872
|
+
);
|
|
2873
|
+
} catch (err) {
|
|
2874
|
+
const msg = err instanceof Error ? err.message : "Invalid input.";
|
|
2875
|
+
process.exitCode = writeError(
|
|
2876
|
+
deps,
|
|
2877
|
+
"local_input_error",
|
|
2878
|
+
msg
|
|
2879
|
+
).exitCode;
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2754
2882
|
}
|
|
2755
2883
|
if (deps.outputMode === "human" && deps.interactive && inputs.length === 1 && typeof publishInput === "string" && isBareWordToken(publishInput) && !await pathExists(publishInput)) {
|
|
2756
2884
|
const suggestion = suggestCommand(
|
|
@@ -2795,6 +2923,9 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2795
2923
|
"--content-type <mime>",
|
|
2796
2924
|
"Override MIME type (auto-detected from extension)"
|
|
2797
2925
|
).option("--path <name>", "Set filename for stdin content").option(
|
|
2926
|
+
"--manifest <file>",
|
|
2927
|
+
"Update content from a multi-file bundle defined in a JSON file (path, content/source_url/content_base64 per file). Cannot combine with a positional input."
|
|
2928
|
+
).option(
|
|
2798
2929
|
"--if-revision <n>",
|
|
2799
2930
|
"Fail if current revision doesn't match (optimistic lock)",
|
|
2800
2931
|
parseInteger
|
|
@@ -2809,20 +2940,22 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2809
2940
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2810
2941
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2811
2942
|
let updateInput;
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2943
|
+
if (inputs.length > 0 || !commandOptions.manifest) {
|
|
2944
|
+
try {
|
|
2945
|
+
updateInput = await resolvePublishInputs(
|
|
2946
|
+
inputs,
|
|
2947
|
+
options.stdin,
|
|
2948
|
+
stdinIsTTY
|
|
2949
|
+
);
|
|
2950
|
+
} catch (err) {
|
|
2951
|
+
const msg = err instanceof Error ? err.message : "Invalid input.";
|
|
2952
|
+
process.exitCode = writeError(
|
|
2953
|
+
deps,
|
|
2954
|
+
"local_input_error",
|
|
2955
|
+
msg
|
|
2956
|
+
).exitCode;
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2826
2959
|
}
|
|
2827
2960
|
let dropOpts;
|
|
2828
2961
|
try {
|
|
@@ -3221,7 +3354,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3221
3354
|
);
|
|
3222
3355
|
const result = await runUpgrade(commandOptions, {
|
|
3223
3356
|
...deps,
|
|
3224
|
-
currentVersion: "0.
|
|
3357
|
+
currentVersion: "0.21.0"
|
|
3225
3358
|
});
|
|
3226
3359
|
process.exitCode = result.exitCode;
|
|
3227
3360
|
});
|
|
@@ -3331,6 +3464,7 @@ function toDropOptions(options) {
|
|
|
3331
3464
|
...options.domain ? { domain: options.domain } : {},
|
|
3332
3465
|
...options.shared ? { shared: true } : {},
|
|
3333
3466
|
...options.slug ? { slug: options.slug } : {},
|
|
3467
|
+
...options.manifest ? { manifest: options.manifest } : {},
|
|
3334
3468
|
...options.json !== void 0 ? { json: options.json } : {},
|
|
3335
3469
|
...options.quiet !== void 0 ? { quiet: options.quiet } : {},
|
|
3336
3470
|
...options.url !== void 0 ? { url: options.url } : {},
|
|
@@ -3465,7 +3599,7 @@ var showNotice = shouldShowNotice({
|
|
|
3465
3599
|
if (showNotice) {
|
|
3466
3600
|
const notice = noticeFromCache({
|
|
3467
3601
|
cache: updateCache,
|
|
3468
|
-
currentVersion: "0.
|
|
3602
|
+
currentVersion: "0.21.0"
|
|
3469
3603
|
});
|
|
3470
3604
|
if (notice) {
|
|
3471
3605
|
process.stderr.write(`
|