@inblog/cli 0.2.1 → 0.2.3
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/bin/inblog.js +193 -35
- package/dist/bin/inblog.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/inblog.js
CHANGED
|
@@ -242,8 +242,8 @@ var InblogClient = class {
|
|
|
242
242
|
if (this.accessToken) return this.accessToken;
|
|
243
243
|
throw new Error("No valid authentication token available");
|
|
244
244
|
}
|
|
245
|
-
buildUrl(
|
|
246
|
-
const url = new URL(`/api${
|
|
245
|
+
buildUrl(path4, params) {
|
|
246
|
+
const url = new URL(`/api${path4}`, this.baseUrl);
|
|
247
247
|
if (params) {
|
|
248
248
|
for (const [key, value] of Object.entries(params)) {
|
|
249
249
|
if (value === void 0 || value === null) continue;
|
|
@@ -282,8 +282,8 @@ var InblogClient = class {
|
|
|
282
282
|
}
|
|
283
283
|
return body;
|
|
284
284
|
}
|
|
285
|
-
async get(
|
|
286
|
-
const url = this.buildUrl(
|
|
285
|
+
async get(path4, params) {
|
|
286
|
+
const url = this.buildUrl(path4, params);
|
|
287
287
|
const response = await fetch(url, { method: "GET", headers: await this.readHeaders() });
|
|
288
288
|
const json = await this.handleResponse(response);
|
|
289
289
|
return {
|
|
@@ -291,8 +291,8 @@ var InblogClient = class {
|
|
|
291
291
|
meta: extractMeta(json)
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
|
-
async list(
|
|
295
|
-
const url = this.buildUrl(
|
|
294
|
+
async list(path4, params) {
|
|
295
|
+
const url = this.buildUrl(path4, params);
|
|
296
296
|
const response = await fetch(url, { method: "GET", headers: await this.readHeaders() });
|
|
297
297
|
const json = await this.handleResponse(response);
|
|
298
298
|
return {
|
|
@@ -300,8 +300,8 @@ var InblogClient = class {
|
|
|
300
300
|
meta: extractMeta(json)
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
|
-
async create(
|
|
304
|
-
const url = this.buildUrl(
|
|
303
|
+
async create(path4, type, attributes, params) {
|
|
304
|
+
const url = this.buildUrl(path4, params);
|
|
305
305
|
const body = serialize(type, attributes);
|
|
306
306
|
const response = await fetch(url, {
|
|
307
307
|
method: "POST",
|
|
@@ -314,8 +314,8 @@ var InblogClient = class {
|
|
|
314
314
|
meta: extractMeta(json)
|
|
315
315
|
};
|
|
316
316
|
}
|
|
317
|
-
async update(
|
|
318
|
-
const url = this.buildUrl(
|
|
317
|
+
async update(path4, type, id, attributes) {
|
|
318
|
+
const url = this.buildUrl(path4);
|
|
319
319
|
const body = serialize(type, attributes, id);
|
|
320
320
|
const response = await fetch(url, {
|
|
321
321
|
method: "PATCH",
|
|
@@ -328,15 +328,15 @@ var InblogClient = class {
|
|
|
328
328
|
meta: extractMeta(json)
|
|
329
329
|
};
|
|
330
330
|
}
|
|
331
|
-
async delete(
|
|
332
|
-
const url = this.buildUrl(
|
|
331
|
+
async delete(path4) {
|
|
332
|
+
const url = this.buildUrl(path4);
|
|
333
333
|
const response = await fetch(url, { method: "DELETE", headers: await this.readHeaders() });
|
|
334
334
|
if (!response.ok) {
|
|
335
335
|
await this.handleResponse(response);
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
|
-
async post(
|
|
339
|
-
const url = this.buildUrl(
|
|
338
|
+
async post(path4, body) {
|
|
339
|
+
const url = this.buildUrl(path4);
|
|
340
340
|
const response = await fetch(url, {
|
|
341
341
|
method: "POST",
|
|
342
342
|
headers: await this.writeHeaders(),
|
|
@@ -348,8 +348,8 @@ var InblogClient = class {
|
|
|
348
348
|
meta: extractMeta(json)
|
|
349
349
|
};
|
|
350
350
|
}
|
|
351
|
-
async patch(
|
|
352
|
-
const url = this.buildUrl(
|
|
351
|
+
async patch(path4, body) {
|
|
352
|
+
const url = this.buildUrl(path4);
|
|
353
353
|
const response = await fetch(url, {
|
|
354
354
|
method: "PATCH",
|
|
355
355
|
headers: await this.writeHeaders(),
|
|
@@ -364,16 +364,16 @@ var InblogClient = class {
|
|
|
364
364
|
/**
|
|
365
365
|
* Raw GET — for non-JSON:API endpoints that return plain JSON.
|
|
366
366
|
*/
|
|
367
|
-
async rawGet(
|
|
368
|
-
const url = this.buildUrl(
|
|
367
|
+
async rawGet(path4, params) {
|
|
368
|
+
const url = this.buildUrl(path4, params);
|
|
369
369
|
const response = await fetch(url, { method: "GET", headers: await this.readHeaders() });
|
|
370
370
|
return this.handleRawResponse(response);
|
|
371
371
|
}
|
|
372
372
|
/**
|
|
373
373
|
* Raw POST — for non-JSON:API endpoints.
|
|
374
374
|
*/
|
|
375
|
-
async rawPost(
|
|
376
|
-
const url = this.buildUrl(
|
|
375
|
+
async rawPost(path4, body) {
|
|
376
|
+
const url = this.buildUrl(path4);
|
|
377
377
|
const headers = await this.readHeaders();
|
|
378
378
|
headers["Content-Type"] = "application/json";
|
|
379
379
|
const response = await fetch(url, {
|
|
@@ -386,8 +386,8 @@ var InblogClient = class {
|
|
|
386
386
|
/**
|
|
387
387
|
* Raw PATCH — for non-JSON:API endpoints.
|
|
388
388
|
*/
|
|
389
|
-
async rawPatch(
|
|
390
|
-
const url = this.buildUrl(
|
|
389
|
+
async rawPatch(path4, body) {
|
|
390
|
+
const url = this.buildUrl(path4);
|
|
391
391
|
const headers = await this.readHeaders();
|
|
392
392
|
headers["Content-Type"] = "application/json";
|
|
393
393
|
const response = await fetch(url, {
|
|
@@ -400,8 +400,8 @@ var InblogClient = class {
|
|
|
400
400
|
/**
|
|
401
401
|
* Raw DELETE — for non-JSON:API endpoints.
|
|
402
402
|
*/
|
|
403
|
-
async rawDelete(
|
|
404
|
-
const url = this.buildUrl(
|
|
403
|
+
async rawDelete(path4) {
|
|
404
|
+
const url = this.buildUrl(path4);
|
|
405
405
|
const response = await fetch(url, { method: "DELETE", headers: await this.readHeaders() });
|
|
406
406
|
if (response.status === 204) return { success: true };
|
|
407
407
|
return this.handleRawResponse(response);
|
|
@@ -1107,7 +1107,119 @@ function registerAuthCommands(program2) {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
1109
|
// src/commands/posts.ts
|
|
1110
|
-
var
|
|
1110
|
+
var fs4 = __toESM(require("fs"));
|
|
1111
|
+
|
|
1112
|
+
// src/utils/upload.ts
|
|
1113
|
+
var import_node_fs = __toESM(require("fs"));
|
|
1114
|
+
var import_node_path = __toESM(require("path"));
|
|
1115
|
+
var import_node_crypto2 = require("crypto");
|
|
1116
|
+
var WORKER_URL = "https://upload.inblog.dev/";
|
|
1117
|
+
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
1118
|
+
var MIME_TYPES = {
|
|
1119
|
+
".png": "image/png",
|
|
1120
|
+
".jpg": "image/jpeg",
|
|
1121
|
+
".jpeg": "image/jpeg",
|
|
1122
|
+
".gif": "image/gif",
|
|
1123
|
+
".webp": "image/webp",
|
|
1124
|
+
".svg": "image/svg+xml",
|
|
1125
|
+
".ico": "image/x-icon"
|
|
1126
|
+
};
|
|
1127
|
+
function isLocalPath(value) {
|
|
1128
|
+
if (value.startsWith("http://") || value.startsWith("https://")) return false;
|
|
1129
|
+
return import_node_fs.default.existsSync(value);
|
|
1130
|
+
}
|
|
1131
|
+
async function uploadImage(filePath, bucket) {
|
|
1132
|
+
const resolved = import_node_path.default.resolve(filePath);
|
|
1133
|
+
if (!import_node_fs.default.existsSync(resolved)) {
|
|
1134
|
+
throw new Error(`File not found: ${resolved}`);
|
|
1135
|
+
}
|
|
1136
|
+
const stat = import_node_fs.default.statSync(resolved);
|
|
1137
|
+
if (stat.size > MAX_FILE_SIZE) {
|
|
1138
|
+
throw new Error(`File size exceeds 10MB limit: ${(stat.size / 1024 / 1024).toFixed(1)}MB`);
|
|
1139
|
+
}
|
|
1140
|
+
const ext = import_node_path.default.extname(resolved).toLowerCase();
|
|
1141
|
+
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
1142
|
+
const fileKey = `${bucket}/${(/* @__PURE__ */ new Date()).toISOString()}-${(0, import_node_crypto2.randomUUID)()}`;
|
|
1143
|
+
const body = import_node_fs.default.readFileSync(resolved);
|
|
1144
|
+
const response = await fetch(`${WORKER_URL}?fileKey=${fileKey}`, {
|
|
1145
|
+
method: "POST",
|
|
1146
|
+
body,
|
|
1147
|
+
headers: { "Content-Type": contentType }
|
|
1148
|
+
});
|
|
1149
|
+
if (!response.ok) {
|
|
1150
|
+
throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
|
|
1151
|
+
}
|
|
1152
|
+
const data = await response.json();
|
|
1153
|
+
return data.publicUrl;
|
|
1154
|
+
}
|
|
1155
|
+
async function resolveImageUrl(value, bucket) {
|
|
1156
|
+
if (!isLocalPath(value)) return value;
|
|
1157
|
+
return uploadImage(value, bucket);
|
|
1158
|
+
}
|
|
1159
|
+
async function uploadBase64(dataUri, bucket) {
|
|
1160
|
+
const match = dataUri.match(/^data:([^;]+);base64,(.+)$/s);
|
|
1161
|
+
if (!match) throw new Error("Invalid data URI");
|
|
1162
|
+
const contentType = match[1];
|
|
1163
|
+
const body = Buffer.from(match[2], "base64");
|
|
1164
|
+
if (body.length > MAX_FILE_SIZE) {
|
|
1165
|
+
throw new Error(`Base64 image exceeds 10MB limit: ${(body.length / 1024 / 1024).toFixed(1)}MB`);
|
|
1166
|
+
}
|
|
1167
|
+
const fileKey = `${bucket}/${(/* @__PURE__ */ new Date()).toISOString()}-${(0, import_node_crypto2.randomUUID)()}`;
|
|
1168
|
+
const response = await fetch(`${WORKER_URL}?fileKey=${fileKey}`, {
|
|
1169
|
+
method: "POST",
|
|
1170
|
+
body,
|
|
1171
|
+
headers: { "Content-Type": contentType }
|
|
1172
|
+
});
|
|
1173
|
+
if (!response.ok) {
|
|
1174
|
+
throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
|
|
1175
|
+
}
|
|
1176
|
+
const data = await response.json();
|
|
1177
|
+
return data.publicUrl;
|
|
1178
|
+
}
|
|
1179
|
+
async function processContentImages(html) {
|
|
1180
|
+
const imgSrcRegex = /(<img\s[^>]*\bsrc=["'])([^"']+)(["'][^>]*>)/gi;
|
|
1181
|
+
const matches = [];
|
|
1182
|
+
let m;
|
|
1183
|
+
while ((m = imgSrcRegex.exec(html)) !== null) {
|
|
1184
|
+
matches.push({ full: m[0], prefix: m[1], src: m[2], suffix: m[3], index: m.index });
|
|
1185
|
+
}
|
|
1186
|
+
if (matches.length === 0) return { html, uploadCount: 0 };
|
|
1187
|
+
let uploadCount = 0;
|
|
1188
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
1189
|
+
const concurrency = 5;
|
|
1190
|
+
for (let i = 0; i < matches.length; i += concurrency) {
|
|
1191
|
+
const batch = matches.slice(i, i + concurrency);
|
|
1192
|
+
const results = await Promise.allSettled(
|
|
1193
|
+
batch.map(async ({ src }) => {
|
|
1194
|
+
if (src.startsWith("https://source.inblog.dev/") || src.startsWith("https://image.inblog.dev/")) {
|
|
1195
|
+
return null;
|
|
1196
|
+
}
|
|
1197
|
+
if (src.startsWith("data:image/")) {
|
|
1198
|
+
const url = await uploadBase64(src, "post_image");
|
|
1199
|
+
return { src, url };
|
|
1200
|
+
}
|
|
1201
|
+
if (isLocalPath(src)) {
|
|
1202
|
+
const url = await uploadImage(src, "post_image");
|
|
1203
|
+
return { src, url };
|
|
1204
|
+
}
|
|
1205
|
+
return null;
|
|
1206
|
+
})
|
|
1207
|
+
);
|
|
1208
|
+
for (const result of results) {
|
|
1209
|
+
if (result.status === "fulfilled" && result.value) {
|
|
1210
|
+
replacements.set(result.value.src, result.value.url);
|
|
1211
|
+
uploadCount++;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
let processed = html;
|
|
1216
|
+
for (const [src, url] of replacements) {
|
|
1217
|
+
processed = processed.split(src).join(url);
|
|
1218
|
+
}
|
|
1219
|
+
return { html: processed, uploadCount };
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// src/commands/posts.ts
|
|
1111
1223
|
function formatPost(post) {
|
|
1112
1224
|
return [
|
|
1113
1225
|
["ID", post.id],
|
|
@@ -1183,19 +1295,27 @@ Showing page ${meta.page ?? 1} (${data.length} of ${meta.total} posts)`);
|
|
|
1183
1295
|
handleError(error, json);
|
|
1184
1296
|
}
|
|
1185
1297
|
});
|
|
1186
|
-
posts.command("create").description("Create post (draft by default, use --published to publish)").requiredOption("-t, --title <title>", "Post title").option("-s, --slug <slug>", "Post slug").option("-d, --description <desc>", "Post description").option("--content <html>", "HTML content").option("--content-file <path>", "Read HTML content from file").option("--notion-url <url>", "Notion page URL").option("--published", "Publish immediately").option("--tag-ids <ids>", "Comma-separated tag IDs").option("--author-ids <ids>", "Comma-separated author IDs").option("--canonical-url <url>", "Canonical URL").option("--meta-title <title>", "Meta title").option("--meta-description <desc>", "Meta description").action(async function() {
|
|
1298
|
+
posts.command("create").description("Create post (draft by default, use --published to publish)").requiredOption("-t, --title <title>", "Post title").option("-s, --slug <slug>", "Post slug").option("-d, --description <desc>", "Post description").option("--content <html>", "HTML content").option("--content-file <path>", "Read HTML content from file").option("--image <path-or-url>", "Cover image (local file or URL)").option("--notion-url <url>", "Notion page URL").option("--published", "Publish immediately").option("--tag-ids <ids>", "Comma-separated tag IDs").option("--author-ids <ids>", "Comma-separated author IDs").option("--canonical-url <url>", "Canonical URL").option("--meta-title <title>", "Meta title").option("--meta-description <desc>", "Meta description").action(async function() {
|
|
1187
1299
|
const json = isJsonMode(this);
|
|
1188
1300
|
try {
|
|
1189
1301
|
const opts = this.opts();
|
|
1190
1302
|
const { posts: endpoint } = createClientFromCommand(this);
|
|
1191
1303
|
let contentHtml = opts.content;
|
|
1192
1304
|
if (opts.contentFile) {
|
|
1193
|
-
contentHtml =
|
|
1305
|
+
contentHtml = fs4.readFileSync(opts.contentFile, "utf-8");
|
|
1306
|
+
}
|
|
1307
|
+
if (contentHtml) {
|
|
1308
|
+
const { html, uploadCount } = await processContentImages(contentHtml);
|
|
1309
|
+
contentHtml = html;
|
|
1310
|
+
if (uploadCount > 0 && !json) {
|
|
1311
|
+
printWarning(`Uploaded ${uploadCount} image(s) to CDN.`);
|
|
1312
|
+
}
|
|
1194
1313
|
}
|
|
1195
1314
|
const input = { title: opts.title };
|
|
1196
1315
|
if (opts.slug) input.slug = opts.slug;
|
|
1197
1316
|
if (opts.description) input.description = opts.description;
|
|
1198
1317
|
if (contentHtml) input.content_html = contentHtml;
|
|
1318
|
+
if (opts.image) input.image = { url: await resolveImageUrl(opts.image, "featured_image") };
|
|
1199
1319
|
if (opts.notionUrl) input.notion_url = opts.notionUrl;
|
|
1200
1320
|
if (opts.published) input.published = true;
|
|
1201
1321
|
if (opts.canonicalUrl) input.canonical_url = opts.canonicalUrl;
|
|
@@ -1214,20 +1334,28 @@ Showing page ${meta.page ?? 1} (${data.length} of ${meta.total} posts)`);
|
|
|
1214
1334
|
handleError(error, json);
|
|
1215
1335
|
}
|
|
1216
1336
|
});
|
|
1217
|
-
posts.command("update <id>").description("Update post fields (title, slug, content, SEO metadata)").option("-t, --title <title>", "Post title").option("-s, --slug <slug>", "Post slug").option("-d, --description <desc>", "Post description").option("--content <html>", "HTML content").option("--content-file <path>", "Read HTML content from file").option("--canonical-url <url>", "Canonical URL").option("--meta-title <title>", "Meta title").option("--meta-description <desc>", "Meta description").action(async function(id) {
|
|
1337
|
+
posts.command("update <id>").description("Update post fields (title, slug, content, SEO metadata)").option("-t, --title <title>", "Post title").option("-s, --slug <slug>", "Post slug").option("-d, --description <desc>", "Post description").option("--content <html>", "HTML content").option("--content-file <path>", "Read HTML content from file").option("--image <path-or-url>", "Cover image (local file or URL)").option("--canonical-url <url>", "Canonical URL").option("--meta-title <title>", "Meta title").option("--meta-description <desc>", "Meta description").action(async function(id) {
|
|
1218
1338
|
const json = isJsonMode(this);
|
|
1219
1339
|
try {
|
|
1220
1340
|
const opts = this.opts();
|
|
1221
1341
|
const { posts: endpoint } = createClientFromCommand(this);
|
|
1222
1342
|
let contentHtml = opts.content;
|
|
1223
1343
|
if (opts.contentFile) {
|
|
1224
|
-
contentHtml =
|
|
1344
|
+
contentHtml = fs4.readFileSync(opts.contentFile, "utf-8");
|
|
1345
|
+
}
|
|
1346
|
+
if (contentHtml) {
|
|
1347
|
+
const { html, uploadCount } = await processContentImages(contentHtml);
|
|
1348
|
+
contentHtml = html;
|
|
1349
|
+
if (uploadCount > 0 && !json) {
|
|
1350
|
+
printWarning(`Uploaded ${uploadCount} image(s) to CDN.`);
|
|
1351
|
+
}
|
|
1225
1352
|
}
|
|
1226
1353
|
const input = {};
|
|
1227
1354
|
if (opts.title) input.title = opts.title;
|
|
1228
1355
|
if (opts.slug) input.slug = opts.slug;
|
|
1229
1356
|
if (opts.description) input.description = opts.description;
|
|
1230
1357
|
if (contentHtml) input.content_html = contentHtml;
|
|
1358
|
+
if (opts.image) input.image = { url: await resolveImageUrl(opts.image, "featured_image") };
|
|
1231
1359
|
if (opts.canonicalUrl !== void 0) input.canonical_url = opts.canonicalUrl || null;
|
|
1232
1360
|
if (opts.metaTitle !== void 0) input.meta_title = opts.metaTitle || null;
|
|
1233
1361
|
if (opts.metaDescription !== void 0) input.meta_description = opts.metaDescription || null;
|
|
@@ -1822,7 +1950,7 @@ function registerBlogsCommands(program2) {
|
|
|
1822
1950
|
handleError(error, json);
|
|
1823
1951
|
}
|
|
1824
1952
|
});
|
|
1825
|
-
blogs.command("update").description("Update blog title, description, language, or timezone").option("-t, --title <title>", "Blog title").option("-d, --description <desc>", "Blog description").option("--language <lang>", "Blog language").option("--timezone-diff <hours>", "Timezone offset in hours").option("--logo <url>", "Blog logo image URL").option("--favicon <url>", "Blog favicon image URL").option("--og-image <url>", "Blog OG image URL").option("--ga-id <id>", "Google Analytics measurement ID").action(async function() {
|
|
1953
|
+
blogs.command("update").description("Update blog title, description, language, or timezone").option("-t, --title <title>", "Blog title").option("-d, --description <desc>", "Blog description").option("--language <lang>", "Blog language").option("--timezone-diff <hours>", "Timezone offset in hours").option("--logo <path-or-url>", "Blog logo image (local file or URL)").option("--favicon <path-or-url>", "Blog favicon image (local file or URL)").option("--og-image <path-or-url>", "Blog OG image (local file or URL)").option("--ga-id <id>", "Google Analytics measurement ID").action(async function() {
|
|
1826
1954
|
const json = isJsonMode(this);
|
|
1827
1955
|
try {
|
|
1828
1956
|
const opts = this.opts();
|
|
@@ -1832,9 +1960,9 @@ function registerBlogsCommands(program2) {
|
|
|
1832
1960
|
if (opts.description) input.description = opts.description;
|
|
1833
1961
|
if (opts.language) input.blog_language = opts.language;
|
|
1834
1962
|
if (opts.timezoneDiff !== void 0) input.timezone_diff = parseInt(opts.timezoneDiff, 10);
|
|
1835
|
-
if (opts.logo) input.logo = opts.logo;
|
|
1836
|
-
if (opts.favicon) input.favicon = opts.favicon;
|
|
1837
|
-
if (opts.ogImage) input.og_image = opts.ogImage;
|
|
1963
|
+
if (opts.logo) input.logo = await resolveImageUrl(opts.logo, "logo");
|
|
1964
|
+
if (opts.favicon) input.favicon = await resolveImageUrl(opts.favicon, "favicon");
|
|
1965
|
+
if (opts.ogImage) input.og_image = await resolveImageUrl(opts.ogImage, "og_image");
|
|
1838
1966
|
if (opts.gaId) input.ga_measurement_id = opts.gaId;
|
|
1839
1967
|
if (Object.keys(input).length === 0) {
|
|
1840
1968
|
throw new Error("No fields to update. Provide at least one option.");
|
|
@@ -1965,12 +2093,12 @@ function registerBlogsCommands(program2) {
|
|
|
1965
2093
|
handleError(error, json);
|
|
1966
2094
|
}
|
|
1967
2095
|
});
|
|
1968
|
-
banner.command("set").description("Update banner settings").option("--image <url>", "Banner image URL").option("--title <text>", "Banner title text").option("--subtext <text>", "Banner subtext").option("--title-color <hex>", "Banner title color (hex)").option("--bg-color <hex>", "Banner background color (hex)").action(async function() {
|
|
2096
|
+
banner.command("set").description("Update banner settings").option("--image <path-or-url>", "Banner image (local file or URL)").option("--title <text>", "Banner title text").option("--subtext <text>", "Banner subtext").option("--title-color <hex>", "Banner title color (hex)").option("--bg-color <hex>", "Banner background color (hex)").action(async function() {
|
|
1969
2097
|
const json = isJsonMode(this);
|
|
1970
2098
|
try {
|
|
1971
2099
|
const opts = this.opts();
|
|
1972
2100
|
const input = {};
|
|
1973
|
-
if (opts.image) input.banner_url = opts.image;
|
|
2101
|
+
if (opts.image) input.banner_url = await resolveImageUrl(opts.image, "banner");
|
|
1974
2102
|
if (opts.title) input.banner_title = opts.title;
|
|
1975
2103
|
if (opts.subtext) input.banner_subtext = opts.subtext;
|
|
1976
2104
|
if (opts.titleColor) input.banner_title_color = opts.titleColor;
|
|
@@ -2545,6 +2673,35 @@ function registerAnalyticsCommands(program2) {
|
|
|
2545
2673
|
});
|
|
2546
2674
|
}
|
|
2547
2675
|
|
|
2676
|
+
// src/commands/images.ts
|
|
2677
|
+
var VALID_BUCKETS = ["post_image", "featured_image", "logo", "favicon", "og_image", "banner", "avatar"];
|
|
2678
|
+
function registerImagesCommands(program2) {
|
|
2679
|
+
const images = program2.command("images").description("Upload images to inblog CDN");
|
|
2680
|
+
images.command("upload <file...>").description("Upload local image file(s) to inblog CDN").option("-b, --bucket <type>", "Image bucket (post_image, featured_image, logo, favicon, og_image, banner)", "post_image").action(async function(files) {
|
|
2681
|
+
const json = isJsonMode(this);
|
|
2682
|
+
try {
|
|
2683
|
+
const opts = this.opts();
|
|
2684
|
+
const bucket = opts.bucket;
|
|
2685
|
+
if (!VALID_BUCKETS.includes(bucket)) {
|
|
2686
|
+
throw new Error(`Invalid bucket: ${bucket}. Valid: ${VALID_BUCKETS.join(", ")}`);
|
|
2687
|
+
}
|
|
2688
|
+
const results = [];
|
|
2689
|
+
for (const file of files) {
|
|
2690
|
+
const url = await uploadImage(file, bucket);
|
|
2691
|
+
results.push({ file, url });
|
|
2692
|
+
if (!json) {
|
|
2693
|
+
printSuccess(`${file} \u2192 ${url}`);
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
if (json) {
|
|
2697
|
+
printJson(results);
|
|
2698
|
+
}
|
|
2699
|
+
} catch (error) {
|
|
2700
|
+
handleError(error, json);
|
|
2701
|
+
}
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2548
2705
|
// bin/inblog.ts
|
|
2549
2706
|
var program = new import_commander.Command();
|
|
2550
2707
|
program.name("inblog").description("CLI for managing inblog.ai blog content (posts, tags, authors, redirects, forms)").version("0.2.0").option("--json", "Output as JSON (for programmatic use)").option("--base-url <url>", "API base URL").option("--no-color", "Disable colored output");
|
|
@@ -2559,5 +2716,6 @@ registerFormResponsesCommands(program);
|
|
|
2559
2716
|
registerConfigCommands(program);
|
|
2560
2717
|
registerSearchConsoleCommands(program);
|
|
2561
2718
|
registerAnalyticsCommands(program);
|
|
2719
|
+
registerImagesCommands(program);
|
|
2562
2720
|
program.parse();
|
|
2563
2721
|
//# sourceMappingURL=inblog.js.map
|