@dropthis/cli 0.20.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 +172 -49
- 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-CSahv_jA.d.cts} +70 -4
- package/node_modules/@dropthis/node/dist/{drops-C92Gkuqx.d.ts → drops-CSahv_jA.d.ts} +70 -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
|
});
|
|
@@ -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();
|
|
@@ -1986,6 +2077,23 @@ async function runUpdateContent(target, input, raw, deps) {
|
|
|
1986
2077
|
const resolved = await resolveDropTarget(target, resolveDeps);
|
|
1987
2078
|
if (!resolved.ok) return { exitCode: resolved.exitCode };
|
|
1988
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
|
+
}
|
|
1989
2097
|
if (raw.dryRun) {
|
|
1990
2098
|
return handleDryRun(dropId, input, raw, deps);
|
|
1991
2099
|
}
|
|
@@ -2478,7 +2586,7 @@ function createContext(input) {
|
|
|
2478
2586
|
}
|
|
2479
2587
|
|
|
2480
2588
|
// src/storage.ts
|
|
2481
|
-
var
|
|
2589
|
+
var import_promises4 = require("fs/promises");
|
|
2482
2590
|
var import_node_os = require("os");
|
|
2483
2591
|
var import_node_path2 = require("path");
|
|
2484
2592
|
var import_keyring = require("@napi-rs/keyring");
|
|
@@ -2512,7 +2620,7 @@ var InsecureFileCredentialStore = class {
|
|
|
2512
2620
|
});
|
|
2513
2621
|
}
|
|
2514
2622
|
async clear() {
|
|
2515
|
-
await (0,
|
|
2623
|
+
await (0, import_promises4.rm)(this.filePath, { force: true });
|
|
2516
2624
|
}
|
|
2517
2625
|
};
|
|
2518
2626
|
var KeyringCredentialStore = class {
|
|
@@ -2539,7 +2647,7 @@ var KeyringCredentialStore = class {
|
|
|
2539
2647
|
}
|
|
2540
2648
|
async clear() {
|
|
2541
2649
|
await this.keyring.deletePassword();
|
|
2542
|
-
await (0,
|
|
2650
|
+
await (0, import_promises4.rm)(this.filePath, { force: true });
|
|
2543
2651
|
}
|
|
2544
2652
|
};
|
|
2545
2653
|
function createCredentialStore(options = {}) {
|
|
@@ -2564,7 +2672,7 @@ function credentialPath(configDir) {
|
|
|
2564
2672
|
}
|
|
2565
2673
|
async function readJsonFile(path) {
|
|
2566
2674
|
try {
|
|
2567
|
-
return JSON.parse(await (0,
|
|
2675
|
+
return JSON.parse(await (0, import_promises4.readFile)(path, "utf8"));
|
|
2568
2676
|
} catch (error2) {
|
|
2569
2677
|
if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
|
|
2570
2678
|
return null;
|
|
@@ -2573,18 +2681,18 @@ async function readJsonFile(path) {
|
|
|
2573
2681
|
}
|
|
2574
2682
|
}
|
|
2575
2683
|
async function writeCredentialFile(path, credential) {
|
|
2576
|
-
await (0,
|
|
2684
|
+
await (0, import_promises4.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
2577
2685
|
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
2578
|
-
await (0,
|
|
2686
|
+
await (0, import_promises4.writeFile)(tmpPath, `${JSON.stringify(credential, null, 2)}
|
|
2579
2687
|
`, {
|
|
2580
2688
|
mode: 384
|
|
2581
2689
|
});
|
|
2582
|
-
await (0,
|
|
2583
|
-
await (0,
|
|
2690
|
+
await (0, import_promises4.chmod)(tmpPath, 384);
|
|
2691
|
+
await (0, import_promises4.rename)(tmpPath, path);
|
|
2584
2692
|
}
|
|
2585
2693
|
|
|
2586
2694
|
// src/typo-guard.ts
|
|
2587
|
-
var
|
|
2695
|
+
var import_promises5 = require("fs/promises");
|
|
2588
2696
|
function levenshtein(a, b) {
|
|
2589
2697
|
if (a === b) return 0;
|
|
2590
2698
|
if (a.length === 0) return b.length;
|
|
@@ -2625,7 +2733,7 @@ function isBareWordToken(token) {
|
|
|
2625
2733
|
}
|
|
2626
2734
|
async function pathExists(path) {
|
|
2627
2735
|
try {
|
|
2628
|
-
await (0,
|
|
2736
|
+
await (0, import_promises5.stat)(path);
|
|
2629
2737
|
return true;
|
|
2630
2738
|
} catch {
|
|
2631
2739
|
return false;
|
|
@@ -2659,7 +2767,7 @@ function buildProgram(options = {}) {
|
|
|
2659
2767
|
` ${import_picocolors6.default.cyan("dropthis login")}`,
|
|
2660
2768
|
` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
|
|
2661
2769
|
].join("\n")
|
|
2662
|
-
).version("0.
|
|
2770
|
+
).version("0.21.0").configureHelp({
|
|
2663
2771
|
subcommandTerm(cmd) {
|
|
2664
2772
|
const args = cmd.registeredArguments.map((a) => {
|
|
2665
2773
|
const name = a.name();
|
|
@@ -2710,6 +2818,9 @@ ${lines.map((l) => ` ${l}`).join("\n")}
|
|
|
2710
2818
|
).option(
|
|
2711
2819
|
"--slug <vanity-slug>",
|
|
2712
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."
|
|
2713
2824
|
).option("--url", "Print only the published URL (no JSON envelope)").option(
|
|
2714
2825
|
"--dry-run",
|
|
2715
2826
|
"Show what would be published without publishing (JSON; cannot combine with --url)"
|
|
@@ -2740,7 +2851,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2740
2851
|
].join("\n")
|
|
2741
2852
|
).action(async (inputs, commandOptions) => {
|
|
2742
2853
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2743
|
-
if (inputs.length === 0 && stdinIsTTY) {
|
|
2854
|
+
if (inputs.length === 0 && stdinIsTTY && !commandOptions.manifest) {
|
|
2744
2855
|
program.outputHelp();
|
|
2745
2856
|
return;
|
|
2746
2857
|
}
|
|
@@ -2752,16 +2863,22 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2752
2863
|
stdinIsTTY
|
|
2753
2864
|
);
|
|
2754
2865
|
let publishInput;
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
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
|
+
}
|
|
2765
2882
|
}
|
|
2766
2883
|
if (deps.outputMode === "human" && deps.interactive && inputs.length === 1 && typeof publishInput === "string" && isBareWordToken(publishInput) && !await pathExists(publishInput)) {
|
|
2767
2884
|
const suggestion = suggestCommand(
|
|
@@ -2806,6 +2923,9 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2806
2923
|
"--content-type <mime>",
|
|
2807
2924
|
"Override MIME type (auto-detected from extension)"
|
|
2808
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(
|
|
2809
2929
|
"--if-revision <n>",
|
|
2810
2930
|
"Fail if current revision doesn't match (optimistic lock)",
|
|
2811
2931
|
parseInteger
|
|
@@ -2820,20 +2940,22 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
2820
2940
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2821
2941
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2822
2942
|
let updateInput;
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
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
|
+
}
|
|
2837
2959
|
}
|
|
2838
2960
|
let dropOpts;
|
|
2839
2961
|
try {
|
|
@@ -3232,7 +3354,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3232
3354
|
);
|
|
3233
3355
|
const result = await runUpgrade(commandOptions, {
|
|
3234
3356
|
...deps,
|
|
3235
|
-
currentVersion: "0.
|
|
3357
|
+
currentVersion: "0.21.0"
|
|
3236
3358
|
});
|
|
3237
3359
|
process.exitCode = result.exitCode;
|
|
3238
3360
|
});
|
|
@@ -3342,6 +3464,7 @@ function toDropOptions(options) {
|
|
|
3342
3464
|
...options.domain ? { domain: options.domain } : {},
|
|
3343
3465
|
...options.shared ? { shared: true } : {},
|
|
3344
3466
|
...options.slug ? { slug: options.slug } : {},
|
|
3467
|
+
...options.manifest ? { manifest: options.manifest } : {},
|
|
3345
3468
|
...options.json !== void 0 ? { json: options.json } : {},
|
|
3346
3469
|
...options.quiet !== void 0 ? { quiet: options.quiet } : {},
|
|
3347
3470
|
...options.url !== void 0 ? { url: options.url } : {},
|
|
@@ -3476,7 +3599,7 @@ var showNotice = shouldShowNotice({
|
|
|
3476
3599
|
if (showNotice) {
|
|
3477
3600
|
const notice = noticeFromCache({
|
|
3478
3601
|
cache: updateCache,
|
|
3479
|
-
currentVersion: "0.
|
|
3602
|
+
currentVersion: "0.21.0"
|
|
3480
3603
|
});
|
|
3481
3604
|
if (notice) {
|
|
3482
3605
|
process.stderr.write(`
|