@wenyan-md/core 3.0.3 → 3.0.4
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/core.js +1 -1
- package/dist/publish.js +53 -0
- package/dist/types/credentialStore.d.ts +24 -0
- package/dist/types/node/configStore.d.ts +0 -1
- package/dist/types/node/credentialStoreNodeAdapter.d.ts +7 -0
- package/dist/types/node/publish.d.ts +2 -0
- package/dist/types/node/types.d.ts +2 -1
- package/dist/types/node/utils.d.ts +1 -0
- package/dist/types/publish.d.ts +1 -0
- package/dist/wrapper.js +128 -84
- package/package.json +5 -2
package/dist/core.js
CHANGED
|
@@ -1087,7 +1087,7 @@ function transformUl(ulElement) {
|
|
|
1087
1087
|
function tableToAsciiArt(table) {
|
|
1088
1088
|
const rowsElements = Array.from(table.querySelectorAll("tr"));
|
|
1089
1089
|
const rows = rowsElements.map(
|
|
1090
|
-
(tr) => Array.from(tr.querySelectorAll("th, td")).map((td) => td.
|
|
1090
|
+
(tr) => Array.from(tr.querySelectorAll("th, td")).map((td) => (td?.textContent || "").trim())
|
|
1091
1091
|
);
|
|
1092
1092
|
if (rows.length === 0) return "";
|
|
1093
1093
|
const columnWidths = rows[0].map(
|
package/dist/publish.js
CHANGED
|
@@ -107,6 +107,57 @@ class UploadCacheStore {
|
|
|
107
107
|
return this.adapter.calcHash(buffer);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
+
const defaultCredential = {};
|
|
111
|
+
class CredentialStore {
|
|
112
|
+
credential = { ...defaultCredential };
|
|
113
|
+
adapter;
|
|
114
|
+
initPromise;
|
|
115
|
+
constructor(adapter) {
|
|
116
|
+
this.adapter = adapter;
|
|
117
|
+
this.initPromise = this.load();
|
|
118
|
+
}
|
|
119
|
+
async load() {
|
|
120
|
+
try {
|
|
121
|
+
const loadedData = await this.adapter.loadCredential();
|
|
122
|
+
if (loadedData) {
|
|
123
|
+
this.credential = loadedData;
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
throw new Error(`无法加载凭据: ${error instanceof Error ? error.message : String(error)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async save() {
|
|
130
|
+
try {
|
|
131
|
+
await this.adapter.saveCredential(this.credential);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
throw new Error(`无法保存凭据: ${error instanceof Error ? error.message : String(error)}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async _getWechatCredential() {
|
|
137
|
+
await this.initPromise;
|
|
138
|
+
return this.credential.wechat ?? {};
|
|
139
|
+
}
|
|
140
|
+
async getWechatCredential(appId) {
|
|
141
|
+
const wechat = await this._getWechatCredential();
|
|
142
|
+
if (!wechat) return null;
|
|
143
|
+
const appSecret = wechat[appId];
|
|
144
|
+
if (!appSecret) return null;
|
|
145
|
+
return { appId, appSecret };
|
|
146
|
+
}
|
|
147
|
+
async saveWechatCredential(appId, appSecret) {
|
|
148
|
+
await this.initPromise;
|
|
149
|
+
this.credential.wechat ??= {};
|
|
150
|
+
this.credential.wechat[appId] = appSecret;
|
|
151
|
+
await this.save();
|
|
152
|
+
}
|
|
153
|
+
async deleteWechatCredential(appId) {
|
|
154
|
+
await this.initPromise;
|
|
155
|
+
if (this.credential.wechat) {
|
|
156
|
+
delete this.credential.wechat[appId];
|
|
157
|
+
await this.save();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
110
161
|
class WechatPublisher {
|
|
111
162
|
tokenStore;
|
|
112
163
|
uploadCacheStore;
|
|
@@ -166,8 +217,10 @@ class WechatPublisher {
|
|
|
166
217
|
}
|
|
167
218
|
}
|
|
168
219
|
export {
|
|
220
|
+
CredentialStore,
|
|
169
221
|
TokenStore,
|
|
170
222
|
UploadCacheStore,
|
|
171
223
|
WechatPublisher,
|
|
224
|
+
defaultCredential,
|
|
172
225
|
defaultTokenCache
|
|
173
226
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface WenyanCredential {
|
|
2
|
+
wechat?: Record<string, string>;
|
|
3
|
+
}
|
|
4
|
+
export declare const defaultCredential: WenyanCredential;
|
|
5
|
+
export interface CredentialStorageAdapter {
|
|
6
|
+
loadCredential(): Promise<WenyanCredential | null>;
|
|
7
|
+
saveCredential(credential: WenyanCredential): Promise<void>;
|
|
8
|
+
clearCredential(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare class CredentialStore {
|
|
11
|
+
private credential;
|
|
12
|
+
private adapter;
|
|
13
|
+
private initPromise;
|
|
14
|
+
constructor(adapter: CredentialStorageAdapter);
|
|
15
|
+
private load;
|
|
16
|
+
private save;
|
|
17
|
+
private _getWechatCredential;
|
|
18
|
+
getWechatCredential(appId: string): Promise<{
|
|
19
|
+
appId: string;
|
|
20
|
+
appSecret: string;
|
|
21
|
+
} | null>;
|
|
22
|
+
saveWechatCredential(appId: string, appSecret: string): Promise<void>;
|
|
23
|
+
deleteWechatCredential(appId: string): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CredentialStorageAdapter, WenyanCredential } from "../credentialStore.js";
|
|
2
|
+
export declare const credentialPath: string;
|
|
3
|
+
export declare class NodeCredentialStorageAdapter implements CredentialStorageAdapter {
|
|
4
|
+
loadCredential(): Promise<WenyanCredential | null>;
|
|
5
|
+
saveCredential(credential: WenyanCredential): Promise<void>;
|
|
6
|
+
clearCredential(): Promise<void>;
|
|
7
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { WechatPublishResponse } from "../wechat.js";
|
|
2
2
|
import { ArticleOptions, WechatPublisher } from "../publish.js";
|
|
3
|
+
import { CredentialStore } from "../credentialStore.js";
|
|
3
4
|
export declare const wechatPublisher: WechatPublisher;
|
|
5
|
+
export declare const credentialStore: CredentialStore;
|
|
4
6
|
interface PublishOptions {
|
|
5
7
|
appId?: string;
|
|
6
8
|
appSecret?: string;
|
|
@@ -7,8 +7,9 @@ export interface RenderOptions {
|
|
|
7
7
|
footnote: boolean;
|
|
8
8
|
}
|
|
9
9
|
export interface PublishOptions extends RenderOptions {
|
|
10
|
+
appId?: string;
|
|
10
11
|
}
|
|
11
|
-
export interface ClientPublishOptions extends
|
|
12
|
+
export interface ClientPublishOptions extends PublishOptions {
|
|
12
13
|
server?: string;
|
|
13
14
|
apiKey?: string;
|
|
14
15
|
clientVersion?: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
export declare const configDir: string;
|
|
2
3
|
export declare function readFileContent(filePath: string): Promise<string>;
|
|
3
4
|
export declare function readBinaryFile(filePath: string): Promise<Buffer>;
|
|
4
5
|
export declare function safeReadJson<T>(file: string, fallback: T): Promise<T>;
|
package/dist/types/publish.d.ts
CHANGED
package/dist/wrapper.js
CHANGED
|
@@ -4,13 +4,22 @@ import https from "node:https";
|
|
|
4
4
|
import { JSDOM } from "jsdom";
|
|
5
5
|
import fs, { stat } from "node:fs/promises";
|
|
6
6
|
import crypto from "node:crypto";
|
|
7
|
+
import os from "node:os";
|
|
7
8
|
import { fileFromPath } from "formdata-node/file-from-path";
|
|
8
9
|
import { FormDataEncoder } from "form-data-encoder";
|
|
9
10
|
import { FormData } from "formdata-node";
|
|
10
11
|
import { Readable } from "node:stream";
|
|
11
|
-
import
|
|
12
|
-
import { defaultTokenCache, WechatPublisher } from "./publish.js";
|
|
12
|
+
import { defaultTokenCache, defaultCredential, WechatPublisher, CredentialStore } from "./publish.js";
|
|
13
13
|
import { createWenyanCore, getAllGzhThemes } from "./core.js";
|
|
14
|
+
const configDir = (() => {
|
|
15
|
+
if (process.env.XDG_CONFIG_HOME) {
|
|
16
|
+
return path.join(process.env.XDG_CONFIG_HOME, "wenyan-md");
|
|
17
|
+
}
|
|
18
|
+
if (process.env.APPDATA) {
|
|
19
|
+
return path.join(process.env.APPDATA, "wenyan-md");
|
|
20
|
+
}
|
|
21
|
+
return path.join(os.homedir(), ".config", "wenyan-md");
|
|
22
|
+
})();
|
|
14
23
|
async function readFileContent(filePath) {
|
|
15
24
|
return await fs.readFile(filePath, "utf-8");
|
|
16
25
|
}
|
|
@@ -233,7 +242,7 @@ async function uploadStyledContent(gzhContent, serverUrl, headers) {
|
|
|
233
242
|
return mdFileId;
|
|
234
243
|
}
|
|
235
244
|
async function requestServerPublish(mdFileId, serverUrl, headers, options) {
|
|
236
|
-
const { theme, customTheme, highlight, macStyle, footnote } = options;
|
|
245
|
+
const { theme, customTheme, highlight, macStyle, footnote, appId } = options;
|
|
237
246
|
const publishRes = await fetch(`${serverUrl}/publish`, {
|
|
238
247
|
method: "POST",
|
|
239
248
|
headers: {
|
|
@@ -246,7 +255,8 @@ async function requestServerPublish(mdFileId, serverUrl, headers, options) {
|
|
|
246
255
|
highlight,
|
|
247
256
|
customTheme,
|
|
248
257
|
macStyle,
|
|
249
|
-
footnote
|
|
258
|
+
footnote,
|
|
259
|
+
appId
|
|
250
260
|
})
|
|
251
261
|
});
|
|
252
262
|
const publishData = await publishRes.json();
|
|
@@ -330,80 +340,6 @@ const nodeHttpAdapter = {
|
|
|
330
340
|
};
|
|
331
341
|
}
|
|
332
342
|
};
|
|
333
|
-
const defaultConfig = {};
|
|
334
|
-
const configDir = process.env.APPDATA ? path.join(process.env.APPDATA, "wenyan-md") : path.join(os.homedir(), ".config", "wenyan-md");
|
|
335
|
-
const configPath = path.join(configDir, "config.json");
|
|
336
|
-
class ConfigStore {
|
|
337
|
-
config = { ...defaultConfig };
|
|
338
|
-
initPromise;
|
|
339
|
-
constructor() {
|
|
340
|
-
this.initPromise = this.load();
|
|
341
|
-
}
|
|
342
|
-
async load() {
|
|
343
|
-
await ensureDir(configDir);
|
|
344
|
-
this.config = await safeReadJson(configPath, defaultConfig);
|
|
345
|
-
}
|
|
346
|
-
async save() {
|
|
347
|
-
try {
|
|
348
|
-
await ensureDir(configDir);
|
|
349
|
-
await safeWriteJson(configPath, this.config);
|
|
350
|
-
} catch (error) {
|
|
351
|
-
throw new Error(`无法保存配置文件: ${error instanceof Error ? error.message : String(error)}`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
async getConfig() {
|
|
355
|
-
await this.initPromise;
|
|
356
|
-
return this.config;
|
|
357
|
-
}
|
|
358
|
-
async getThemes() {
|
|
359
|
-
await this.initPromise;
|
|
360
|
-
return Object.values(this.config.themes ?? {});
|
|
361
|
-
}
|
|
362
|
-
async getThemeById(themeId) {
|
|
363
|
-
await this.initPromise;
|
|
364
|
-
const themeOption = this.config.themes?.[themeId];
|
|
365
|
-
if (!themeOption) return void 0;
|
|
366
|
-
const absoluteFilePath = path.join(configDir, themeOption.path);
|
|
367
|
-
try {
|
|
368
|
-
return await fs.readFile(absoluteFilePath, "utf-8");
|
|
369
|
-
} catch {
|
|
370
|
-
return void 0;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
async addThemeToConfig(name, content) {
|
|
374
|
-
await this.initPromise;
|
|
375
|
-
const savedPath = await this.addThemeFile(name, content);
|
|
376
|
-
this.config.themes ??= {};
|
|
377
|
-
this.config.themes[name] = {
|
|
378
|
-
id: name,
|
|
379
|
-
name,
|
|
380
|
-
path: savedPath
|
|
381
|
-
};
|
|
382
|
-
await this.save();
|
|
383
|
-
}
|
|
384
|
-
async addThemeFile(themeId, themeContent) {
|
|
385
|
-
const filePath = `themes/${themeId}.css`;
|
|
386
|
-
const absoluteFilePath = path.join(configDir, filePath);
|
|
387
|
-
await ensureDir(path.dirname(absoluteFilePath));
|
|
388
|
-
await fs.writeFile(absoluteFilePath, themeContent, "utf-8");
|
|
389
|
-
return filePath;
|
|
390
|
-
}
|
|
391
|
-
async deleteThemeFromConfig(themeId) {
|
|
392
|
-
await this.initPromise;
|
|
393
|
-
const theme = this.config.themes?.[themeId];
|
|
394
|
-
if (!theme) return;
|
|
395
|
-
await this.deleteThemeFile(theme.path);
|
|
396
|
-
delete this.config.themes[themeId];
|
|
397
|
-
await this.save();
|
|
398
|
-
}
|
|
399
|
-
async deleteThemeFile(filePath) {
|
|
400
|
-
try {
|
|
401
|
-
await fs.unlink(path.join(configDir, filePath));
|
|
402
|
-
} catch {
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
const configStore = new ConfigStore();
|
|
407
343
|
const tokenPath = path.join(configDir, "token.json");
|
|
408
344
|
class NodeTokenStorageAdapter {
|
|
409
345
|
async loadToken() {
|
|
@@ -447,8 +383,27 @@ class NodeUploadCacheAdapter {
|
|
|
447
383
|
return crypto.createHash("md5").update(Buffer.from(buffer)).digest("hex");
|
|
448
384
|
}
|
|
449
385
|
}
|
|
386
|
+
const credentialPath = path.join(configDir, "credential.json");
|
|
387
|
+
class NodeCredentialStorageAdapter {
|
|
388
|
+
async loadCredential() {
|
|
389
|
+
await ensureDir(configDir);
|
|
390
|
+
return await safeReadJson(credentialPath, defaultCredential);
|
|
391
|
+
}
|
|
392
|
+
async saveCredential(credential) {
|
|
393
|
+
await ensureDir(configDir);
|
|
394
|
+
await safeWriteJson(credentialPath, credential);
|
|
395
|
+
}
|
|
396
|
+
async clearCredential() {
|
|
397
|
+
throw new Error("Method not implemented.");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
450
400
|
const mediaIdMapping = /* @__PURE__ */ new Map();
|
|
451
|
-
const wechatPublisher = new WechatPublisher(
|
|
401
|
+
const wechatPublisher = new WechatPublisher(
|
|
402
|
+
nodeHttpAdapter,
|
|
403
|
+
new NodeTokenStorageAdapter(),
|
|
404
|
+
new NodeUploadCacheAdapter()
|
|
405
|
+
);
|
|
406
|
+
const credentialStore = new CredentialStore(new NodeCredentialStorageAdapter());
|
|
452
407
|
async function uploadImage(imageUrl, accessToken, fileName, relativePath) {
|
|
453
408
|
let fileData;
|
|
454
409
|
let finalName;
|
|
@@ -510,11 +465,7 @@ async function uploadImages(content, accessToken, relativePath) {
|
|
|
510
465
|
async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
511
466
|
const { title, content, cover, author, source_url } = articleOptions;
|
|
512
467
|
const { appId, appSecret, relativePath } = publishOptions;
|
|
513
|
-
const appIdFinal = appId
|
|
514
|
-
const appSecretFinal = appSecret ?? process.env.WECHAT_APP_SECRET;
|
|
515
|
-
if (!appIdFinal || !appSecretFinal) {
|
|
516
|
-
throw new Error("请通过参数或环境变量 WECHAT_APP_ID / WECHAT_APP_SECRET 提供公众号凭据");
|
|
517
|
-
}
|
|
468
|
+
const { appId: appIdFinal, appSecret: appSecretFinal } = await getAppIdAndSecret(appId, appSecret);
|
|
518
469
|
const accessToken = await wechatPublisher.getAccessTokenWithCache(appIdFinal, appSecretFinal);
|
|
519
470
|
const { html, firstImageId } = await uploadImages(content, accessToken, relativePath);
|
|
520
471
|
let thumbMediaId;
|
|
@@ -557,6 +508,97 @@ async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
|
557
508
|
async function publishToDraft(title, content, cover = "", options = {}) {
|
|
558
509
|
return publishToWechatDraft({ title, content, cover }, options);
|
|
559
510
|
}
|
|
511
|
+
async function getAppIdAndSecret(appId, appSecret) {
|
|
512
|
+
if (appId && appSecret) {
|
|
513
|
+
return { appId, appSecret };
|
|
514
|
+
}
|
|
515
|
+
const envAppId = process.env.WECHAT_APP_ID;
|
|
516
|
+
const envAppSecret = process.env.WECHAT_APP_SECRET;
|
|
517
|
+
if (envAppId && envAppSecret && (envAppId === appId || !appId)) {
|
|
518
|
+
return { appId: envAppId, appSecret: envAppSecret };
|
|
519
|
+
}
|
|
520
|
+
if (!appId) {
|
|
521
|
+
throw new Error("未提供 AppID:请通过参数、环境变量或配置文件指定。");
|
|
522
|
+
}
|
|
523
|
+
const credential = await credentialStore.getWechatCredential(appId);
|
|
524
|
+
if (credential?.appId && credential?.appSecret) {
|
|
525
|
+
return { appId: credential.appId, appSecret: credential.appSecret };
|
|
526
|
+
}
|
|
527
|
+
throw new Error(`未能找到 AppID 为 "${appId}" 的公众号凭据,请检查配置文件。`);
|
|
528
|
+
}
|
|
529
|
+
const defaultConfig = {};
|
|
530
|
+
const configPath = path.join(configDir, "config.json");
|
|
531
|
+
class ConfigStore {
|
|
532
|
+
config = { ...defaultConfig };
|
|
533
|
+
initPromise;
|
|
534
|
+
constructor() {
|
|
535
|
+
this.initPromise = this.load();
|
|
536
|
+
}
|
|
537
|
+
async load() {
|
|
538
|
+
await ensureDir(configDir);
|
|
539
|
+
this.config = await safeReadJson(configPath, defaultConfig);
|
|
540
|
+
}
|
|
541
|
+
async save() {
|
|
542
|
+
try {
|
|
543
|
+
await ensureDir(configDir);
|
|
544
|
+
await safeWriteJson(configPath, this.config);
|
|
545
|
+
} catch (error) {
|
|
546
|
+
throw new Error(`无法保存配置文件: ${error instanceof Error ? error.message : String(error)}`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
async getConfig() {
|
|
550
|
+
await this.initPromise;
|
|
551
|
+
return this.config;
|
|
552
|
+
}
|
|
553
|
+
async getThemes() {
|
|
554
|
+
await this.initPromise;
|
|
555
|
+
return Object.values(this.config.themes ?? {});
|
|
556
|
+
}
|
|
557
|
+
async getThemeById(themeId) {
|
|
558
|
+
await this.initPromise;
|
|
559
|
+
const themeOption = this.config.themes?.[themeId];
|
|
560
|
+
if (!themeOption) return void 0;
|
|
561
|
+
const absoluteFilePath = path.join(configDir, themeOption.path);
|
|
562
|
+
try {
|
|
563
|
+
return await fs.readFile(absoluteFilePath, "utf-8");
|
|
564
|
+
} catch {
|
|
565
|
+
return void 0;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async addThemeToConfig(name, content) {
|
|
569
|
+
await this.initPromise;
|
|
570
|
+
const savedPath = await this.addThemeFile(name, content);
|
|
571
|
+
this.config.themes ??= {};
|
|
572
|
+
this.config.themes[name] = {
|
|
573
|
+
id: name,
|
|
574
|
+
name,
|
|
575
|
+
path: savedPath
|
|
576
|
+
};
|
|
577
|
+
await this.save();
|
|
578
|
+
}
|
|
579
|
+
async addThemeFile(themeId, themeContent) {
|
|
580
|
+
const filePath = `themes/${themeId}.css`;
|
|
581
|
+
const absoluteFilePath = path.join(configDir, filePath);
|
|
582
|
+
await ensureDir(path.dirname(absoluteFilePath));
|
|
583
|
+
await fs.writeFile(absoluteFilePath, themeContent, "utf-8");
|
|
584
|
+
return filePath;
|
|
585
|
+
}
|
|
586
|
+
async deleteThemeFromConfig(themeId) {
|
|
587
|
+
await this.initPromise;
|
|
588
|
+
const theme = this.config.themes?.[themeId];
|
|
589
|
+
if (!theme) return;
|
|
590
|
+
await this.deleteThemeFile(theme.path);
|
|
591
|
+
delete this.config.themes[themeId];
|
|
592
|
+
await this.save();
|
|
593
|
+
}
|
|
594
|
+
async deleteThemeFile(filePath) {
|
|
595
|
+
try {
|
|
596
|
+
await fs.unlink(path.join(configDir, filePath));
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const configStore = new ConfigStore();
|
|
560
602
|
const wenyanCoreInstance = await createWenyanCore();
|
|
561
603
|
async function renderWithTheme(markdownContent, options) {
|
|
562
604
|
if (!markdownContent) {
|
|
@@ -683,6 +725,7 @@ async function renderAndPublish(inputContent, options, getInputContent) {
|
|
|
683
725
|
source_url: gzhContent.source_url
|
|
684
726
|
},
|
|
685
727
|
{
|
|
728
|
+
appId: options.appId,
|
|
686
729
|
relativePath: absoluteDirPath
|
|
687
730
|
}
|
|
688
731
|
);
|
|
@@ -710,6 +753,7 @@ export {
|
|
|
710
753
|
configDir,
|
|
711
754
|
configPath,
|
|
712
755
|
configStore,
|
|
756
|
+
credentialStore,
|
|
713
757
|
ensureDir,
|
|
714
758
|
getGzhContent,
|
|
715
759
|
getNormalizeFilePath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wenyan-md/core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4",
|
|
4
4
|
"description": "Core library for Wenyan markdown rendering & publishing",
|
|
5
5
|
"author": "Lei <caol64@gmail.com> (https://github.com/caol64)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"vitest": "^3.2.4"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"css-tree": "^3.1
|
|
63
|
+
"css-tree": "^3.2.1",
|
|
64
64
|
"front-matter": "^4.0.2",
|
|
65
65
|
"highlight.js": "11.10.0",
|
|
66
66
|
"marked": "^15.0.12",
|
|
@@ -83,6 +83,9 @@
|
|
|
83
83
|
"optional": true
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"registry": "https://registry.npmjs.org/"
|
|
88
|
+
},
|
|
86
89
|
"scripts": {
|
|
87
90
|
"typecheck": "tsc --noEmit",
|
|
88
91
|
"build": "vite build && tsc",
|