careervivid 1.7.0 → 1.9.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/api.d.ts +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +4 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +59 -8
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export interface PublishResult {
|
|
|
20
20
|
postId: string;
|
|
21
21
|
url: string;
|
|
22
22
|
message: string;
|
|
23
|
+
title?: string;
|
|
23
24
|
}
|
|
24
25
|
export interface VerifyResult {
|
|
25
26
|
userId: string;
|
|
@@ -39,6 +40,7 @@ export interface ApiError {
|
|
|
39
40
|
}[];
|
|
40
41
|
}
|
|
41
42
|
export declare function publishPost(payload: PublishPayload, dryRun?: boolean): Promise<PublishResult | ApiError>;
|
|
43
|
+
export declare function getPost(postId: string): Promise<PublishResult | ApiError>;
|
|
42
44
|
export declare function updatePost(postId: string, payload: Partial<PublishPayload>): Promise<PublishResult | ApiError>;
|
|
43
45
|
/**
|
|
44
46
|
* Verify an API key against the /verifyAuth endpoint.
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAChD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { getApiKey, getApiUrl } from "./config.js";
|
|
8
8
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
9
|
-
const CLI_VERSION = "1.
|
|
9
|
+
const CLI_VERSION = "1.9.0";
|
|
10
10
|
function requireApiKey() {
|
|
11
11
|
const key = getApiKey();
|
|
12
12
|
if (!key) {
|
|
@@ -73,6 +73,9 @@ export async function publishPost(payload, dryRun = false) {
|
|
|
73
73
|
}
|
|
74
74
|
return apiRequest("POST", "publish", payload);
|
|
75
75
|
}
|
|
76
|
+
export async function getPost(postId) {
|
|
77
|
+
return apiRequest("GET", `publish/${postId}`);
|
|
78
|
+
}
|
|
76
79
|
export async function updatePost(postId, payload) {
|
|
77
80
|
return apiRequest("PATCH", "publish", { ...payload, postId });
|
|
78
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuOpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6J7D"}
|
package/dist/commands/publish.js
CHANGED
|
@@ -55,15 +55,37 @@ async function publishSingleFile(filePath, content, opts, jsonMode) {
|
|
|
55
55
|
const dryRun = !!opts.dryRun;
|
|
56
56
|
// ── Parse Frontmatter ───────────────────────────────────────────
|
|
57
57
|
let postId = undefined;
|
|
58
|
+
let frontmatterTags = [];
|
|
58
59
|
let cleanContent = content;
|
|
59
60
|
// Robust frontmatter extraction (multiline, flexible spacing)
|
|
60
|
-
|
|
61
|
+
// Matches --- start, any non-greedy content, and --- end with optional whitespace/newlines
|
|
62
|
+
const frontmatterMatch = content.match(/^---\s*[\r\n]+([\s\S]*?)[\r\n]+---/);
|
|
61
63
|
if (frontmatterMatch) {
|
|
62
64
|
const fm = frontmatterMatch[1];
|
|
63
65
|
// Match postId with potential leading/trailing whitespace or quotes
|
|
64
66
|
const idMatch = fm.match(/postId:\s*["']?([a-zA-Z0-9_-]+)["']?/i);
|
|
65
67
|
postId = idMatch?.[1];
|
|
66
|
-
|
|
68
|
+
// Match tags: [tag1, tag2] or tags: tag1, tag2
|
|
69
|
+
const tagsMatch = fm.match(/tags:\s*(?:\[(.*?)\]|(.*))/i);
|
|
70
|
+
if (tagsMatch) {
|
|
71
|
+
const tagsStr = tagsMatch[1] || tagsMatch[2];
|
|
72
|
+
frontmatterTags = tagsStr
|
|
73
|
+
?.split(",")
|
|
74
|
+
.map(t => t.trim().replace(/^["']|["']$/g, ""))
|
|
75
|
+
.filter(Boolean) || [];
|
|
76
|
+
}
|
|
77
|
+
// Remove the frontmatter block AND any trailing whitespace/newlines
|
|
78
|
+
const afterFm = content.slice(frontmatterMatch[0].length);
|
|
79
|
+
cleanContent = afterFm.replace(/^\s+/, "");
|
|
80
|
+
}
|
|
81
|
+
// Best Practice: Also look for "Tags: #tag1, #tag2" at the bottom of the article
|
|
82
|
+
const footerTagsMatch = cleanContent.match(/Tags:\s*(.*)$/im);
|
|
83
|
+
let footerTags = [];
|
|
84
|
+
if (footerTagsMatch) {
|
|
85
|
+
footerTags = footerTagsMatch[1]
|
|
86
|
+
.split(/[,\s]+/)
|
|
87
|
+
.map(t => t.trim().replace(/^#/, ""))
|
|
88
|
+
.filter(Boolean);
|
|
67
89
|
}
|
|
68
90
|
// Fail if onlyUpdate is set but no postId is found
|
|
69
91
|
if (opts.onlyUpdate && !postId) {
|
|
@@ -77,7 +99,7 @@ async function publishSingleFile(filePath, content, opts, jsonMode) {
|
|
|
77
99
|
const type = opts.type || inferType(format);
|
|
78
100
|
let title = opts.title || "";
|
|
79
101
|
if (!title && format === "markdown") {
|
|
80
|
-
const firstHeading = cleanContent.match(
|
|
102
|
+
const firstHeading = cleanContent.match(/^[#]{1,2}\s+(.+)$/m);
|
|
81
103
|
if (firstHeading) {
|
|
82
104
|
title = firstHeading[1].trim();
|
|
83
105
|
}
|
|
@@ -98,21 +120,50 @@ async function publishSingleFile(filePath, content, opts, jsonMode) {
|
|
|
98
120
|
title = answers.title.trim();
|
|
99
121
|
}
|
|
100
122
|
}
|
|
101
|
-
const tags =
|
|
102
|
-
|
|
103
|
-
|
|
123
|
+
const tags = [
|
|
124
|
+
...frontmatterTags,
|
|
125
|
+
...footerTags,
|
|
126
|
+
...(opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [])
|
|
127
|
+
];
|
|
128
|
+
// De-duplicate and limit to 5 tags
|
|
129
|
+
const finalTags = [...new Set(tags)].slice(0, 5);
|
|
104
130
|
const payload = {
|
|
105
131
|
type,
|
|
106
132
|
dataFormat: format,
|
|
107
133
|
title,
|
|
108
134
|
content: cleanContent,
|
|
109
|
-
tags,
|
|
135
|
+
tags: finalTags,
|
|
110
136
|
...(opts.cover ? { coverImage: opts.cover } : {}),
|
|
111
137
|
...(opts.official ? { isOfficialPost: true } : {}),
|
|
112
138
|
};
|
|
113
139
|
let result;
|
|
114
140
|
if (postId && !dryRun) {
|
|
115
|
-
const { updatePost } = await import("../api.js");
|
|
141
|
+
const { updatePost, getPost } = await import("../api.js");
|
|
142
|
+
// Best Practice: Fetch remote title to verify identity before overwrite
|
|
143
|
+
const remotePost = await getPost(postId);
|
|
144
|
+
if (!isApiError(remotePost)) {
|
|
145
|
+
const remoteTitle = remotePost.title;
|
|
146
|
+
// Case-insensitive title comparison to catch potential mixups
|
|
147
|
+
if (title && remoteTitle && title.toLowerCase() !== remoteTitle.toLowerCase()) {
|
|
148
|
+
if (jsonMode) {
|
|
149
|
+
console.error(chalk.red(`\n ✖ Title mismatch for ${postId}. Local: "${title}", Remote: "${remoteTitle}". Aborting.`));
|
|
150
|
+
return { success: false };
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const enquirer = (await import("enquirer"));
|
|
154
|
+
const prompt = enquirer.default?.prompt || enquirer.prompt;
|
|
155
|
+
const answers = await prompt({
|
|
156
|
+
type: "confirm",
|
|
157
|
+
name: "confirm",
|
|
158
|
+
message: `Title Mismatch! Local: "${chalk.cyan(title)}", Remote: "${chalk.yellow(remoteTitle)}". Continue?`,
|
|
159
|
+
initial: false
|
|
160
|
+
});
|
|
161
|
+
if (!answers.confirm) {
|
|
162
|
+
return { success: false };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
116
167
|
result = await updatePost(postId, payload);
|
|
117
168
|
}
|
|
118
169
|
else {
|