@dropthis/cli 0.20.0 → 0.22.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 +211 -51
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +20 -2
- package/node_modules/@dropthis/node/dist/{drops-C92Gkuqx.d.cts → drops-DNwOp7g_.d.cts} +89 -5
- package/node_modules/@dropthis/node/dist/{drops-C92Gkuqx.d.ts → drops-DNwOp7g_.d.ts} +89 -5
- package/node_modules/@dropthis/node/dist/edge.cjs +88 -21
- 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 +88 -21
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +88 -21
- 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 +88 -21
- 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.22.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.22.0",
|
|
926
926
|
auth: { source: authSource },
|
|
927
927
|
storage: { backend: storageBackend }
|
|
928
928
|
});
|
|
@@ -1615,6 +1615,7 @@ async function runLogout(input, deps) {
|
|
|
1615
1615
|
|
|
1616
1616
|
// src/drop-operations.ts
|
|
1617
1617
|
var import_node_crypto = require("crypto");
|
|
1618
|
+
var import_promises = require("fs/promises");
|
|
1618
1619
|
var MAX_BUNDLE_FILE_COUNT = 200;
|
|
1619
1620
|
function isFileSystemError(error2) {
|
|
1620
1621
|
if (!(error2 instanceof Error)) return false;
|
|
@@ -1634,6 +1635,70 @@ function validateManifestFileCount(count) {
|
|
|
1634
1635
|
);
|
|
1635
1636
|
}
|
|
1636
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
|
+
}
|
|
1637
1702
|
function formatDryRunManifest(prepared, extra) {
|
|
1638
1703
|
if (prepared.kind === "source") {
|
|
1639
1704
|
return {
|
|
@@ -1646,8 +1711,11 @@ function formatDryRunManifest(prepared, extra) {
|
|
|
1646
1711
|
...prepared.metadata ? { metadata: prepared.metadata } : {}
|
|
1647
1712
|
};
|
|
1648
1713
|
}
|
|
1714
|
+
const remoteFileCount = prepared.manifest.files.filter(
|
|
1715
|
+
(f) => typeof f.sizeBytes !== "number"
|
|
1716
|
+
).length;
|
|
1649
1717
|
const totalBytes = prepared.manifest.files.reduce(
|
|
1650
|
-
(sum, f) => sum + f.sizeBytes,
|
|
1718
|
+
(sum, f) => sum + (typeof f.sizeBytes === "number" ? f.sizeBytes : 0),
|
|
1651
1719
|
0
|
|
1652
1720
|
);
|
|
1653
1721
|
return {
|
|
@@ -1661,12 +1729,15 @@ function formatDryRunManifest(prepared, extra) {
|
|
|
1661
1729
|
},
|
|
1662
1730
|
options: prepared.options,
|
|
1663
1731
|
...prepared.metadata ? { metadata: prepared.metadata } : {},
|
|
1664
|
-
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 } : {}
|
|
1665
1736
|
};
|
|
1666
1737
|
}
|
|
1667
1738
|
|
|
1668
1739
|
// src/options.ts
|
|
1669
|
-
var
|
|
1740
|
+
var import_promises2 = require("fs/promises");
|
|
1670
1741
|
var import_node = require("@dropthis/node");
|
|
1671
1742
|
async function parseDropOptions(raw) {
|
|
1672
1743
|
if (raw.metadata && raw.metadataFile) {
|
|
@@ -1695,7 +1766,7 @@ async function parseDropOptions(raw) {
|
|
|
1695
1766
|
}
|
|
1696
1767
|
}
|
|
1697
1768
|
const metadata = raw.metadata ? parseJsonObject(raw.metadata, "--metadata") : raw.metadataFile ? parseJsonObject(
|
|
1698
|
-
await (0,
|
|
1769
|
+
await (0, import_promises2.readFile)(raw.metadataFile, "utf8"),
|
|
1699
1770
|
"--metadata-file"
|
|
1700
1771
|
) : void 0;
|
|
1701
1772
|
return {
|
|
@@ -1777,6 +1848,25 @@ async function runPublish(input, raw, deps) {
|
|
|
1777
1848
|
if (didInlineAuth && deps.createClient) {
|
|
1778
1849
|
client = deps.createClient(credential.apiKey);
|
|
1779
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
|
+
}
|
|
1780
1870
|
if (raw.dryRun) {
|
|
1781
1871
|
return handlePublishDryRun(input, raw, deps, client);
|
|
1782
1872
|
}
|
|
@@ -1845,7 +1935,8 @@ async function handlePublishDryRun(input, raw, deps, client) {
|
|
|
1845
1935
|
);
|
|
1846
1936
|
}
|
|
1847
1937
|
try {
|
|
1848
|
-
|
|
1938
|
+
const hasInput = Array.isArray(input) ? input.length > 0 : input !== void 0;
|
|
1939
|
+
if (!hasInput) {
|
|
1849
1940
|
throw new Error("Publish requires <input>.");
|
|
1850
1941
|
}
|
|
1851
1942
|
const options = await parseDropOptions(raw);
|
|
@@ -1868,7 +1959,7 @@ async function handlePublishDryRun(input, raw, deps, client) {
|
|
|
1868
1959
|
}
|
|
1869
1960
|
|
|
1870
1961
|
// src/commands/pull.ts
|
|
1871
|
-
var
|
|
1962
|
+
var import_promises3 = require("fs/promises");
|
|
1872
1963
|
var import_node_path = require("path");
|
|
1873
1964
|
async function runPull(target, input, deps) {
|
|
1874
1965
|
try {
|
|
@@ -1908,7 +1999,7 @@ async function runPull(target, input, deps) {
|
|
|
1908
1999
|
return writeError(deps, "local_input_error", message);
|
|
1909
2000
|
}
|
|
1910
2001
|
try {
|
|
1911
|
-
await (0,
|
|
2002
|
+
await (0, import_promises3.mkdir)(outDir, { recursive: true });
|
|
1912
2003
|
for (const { path, dest } of destinations) {
|
|
1913
2004
|
const fileResult = await deps.client.drops.getContent(dropId, { path });
|
|
1914
2005
|
if (fileResult.error) {
|
|
@@ -1919,8 +2010,8 @@ async function runPull(target, input, deps) {
|
|
|
1919
2010
|
});
|
|
1920
2011
|
}
|
|
1921
2012
|
const file = fileResult.data;
|
|
1922
|
-
await (0,
|
|
1923
|
-
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);
|
|
1924
2015
|
}
|
|
1925
2016
|
} catch (error2) {
|
|
1926
2017
|
spin?.fail();
|
|
@@ -1968,6 +2059,15 @@ function contentOptions(options) {
|
|
|
1968
2059
|
if (options.path !== void 0) out.path = options.path;
|
|
1969
2060
|
return out;
|
|
1970
2061
|
}
|
|
2062
|
+
function partialOptions(raw) {
|
|
2063
|
+
const out = {};
|
|
2064
|
+
if (raw.replace) out.mode = "replace";
|
|
2065
|
+
else if (raw.mode !== void 0) out.mode = raw.mode;
|
|
2066
|
+
if (raw.deletePaths !== void 0 && raw.deletePaths.length > 0) {
|
|
2067
|
+
out.deletePaths = raw.deletePaths;
|
|
2068
|
+
}
|
|
2069
|
+
return out;
|
|
2070
|
+
}
|
|
1971
2071
|
async function runUpdateContent(target, input, raw, deps) {
|
|
1972
2072
|
const apiKey = raw.apiKey ?? deps.apiKey;
|
|
1973
2073
|
try {
|
|
@@ -1986,6 +2086,23 @@ async function runUpdateContent(target, input, raw, deps) {
|
|
|
1986
2086
|
const resolved = await resolveDropTarget(target, resolveDeps);
|
|
1987
2087
|
if (!resolved.ok) return { exitCode: resolved.exitCode };
|
|
1988
2088
|
const dropId = resolved.dropId;
|
|
2089
|
+
if (raw.manifest) {
|
|
2090
|
+
const hasInput = Array.isArray(input) ? input.length > 0 : input !== void 0;
|
|
2091
|
+
if (hasInput) {
|
|
2092
|
+
return writeError(
|
|
2093
|
+
deps,
|
|
2094
|
+
"invalid_usage",
|
|
2095
|
+
"--manifest cannot be combined with a positional input.",
|
|
2096
|
+
"Remove the positional argument, or omit --manifest and pass your files directly."
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
try {
|
|
2100
|
+
input = await loadManifestFile(raw.manifest);
|
|
2101
|
+
} catch (err) {
|
|
2102
|
+
const msg = err instanceof Error ? err.message : "Invalid manifest.";
|
|
2103
|
+
return writeError(deps, "invalid_usage", msg);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
1989
2106
|
if (raw.dryRun) {
|
|
1990
2107
|
return handleDryRun(dropId, input, raw, deps);
|
|
1991
2108
|
}
|
|
@@ -2008,7 +2125,11 @@ async function runUpdateContent(target, input, raw, deps) {
|
|
|
2008
2125
|
dropId,
|
|
2009
2126
|
input,
|
|
2010
2127
|
withIdempotencyKey(
|
|
2011
|
-
{
|
|
2128
|
+
{
|
|
2129
|
+
...contentOptions(parsed),
|
|
2130
|
+
...partialOptions(raw),
|
|
2131
|
+
...revisionOptions
|
|
2132
|
+
},
|
|
2012
2133
|
"upd"
|
|
2013
2134
|
)
|
|
2014
2135
|
);
|
|
@@ -2478,7 +2599,7 @@ function createContext(input) {
|
|
|
2478
2599
|
}
|
|
2479
2600
|
|
|
2480
2601
|
// src/storage.ts
|
|
2481
|
-
var
|
|
2602
|
+
var import_promises4 = require("fs/promises");
|
|
2482
2603
|
var import_node_os = require("os");
|
|
2483
2604
|
var import_node_path2 = require("path");
|
|
2484
2605
|
var import_keyring = require("@napi-rs/keyring");
|
|
@@ -2512,7 +2633,7 @@ var InsecureFileCredentialStore = class {
|
|
|
2512
2633
|
});
|
|
2513
2634
|
}
|
|
2514
2635
|
async clear() {
|
|
2515
|
-
await (0,
|
|
2636
|
+
await (0, import_promises4.rm)(this.filePath, { force: true });
|
|
2516
2637
|
}
|
|
2517
2638
|
};
|
|
2518
2639
|
var KeyringCredentialStore = class {
|
|
@@ -2539,7 +2660,7 @@ var KeyringCredentialStore = class {
|
|
|
2539
2660
|
}
|
|
2540
2661
|
async clear() {
|
|
2541
2662
|
await this.keyring.deletePassword();
|
|
2542
|
-
await (0,
|
|
2663
|
+
await (0, import_promises4.rm)(this.filePath, { force: true });
|
|
2543
2664
|
}
|
|
2544
2665
|
};
|
|
2545
2666
|
function createCredentialStore(options = {}) {
|
|
@@ -2564,7 +2685,7 @@ function credentialPath(configDir) {
|
|
|
2564
2685
|
}
|
|
2565
2686
|
async function readJsonFile(path) {
|
|
2566
2687
|
try {
|
|
2567
|
-
return JSON.parse(await (0,
|
|
2688
|
+
return JSON.parse(await (0, import_promises4.readFile)(path, "utf8"));
|
|
2568
2689
|
} catch (error2) {
|
|
2569
2690
|
if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
|
|
2570
2691
|
return null;
|
|
@@ -2573,18 +2694,18 @@ async function readJsonFile(path) {
|
|
|
2573
2694
|
}
|
|
2574
2695
|
}
|
|
2575
2696
|
async function writeCredentialFile(path, credential) {
|
|
2576
|
-
await (0,
|
|
2697
|
+
await (0, import_promises4.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
2577
2698
|
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
2578
|
-
await (0,
|
|
2699
|
+
await (0, import_promises4.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
|
|
2579
2700
|
`, {
|
|
2580
2701
|
mode: 384
|
|
2581
2702
|
});
|
|
2582
|
-
await (0,
|
|
2583
|
-
await (0,
|
|
2703
|
+
await (0, import_promises4.chmod)(tmpPath, 384);
|
|
2704
|
+
await (0, import_promises4.rename)(tmpPath, path);
|
|
2584
2705
|
}
|
|
2585
2706
|
|
|
2586
2707
|
// src/typo-guard.ts
|
|
2587
|
-
var
|
|
2708
|
+
var import_promises5 = require("fs/promises");
|
|
2588
2709
|
function levenshtein(a, b) {
|
|
2589
2710
|
if (a === b) return 0;
|
|
2590
2711
|
if (a.length === 0) return b.length;
|
|
@@ -2625,7 +2746,7 @@ function isBareWordToken(token) {
|
|
|
2625
2746
|
}
|
|
2626
2747
|
async function pathExists(path) {
|
|
2627
2748
|
try {
|
|
2628
|
-
await (0,
|
|
2749
|
+
await (0, import_promises5.stat)(path);
|
|
2629
2750
|
return true;
|
|
2630
2751
|
} catch {
|
|
2631
2752
|
return false;
|
|
@@ -2659,7 +2780,7 @@ function buildProgram(options = {}) {
|
|
|
2659
2780
|
` ${import_picocolors6.default.cyan("dropthis login")}`,
|
|
2660
2781
|
` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
|
|
2661
2782
|
].join("\n")
|
|
2662
|
-
).version("0.
|
|
2783
|
+
).version("0.22.0").configureHelp({
|
|
2663
2784
|
subcommandTerm(cmd) {
|
|
2664
2785
|
const args = cmd.registeredArguments.map((a) => {
|
|
2665
2786
|
const name = a.name();
|
|
@@ -2710,6 +2831,9 @@ ${lines.map((l) => ` ${l}`).join("\n")}
|
|
|
2710
2831
|
).option(
|
|
2711
2832
|
"--slug <vanity-slug>",
|
|
2712
2833
|
"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."
|
|
2834
|
+
).option(
|
|
2835
|
+
"--manifest <file>",
|
|
2836
|
+
"Publish a multi-file bundle defined in a JSON file (path, content/source_url/content_base64 per file). Cannot combine with a positional input."
|
|
2713
2837
|
).option("--url", "Print only the published URL (no JSON envelope)").option(
|
|
2714
2838
|
"--dry-run",
|
|
2715
2839
|
"Show what would be published without publishing (JSON; cannot combine with --url)"
|
|
@@ -2740,7 +2864,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2740
2864
|
].join("\n")
|
|
2741
2865
|
).action(async (inputs, commandOptions) => {
|
|
2742
2866
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2743
|
-
if (inputs.length === 0 && stdinIsTTY) {
|
|
2867
|
+
if (inputs.length === 0 && stdinIsTTY && !commandOptions.manifest) {
|
|
2744
2868
|
program.outputHelp();
|
|
2745
2869
|
return;
|
|
2746
2870
|
}
|
|
@@ -2752,16 +2876,22 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2752
2876
|
stdinIsTTY
|
|
2753
2877
|
);
|
|
2754
2878
|
let publishInput;
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2879
|
+
if (inputs.length > 0 || !commandOptions.manifest) {
|
|
2880
|
+
try {
|
|
2881
|
+
publishInput = await resolvePublishInputs(
|
|
2882
|
+
inputs,
|
|
2883
|
+
options.stdin,
|
|
2884
|
+
stdinIsTTY
|
|
2885
|
+
);
|
|
2886
|
+
} catch (err) {
|
|
2887
|
+
const msg = err instanceof Error ? err.message : "Invalid input.";
|
|
2888
|
+
process.exitCode = writeError(
|
|
2889
|
+
deps,
|
|
2890
|
+
"local_input_error",
|
|
2891
|
+
msg
|
|
2892
|
+
).exitCode;
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2765
2895
|
}
|
|
2766
2896
|
if (deps.outputMode === "human" && deps.interactive && inputs.length === 1 && typeof publishInput === "string" && isBareWordToken(publishInput) && !await pathExists(publishInput)) {
|
|
2767
2897
|
const suggestion = suggestCommand(
|
|
@@ -2806,6 +2936,18 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2806
2936
|
"--content-type <mime>",
|
|
2807
2937
|
"Override MIME type (auto-detected from extension)"
|
|
2808
2938
|
).option("--path <name>", "Set filename for stdin content").option(
|
|
2939
|
+
"--manifest <file>",
|
|
2940
|
+
"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."
|
|
2941
|
+
).option(
|
|
2942
|
+
"--mode <mode>",
|
|
2943
|
+
"patch (default: provided files upsert, the rest carry forward) or replace (provided files become the whole content set)",
|
|
2944
|
+
parseMode
|
|
2945
|
+
).option("--replace", "Shortcut for --mode replace (full content swap)").option(
|
|
2946
|
+
"--delete-path <path>",
|
|
2947
|
+
"Remove a file by path (patch-mode only; repeatable). Invalid with --replace.",
|
|
2948
|
+
collect,
|
|
2949
|
+
[]
|
|
2950
|
+
).option(
|
|
2809
2951
|
"--if-revision <n>",
|
|
2810
2952
|
"Fail if current revision doesn't match (optimistic lock)",
|
|
2811
2953
|
parseInteger
|
|
@@ -2820,20 +2962,22 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2820
2962
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2821
2963
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2822
2964
|
let updateInput;
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2965
|
+
if (inputs.length > 0 || !commandOptions.manifest) {
|
|
2966
|
+
try {
|
|
2967
|
+
updateInput = await resolvePublishInputs(
|
|
2968
|
+
inputs,
|
|
2969
|
+
options.stdin,
|
|
2970
|
+
stdinIsTTY
|
|
2971
|
+
);
|
|
2972
|
+
} catch (err) {
|
|
2973
|
+
const msg = err instanceof Error ? err.message : "Invalid input.";
|
|
2974
|
+
process.exitCode = writeError(
|
|
2975
|
+
deps,
|
|
2976
|
+
"local_input_error",
|
|
2977
|
+
msg
|
|
2978
|
+
).exitCode;
|
|
2979
|
+
return;
|
|
2980
|
+
}
|
|
2837
2981
|
}
|
|
2838
2982
|
let dropOpts;
|
|
2839
2983
|
try {
|
|
@@ -2843,10 +2987,16 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2843
2987
|
process.exitCode = writeError(deps, "invalid_usage", msg).exitCode;
|
|
2844
2988
|
return;
|
|
2845
2989
|
}
|
|
2990
|
+
const deletePaths = commandOptions.deletePath ?? [];
|
|
2991
|
+
const updateOpts = {
|
|
2992
|
+
...dropOpts,
|
|
2993
|
+
...commandOptions.replace ? { mode: "replace" } : commandOptions.mode !== void 0 ? { mode: commandOptions.mode } : {},
|
|
2994
|
+
...deletePaths.length > 0 ? { deletePaths } : {}
|
|
2995
|
+
};
|
|
2846
2996
|
const result = await runUpdateContent(
|
|
2847
2997
|
dropId,
|
|
2848
2998
|
updateInput,
|
|
2849
|
-
|
|
2999
|
+
updateOpts,
|
|
2850
3000
|
deps
|
|
2851
3001
|
);
|
|
2852
3002
|
process.exitCode = result.exitCode;
|
|
@@ -3232,7 +3382,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3232
3382
|
);
|
|
3233
3383
|
const result = await runUpgrade(commandOptions, {
|
|
3234
3384
|
...deps,
|
|
3235
|
-
currentVersion: "0.
|
|
3385
|
+
currentVersion: "0.22.0"
|
|
3236
3386
|
});
|
|
3237
3387
|
process.exitCode = result.exitCode;
|
|
3238
3388
|
});
|
|
@@ -3342,6 +3492,7 @@ function toDropOptions(options) {
|
|
|
3342
3492
|
...options.domain ? { domain: options.domain } : {},
|
|
3343
3493
|
...options.shared ? { shared: true } : {},
|
|
3344
3494
|
...options.slug ? { slug: options.slug } : {},
|
|
3495
|
+
...options.manifest ? { manifest: options.manifest } : {},
|
|
3345
3496
|
...options.json !== void 0 ? { json: options.json } : {},
|
|
3346
3497
|
...options.quiet !== void 0 ? { quiet: options.quiet } : {},
|
|
3347
3498
|
...options.url !== void 0 ? { url: options.url } : {},
|
|
@@ -3354,6 +3505,15 @@ function parseInteger(value) {
|
|
|
3354
3505
|
if (Number.isNaN(n)) throw new import_commander.InvalidArgumentError("Expected an integer.");
|
|
3355
3506
|
return n;
|
|
3356
3507
|
}
|
|
3508
|
+
function parseMode(value) {
|
|
3509
|
+
if (value !== "patch" && value !== "replace") {
|
|
3510
|
+
throw new import_commander.InvalidArgumentError('Use "patch" or "replace".');
|
|
3511
|
+
}
|
|
3512
|
+
return value;
|
|
3513
|
+
}
|
|
3514
|
+
function collect(value, previous) {
|
|
3515
|
+
return [...previous, value];
|
|
3516
|
+
}
|
|
3357
3517
|
async function resolvePublishInputs(inputs, stdin, stdinIsTTY) {
|
|
3358
3518
|
if (inputs.length === 0) {
|
|
3359
3519
|
if (stdinIsTTY) return void 0;
|
|
@@ -3476,7 +3636,7 @@ var showNotice = shouldShowNotice({
|
|
|
3476
3636
|
if (showNotice) {
|
|
3477
3637
|
const notice = noticeFromCache({
|
|
3478
3638
|
cache: updateCache,
|
|
3479
|
-
currentVersion: "0.
|
|
3639
|
+
currentVersion: "0.22.0"
|
|
3480
3640
|
});
|
|
3481
3641
|
if (notice) {
|
|
3482
3642
|
process.stderr.write(`
|