delivered-cli 0.2.0 → 0.3.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/dist/index.js +72 -40
- package/package.json +1 -1
- package/src/index.ts +94 -39
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ const program = new commander_1.Command();
|
|
|
52
52
|
program
|
|
53
53
|
.name("delivered")
|
|
54
54
|
.description("CLI for delivered.md - Focus. Ship. Repeat.")
|
|
55
|
-
.version("0.
|
|
55
|
+
.version("0.3.0");
|
|
56
56
|
// Helper to get API key
|
|
57
57
|
function getApiKey() {
|
|
58
58
|
const apiKey = config.get("apiKey");
|
|
@@ -159,13 +159,25 @@ program
|
|
|
159
159
|
process.exit(1);
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
|
-
//
|
|
162
|
+
// Download command
|
|
163
163
|
program
|
|
164
|
-
.command("
|
|
165
|
-
.description("Download your page as markdown")
|
|
166
|
-
.
|
|
167
|
-
.action(async (options) => {
|
|
164
|
+
.command("download")
|
|
165
|
+
.description("Download your page as markdown to current directory")
|
|
166
|
+
.action(async () => {
|
|
168
167
|
try {
|
|
168
|
+
// Get username first
|
|
169
|
+
const whoamiResponse = await apiRequest("/whoami");
|
|
170
|
+
if (!whoamiResponse.ok) {
|
|
171
|
+
console.error("Error: Failed to get user info");
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
const userInfo = await whoamiResponse.json();
|
|
175
|
+
const username = userInfo.username;
|
|
176
|
+
if (!username) {
|
|
177
|
+
console.error("Error: No username set. Visit https://app.delivered.md to claim a username first.");
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
// Fetch page content
|
|
169
181
|
const response = await apiRequest("/page");
|
|
170
182
|
if (!response.ok) {
|
|
171
183
|
const error = await response.json();
|
|
@@ -174,62 +186,82 @@ program
|
|
|
174
186
|
}
|
|
175
187
|
const data = await response.json();
|
|
176
188
|
const markdown = data.content;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
// Output to stdout
|
|
184
|
-
console.log(markdown);
|
|
185
|
-
}
|
|
189
|
+
// Save to current directory as {username}.md
|
|
190
|
+
const filename = `${username}.md`;
|
|
191
|
+
const outputPath = path.resolve(process.cwd(), filename);
|
|
192
|
+
fs.writeFileSync(outputPath, markdown);
|
|
193
|
+
console.log(`\nDownloaded your page to ./${filename}`);
|
|
186
194
|
}
|
|
187
195
|
catch (error) {
|
|
188
|
-
console.error("Error: Failed to
|
|
196
|
+
console.error("Error: Failed to download page");
|
|
189
197
|
process.exit(1);
|
|
190
198
|
}
|
|
191
199
|
});
|
|
192
|
-
//
|
|
200
|
+
// Upload command
|
|
193
201
|
program
|
|
194
|
-
.command("
|
|
195
|
-
.description("Upload markdown
|
|
202
|
+
.command("upload")
|
|
203
|
+
.description("Upload a markdown file to your page")
|
|
204
|
+
.argument("<file>", "Path to markdown file")
|
|
196
205
|
.action(async (file) => {
|
|
197
206
|
try {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
console.error(`Error: File not found: ${filePath}`);
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
content = fs.readFileSync(filePath, "utf-8");
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
// Read from stdin
|
|
210
|
-
const chunks = [];
|
|
211
|
-
for await (const chunk of process.stdin) {
|
|
212
|
-
chunks.push(chunk);
|
|
213
|
-
}
|
|
214
|
-
content = Buffer.concat(chunks).toString("utf-8");
|
|
207
|
+
// Read from file
|
|
208
|
+
const filePath = path.resolve(file);
|
|
209
|
+
if (!fs.existsSync(filePath)) {
|
|
210
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
211
|
+
process.exit(1);
|
|
215
212
|
}
|
|
213
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
216
214
|
if (!content.trim()) {
|
|
217
|
-
console.error("Error:
|
|
215
|
+
console.error("Error: File is empty");
|
|
218
216
|
process.exit(1);
|
|
219
217
|
}
|
|
218
|
+
// Check file size locally first (100KB limit)
|
|
219
|
+
const sizeBytes = Buffer.byteLength(content, "utf-8");
|
|
220
|
+
const maxSizeBytes = 100 * 1024;
|
|
221
|
+
if (sizeBytes > maxSizeBytes) {
|
|
222
|
+
const wordCount = content.trim().split(/\s+/).filter(Boolean).length;
|
|
223
|
+
const maxWords = Math.floor(maxSizeBytes / 6);
|
|
224
|
+
console.error(`\nError: File too large.`);
|
|
225
|
+
console.error(`Your file: ~${wordCount.toLocaleString()} words (${Math.round(sizeBytes / 1024)}KB)`);
|
|
226
|
+
console.error(`Maximum: ~${maxWords.toLocaleString()} words (100KB)`);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
// Upload
|
|
220
230
|
const response = await apiRequest("/page", {
|
|
221
231
|
method: "PUT",
|
|
222
232
|
body: JSON.stringify({ content }),
|
|
223
233
|
});
|
|
224
234
|
if (!response.ok) {
|
|
225
235
|
const error = await response.json();
|
|
226
|
-
|
|
236
|
+
// Handle specific error types
|
|
237
|
+
if (error.error === "FILE_TOO_LARGE") {
|
|
238
|
+
console.error(`\nError: File too large.`);
|
|
239
|
+
console.error(`Your file: ~${error.wordCount?.toLocaleString() || "?"} words (${Math.round((error.currentSize || 0) / 1024)}KB)`);
|
|
240
|
+
console.error(`Maximum: ~${error.maxWords?.toLocaleString() || "16,000"} words (100KB)`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
if (error.error === "RATE_LIMIT") {
|
|
244
|
+
console.error(`\nError: Upload limit reached (${error.maxUploads || 50}/day).`);
|
|
245
|
+
console.error(`You can upload again in ${error.nextUploadIn || "a while"}.`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
console.error(`Error: ${error.message || error.error || "Failed to upload"}`);
|
|
227
249
|
process.exit(1);
|
|
228
250
|
}
|
|
229
|
-
|
|
251
|
+
// Get username for the success message
|
|
252
|
+
const whoamiResponse = await apiRequest("/whoami");
|
|
253
|
+
let pageUrl = "https://delivered.md";
|
|
254
|
+
if (whoamiResponse.ok) {
|
|
255
|
+
const userInfo = await whoamiResponse.json();
|
|
256
|
+
if (userInfo.username) {
|
|
257
|
+
pageUrl = `https://delivered.md/${userInfo.username}`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
console.log(`\nUploaded successfully!`);
|
|
261
|
+
console.log(`View your page: ${pageUrl}`);
|
|
230
262
|
}
|
|
231
263
|
catch (error) {
|
|
232
|
-
console.error("Error: Failed to
|
|
264
|
+
console.error("Error: Failed to upload page");
|
|
233
265
|
process.exit(1);
|
|
234
266
|
}
|
|
235
267
|
});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ const program = new Command();
|
|
|
19
19
|
program
|
|
20
20
|
.name("delivered")
|
|
21
21
|
.description("CLI for delivered.md - Focus. Ship. Repeat.")
|
|
22
|
-
.version("0.
|
|
22
|
+
.version("0.3.0");
|
|
23
23
|
|
|
24
24
|
// Helper to get API key
|
|
25
25
|
function getApiKey(): string {
|
|
@@ -142,13 +142,29 @@ program
|
|
|
142
142
|
}
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
//
|
|
145
|
+
// Download command
|
|
146
146
|
program
|
|
147
|
-
.command("
|
|
148
|
-
.description("Download your page as markdown")
|
|
149
|
-
.
|
|
150
|
-
.action(async (options) => {
|
|
147
|
+
.command("download")
|
|
148
|
+
.description("Download your page as markdown to current directory")
|
|
149
|
+
.action(async () => {
|
|
151
150
|
try {
|
|
151
|
+
// Get username first
|
|
152
|
+
const whoamiResponse = await apiRequest("/whoami");
|
|
153
|
+
if (!whoamiResponse.ok) {
|
|
154
|
+
console.error("Error: Failed to get user info");
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
const userInfo = await whoamiResponse.json();
|
|
158
|
+
const username = userInfo.username;
|
|
159
|
+
|
|
160
|
+
if (!username) {
|
|
161
|
+
console.error(
|
|
162
|
+
"Error: No username set. Visit https://app.delivered.md to claim a username first.",
|
|
163
|
+
);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Fetch page content
|
|
152
168
|
const response = await apiRequest("/page");
|
|
153
169
|
|
|
154
170
|
if (!response.ok) {
|
|
@@ -160,50 +176,53 @@ program
|
|
|
160
176
|
const data = await response.json();
|
|
161
177
|
const markdown = data.content;
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
console.log(markdown);
|
|
170
|
-
}
|
|
179
|
+
// Save to current directory as {username}.md
|
|
180
|
+
const filename = `${username}.md`;
|
|
181
|
+
const outputPath = path.resolve(process.cwd(), filename);
|
|
182
|
+
fs.writeFileSync(outputPath, markdown);
|
|
183
|
+
|
|
184
|
+
console.log(`\nDownloaded your page to ./${filename}`);
|
|
171
185
|
} catch (error) {
|
|
172
|
-
console.error("Error: Failed to
|
|
186
|
+
console.error("Error: Failed to download page");
|
|
173
187
|
process.exit(1);
|
|
174
188
|
}
|
|
175
189
|
});
|
|
176
190
|
|
|
177
|
-
//
|
|
191
|
+
// Upload command
|
|
178
192
|
program
|
|
179
|
-
.command("
|
|
180
|
-
.description("Upload markdown
|
|
193
|
+
.command("upload")
|
|
194
|
+
.description("Upload a markdown file to your page")
|
|
195
|
+
.argument("<file>", "Path to markdown file")
|
|
181
196
|
.action(async (file) => {
|
|
182
197
|
try {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (!fs.existsSync(filePath)) {
|
|
189
|
-
console.error(`Error: File not found: ${filePath}`);
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}
|
|
192
|
-
content = fs.readFileSync(filePath, "utf-8");
|
|
193
|
-
} else {
|
|
194
|
-
// Read from stdin
|
|
195
|
-
const chunks: Buffer[] = [];
|
|
196
|
-
for await (const chunk of process.stdin) {
|
|
197
|
-
chunks.push(chunk);
|
|
198
|
-
}
|
|
199
|
-
content = Buffer.concat(chunks).toString("utf-8");
|
|
198
|
+
// Read from file
|
|
199
|
+
const filePath = path.resolve(file);
|
|
200
|
+
if (!fs.existsSync(filePath)) {
|
|
201
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
202
|
+
process.exit(1);
|
|
200
203
|
}
|
|
204
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
201
205
|
|
|
202
206
|
if (!content.trim()) {
|
|
203
|
-
console.error("Error:
|
|
207
|
+
console.error("Error: File is empty");
|
|
204
208
|
process.exit(1);
|
|
205
209
|
}
|
|
206
210
|
|
|
211
|
+
// Check file size locally first (100KB limit)
|
|
212
|
+
const sizeBytes = Buffer.byteLength(content, "utf-8");
|
|
213
|
+
const maxSizeBytes = 100 * 1024;
|
|
214
|
+
if (sizeBytes > maxSizeBytes) {
|
|
215
|
+
const wordCount = content.trim().split(/\s+/).filter(Boolean).length;
|
|
216
|
+
const maxWords = Math.floor(maxSizeBytes / 6);
|
|
217
|
+
console.error(`\nError: File too large.`);
|
|
218
|
+
console.error(
|
|
219
|
+
`Your file: ~${wordCount.toLocaleString()} words (${Math.round(sizeBytes / 1024)}KB)`,
|
|
220
|
+
);
|
|
221
|
+
console.error(`Maximum: ~${maxWords.toLocaleString()} words (100KB)`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Upload
|
|
207
226
|
const response = await apiRequest("/page", {
|
|
208
227
|
method: "PUT",
|
|
209
228
|
body: JSON.stringify({ content }),
|
|
@@ -211,13 +230,49 @@ program
|
|
|
211
230
|
|
|
212
231
|
if (!response.ok) {
|
|
213
232
|
const error = await response.json();
|
|
214
|
-
|
|
233
|
+
|
|
234
|
+
// Handle specific error types
|
|
235
|
+
if (error.error === "FILE_TOO_LARGE") {
|
|
236
|
+
console.error(`\nError: File too large.`);
|
|
237
|
+
console.error(
|
|
238
|
+
`Your file: ~${error.wordCount?.toLocaleString() || "?"} words (${Math.round((error.currentSize || 0) / 1024)}KB)`,
|
|
239
|
+
);
|
|
240
|
+
console.error(
|
|
241
|
+
`Maximum: ~${error.maxWords?.toLocaleString() || "16,000"} words (100KB)`,
|
|
242
|
+
);
|
|
243
|
+
process.exit(1);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (error.error === "RATE_LIMIT") {
|
|
247
|
+
console.error(
|
|
248
|
+
`\nError: Upload limit reached (${error.maxUploads || 50}/day).`,
|
|
249
|
+
);
|
|
250
|
+
console.error(
|
|
251
|
+
`You can upload again in ${error.nextUploadIn || "a while"}.`,
|
|
252
|
+
);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
console.error(
|
|
257
|
+
`Error: ${error.message || error.error || "Failed to upload"}`,
|
|
258
|
+
);
|
|
215
259
|
process.exit(1);
|
|
216
260
|
}
|
|
217
261
|
|
|
218
|
-
|
|
262
|
+
// Get username for the success message
|
|
263
|
+
const whoamiResponse = await apiRequest("/whoami");
|
|
264
|
+
let pageUrl = "https://delivered.md";
|
|
265
|
+
if (whoamiResponse.ok) {
|
|
266
|
+
const userInfo = await whoamiResponse.json();
|
|
267
|
+
if (userInfo.username) {
|
|
268
|
+
pageUrl = `https://delivered.md/${userInfo.username}`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
console.log(`\nUploaded successfully!`);
|
|
273
|
+
console.log(`View your page: ${pageUrl}`);
|
|
219
274
|
} catch (error) {
|
|
220
|
-
console.error("Error: Failed to
|
|
275
|
+
console.error("Error: Failed to upload page");
|
|
221
276
|
process.exit(1);
|
|
222
277
|
}
|
|
223
278
|
});
|