nexo-md-to-pdf-cli 0.1.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/LICENSE +21 -0
- package/README.md +246 -0
- package/assets/brand/nexo_logo_primary.svg +6 -0
- package/assets/brand/nexo_logo_primary_mono.svg +6 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +166 -0
- package/dist/cli.js.map +1 -0
- package/dist/free-convert.d.ts +138 -0
- package/dist/free-convert.js +130 -0
- package/dist/free-convert.js.map +1 -0
- package/dist/free-limits.d.ts +27 -0
- package/dist/free-limits.js +40 -0
- package/dist/free-limits.js.map +1 -0
- package/package.json +53 -0
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { validateFreeConvertRequest } from "./free-convert.js";
|
|
6
|
+
const DEFAULT_API_BASE_URL = "https://nexo.speck-solutions.com.br";
|
|
7
|
+
function printHelp() {
|
|
8
|
+
console.log(`nexo
|
|
9
|
+
|
|
10
|
+
Uso:
|
|
11
|
+
nexo arquivo.md
|
|
12
|
+
nexo arquivo.md --output ./saida.pdf
|
|
13
|
+
nexo a.md b.md c.md --output-dir ./pdfs
|
|
14
|
+
nexo arquivo.md --logo ./logo.svg --logo-tone light
|
|
15
|
+
nexo arquivo.md --api-base-url http://localhost:3000
|
|
16
|
+
|
|
17
|
+
Opcoes:
|
|
18
|
+
--output <arquivo> Define o PDF de saida para um unico markdown
|
|
19
|
+
--output-dir <pasta> Pasta de saida quando houver varios arquivos
|
|
20
|
+
--logo <arquivo> Logo opcional (png, jpg, webp ou svg)
|
|
21
|
+
--logo-tone <dark|light> Fundo da logo no cabecalho (padrao: dark)
|
|
22
|
+
--api-base-url <url> Base da API NEXO (padrao: ${DEFAULT_API_BASE_URL})
|
|
23
|
+
--help, -h Exibe esta ajuda
|
|
24
|
+
|
|
25
|
+
Regras:
|
|
26
|
+
- Cada conversao respeita os mesmos limites do modo Free/nao autenticado da NEXO
|
|
27
|
+
- Cada .md vira um PDF separado, o que facilita processamento em massa
|
|
28
|
+
- Sem --output-dir, o PDF e salvo ao lado do arquivo original
|
|
29
|
+
- O uso e contabilizado no backend da NEXO com origem identificada como CLI
|
|
30
|
+
- Anexos nao sao suportados nesta versao da CLI
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
function detectMimeType(filePath) {
|
|
34
|
+
const extension = extname(filePath).toLowerCase();
|
|
35
|
+
switch (extension) {
|
|
36
|
+
case ".png":
|
|
37
|
+
return "image/png";
|
|
38
|
+
case ".jpg":
|
|
39
|
+
case ".jpeg":
|
|
40
|
+
return "image/jpeg";
|
|
41
|
+
case ".webp":
|
|
42
|
+
return "image/webp";
|
|
43
|
+
case ".svg":
|
|
44
|
+
return "image/svg+xml";
|
|
45
|
+
default:
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function encodeFileAsDataUrl(filePath) {
|
|
50
|
+
const absolutePath = resolve(filePath);
|
|
51
|
+
const mimeType = detectMimeType(absolutePath);
|
|
52
|
+
if (!mimeType) {
|
|
53
|
+
throw new Error(`Formato de arquivo nao suportado em ${absolutePath}.`);
|
|
54
|
+
}
|
|
55
|
+
const bytes = await readFile(absolutePath);
|
|
56
|
+
return {
|
|
57
|
+
fileName: basename(absolutePath),
|
|
58
|
+
mimeType,
|
|
59
|
+
dataUrl: `data:${mimeType};base64,${bytes.toString("base64")}`
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function deriveOutputPath(inputPath, options) {
|
|
63
|
+
if (options.output)
|
|
64
|
+
return resolve(options.output);
|
|
65
|
+
const inputAbsolutePath = resolve(inputPath);
|
|
66
|
+
const outputDir = options.outputDir ? resolve(options.outputDir) : dirname(inputAbsolutePath);
|
|
67
|
+
const outputFileName = `${basename(inputAbsolutePath, extname(inputAbsolutePath))}.pdf`;
|
|
68
|
+
return join(outputDir, outputFileName);
|
|
69
|
+
}
|
|
70
|
+
function toCliOptions(values) {
|
|
71
|
+
return {
|
|
72
|
+
output: typeof values.output === "string" ? values.output : undefined,
|
|
73
|
+
outputDir: typeof values["output-dir"] === "string" ? values["output-dir"] : undefined,
|
|
74
|
+
logo: typeof values.logo === "string" ? values.logo : undefined,
|
|
75
|
+
logoTone: values["logo-tone"] === "light" ? "light" : "dark",
|
|
76
|
+
apiBaseUrl: typeof values["api-base-url"] === "string" ? values["api-base-url"] : undefined,
|
|
77
|
+
help: Boolean(values.help)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function buildApiUrl(options) {
|
|
81
|
+
const baseUrl = (options.apiBaseUrl || process.env.NEXO_API_BASE_URL || DEFAULT_API_BASE_URL).replace(/\/+$/, "");
|
|
82
|
+
return `${baseUrl}/api/free/convert`;
|
|
83
|
+
}
|
|
84
|
+
async function convertMarkdownFile(inputPath, options, customLogoData) {
|
|
85
|
+
const absoluteInputPath = resolve(inputPath);
|
|
86
|
+
const markdown = await readFile(absoluteInputPath, "utf8");
|
|
87
|
+
const requestBody = {
|
|
88
|
+
documents: [
|
|
89
|
+
{
|
|
90
|
+
markdown,
|
|
91
|
+
fileName: basename(absoluteInputPath),
|
|
92
|
+
attachments: []
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
...(customLogoData
|
|
96
|
+
? {
|
|
97
|
+
customLogo: {
|
|
98
|
+
...customLogoData,
|
|
99
|
+
tone: options.logoTone
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
: {})
|
|
103
|
+
};
|
|
104
|
+
const requestBytes = Buffer.byteLength(JSON.stringify(requestBody));
|
|
105
|
+
validateFreeConvertRequest(requestBody, requestBytes);
|
|
106
|
+
const response = await fetch(buildApiUrl(options), {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: {
|
|
109
|
+
"content-type": "application/json",
|
|
110
|
+
"x-nexo-client-source": "cli"
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify(requestBody)
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
116
|
+
const message = typeof errorBody?.message === "string"
|
|
117
|
+
? errorBody.message
|
|
118
|
+
: `Falha na conversao (${response.status}).`;
|
|
119
|
+
throw new Error(message);
|
|
120
|
+
}
|
|
121
|
+
const pdfBytes = Buffer.from(await response.arrayBuffer());
|
|
122
|
+
const outputPath = deriveOutputPath(absoluteInputPath, options);
|
|
123
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
124
|
+
await writeFile(outputPath, pdfBytes);
|
|
125
|
+
return outputPath;
|
|
126
|
+
}
|
|
127
|
+
async function main() {
|
|
128
|
+
const parsed = parseArgs({
|
|
129
|
+
options: {
|
|
130
|
+
output: { type: "string" },
|
|
131
|
+
"output-dir": { type: "string" },
|
|
132
|
+
logo: { type: "string" },
|
|
133
|
+
"logo-tone": { type: "string" },
|
|
134
|
+
"api-base-url": { type: "string" },
|
|
135
|
+
help: { type: "boolean", short: "h" }
|
|
136
|
+
},
|
|
137
|
+
allowPositionals: true
|
|
138
|
+
});
|
|
139
|
+
const options = toCliOptions(parsed.values);
|
|
140
|
+
const inputs = parsed.positionals;
|
|
141
|
+
if (options.help || inputs.length === 0) {
|
|
142
|
+
printHelp();
|
|
143
|
+
process.exit(inputs.length === 0 && !options.help ? 1 : 0);
|
|
144
|
+
}
|
|
145
|
+
if (options.output && inputs.length > 1) {
|
|
146
|
+
throw new Error("Use --output apenas quando houver um unico arquivo .md.");
|
|
147
|
+
}
|
|
148
|
+
const customLogoData = options.logo ? await encodeFileAsDataUrl(options.logo) : null;
|
|
149
|
+
let failures = 0;
|
|
150
|
+
for (const inputPath of inputs) {
|
|
151
|
+
try {
|
|
152
|
+
const outputPath = await convertMarkdownFile(inputPath, options, customLogoData);
|
|
153
|
+
console.log(`[ok] ${resolve(inputPath)} -> ${outputPath}`);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
failures += 1;
|
|
157
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
158
|
+
console.error(`[erro] ${resolve(inputPath)} -> ${reason}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (failures > 0) {
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
await main();
|
|
166
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAW/D,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AAEnE,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;uDAcyC,oBAAoB;;;;;;;;;CAS1E,CAAC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAClD,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,WAAW,CAAC;QACrB,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,eAAe,CAAC;QACzB;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,uCAAuC,YAAY,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC3C,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC;QAChC,QAAQ;QACR,OAAO,EAAE,QAAQ,QAAQ,WAAW,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;KAC/D,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB,EAAE,OAAmB;IAC9D,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnD,MAAM,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9F,MAAM,cAAc,GAAG,GAAG,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;IACxF,OAAO,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,YAAY,CAAC,MAAoD;IACxE,OAAO;QACL,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QACrE,SAAS,EAAE,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;QACtF,IAAI,EAAE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC/D,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;QAC5D,UAAU,EACR,OAAO,MAAM,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS;QACjF,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,OAAmB;IACtC,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,oBAAoB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClH,OAAO,GAAG,OAAO,mBAAmB,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,SAAiB,EACjB,OAAmB,EACnB,cAAsE;IAEtE,MAAM,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG;QAClB,SAAS,EAAE;YACT;gBACE,QAAQ;gBACR,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC;gBACrC,WAAW,EAAE,EAAE;aAChB;SACF;QACD,GAAG,CAAC,cAAc;YAChB,CAAC,CAAC;gBACE,UAAU,EAAE;oBACV,GAAG,cAAc;oBACjB,IAAI,EAAE,OAAO,CAAC,QAAQ;iBACvB;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IACpE,0BAA0B,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAEtD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE;QACjD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,sBAAsB,EAAE,KAAK;SAC9B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1D,MAAM,OAAO,GACX,OAAO,SAAS,EAAE,OAAO,KAAK,QAAQ;YACpC,CAAC,CAAC,SAAS,CAAC,OAAO;YACnB,CAAC,CAAC,uBAAuB,QAAQ,CAAC,MAAM,IAAI,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAE3D,MAAM,UAAU,GAAG,gBAAgB,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAChE,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACtC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,SAAS,CAAC;QACvB,OAAO,EAAE;YACP,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAChC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAClC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;SACtC;QACD,gBAAgB,EAAE,IAAI;KACvB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;IAElC,IAAI,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACrF,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,KAAK,MAAM,SAAS,IAAI,MAAM,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,SAAS,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;YACjF,OAAO,CAAC,GAAG,CAAC,QAAQ,OAAO,CAAC,SAAS,CAAC,OAAO,UAAU,EAAE,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,IAAI,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACtE,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,CAAC,SAAS,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const attachmentSchema: z.ZodObject<{
|
|
3
|
+
fileName: z.ZodString;
|
|
4
|
+
mimeType: z.ZodString;
|
|
5
|
+
dataUrl: z.ZodString;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
fileName: string;
|
|
8
|
+
mimeType: string;
|
|
9
|
+
dataUrl: string;
|
|
10
|
+
}, {
|
|
11
|
+
fileName: string;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
dataUrl: string;
|
|
14
|
+
}>;
|
|
15
|
+
declare const customLogoSchema: z.ZodObject<z.objectUtil.extendShape<{
|
|
16
|
+
fileName: z.ZodString;
|
|
17
|
+
mimeType: z.ZodString;
|
|
18
|
+
dataUrl: z.ZodString;
|
|
19
|
+
}, {
|
|
20
|
+
tone: z.ZodDefault<z.ZodEnum<["dark", "light"]>>;
|
|
21
|
+
}>, "strip", z.ZodTypeAny, {
|
|
22
|
+
fileName: string;
|
|
23
|
+
mimeType: string;
|
|
24
|
+
dataUrl: string;
|
|
25
|
+
tone: "dark" | "light";
|
|
26
|
+
}, {
|
|
27
|
+
fileName: string;
|
|
28
|
+
mimeType: string;
|
|
29
|
+
dataUrl: string;
|
|
30
|
+
tone?: "dark" | "light" | undefined;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const freeConvertRequestSchema: z.ZodObject<{
|
|
33
|
+
documents: z.ZodArray<z.ZodObject<{
|
|
34
|
+
markdown: z.ZodString;
|
|
35
|
+
fileName: z.ZodString;
|
|
36
|
+
attachments: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
37
|
+
fileName: z.ZodString;
|
|
38
|
+
mimeType: z.ZodString;
|
|
39
|
+
dataUrl: z.ZodString;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
fileName: string;
|
|
42
|
+
mimeType: string;
|
|
43
|
+
dataUrl: string;
|
|
44
|
+
}, {
|
|
45
|
+
fileName: string;
|
|
46
|
+
mimeType: string;
|
|
47
|
+
dataUrl: string;
|
|
48
|
+
}>, "many">>;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
fileName: string;
|
|
51
|
+
markdown: string;
|
|
52
|
+
attachments: {
|
|
53
|
+
fileName: string;
|
|
54
|
+
mimeType: string;
|
|
55
|
+
dataUrl: string;
|
|
56
|
+
}[];
|
|
57
|
+
}, {
|
|
58
|
+
fileName: string;
|
|
59
|
+
markdown: string;
|
|
60
|
+
attachments?: {
|
|
61
|
+
fileName: string;
|
|
62
|
+
mimeType: string;
|
|
63
|
+
dataUrl: string;
|
|
64
|
+
}[] | undefined;
|
|
65
|
+
}>, "many">;
|
|
66
|
+
customLogo: z.ZodOptional<z.ZodObject<z.objectUtil.extendShape<{
|
|
67
|
+
fileName: z.ZodString;
|
|
68
|
+
mimeType: z.ZodString;
|
|
69
|
+
dataUrl: z.ZodString;
|
|
70
|
+
}, {
|
|
71
|
+
tone: z.ZodDefault<z.ZodEnum<["dark", "light"]>>;
|
|
72
|
+
}>, "strip", z.ZodTypeAny, {
|
|
73
|
+
fileName: string;
|
|
74
|
+
mimeType: string;
|
|
75
|
+
dataUrl: string;
|
|
76
|
+
tone: "dark" | "light";
|
|
77
|
+
}, {
|
|
78
|
+
fileName: string;
|
|
79
|
+
mimeType: string;
|
|
80
|
+
dataUrl: string;
|
|
81
|
+
tone?: "dark" | "light" | undefined;
|
|
82
|
+
}>>;
|
|
83
|
+
}, "strip", z.ZodTypeAny, {
|
|
84
|
+
documents: {
|
|
85
|
+
fileName: string;
|
|
86
|
+
markdown: string;
|
|
87
|
+
attachments: {
|
|
88
|
+
fileName: string;
|
|
89
|
+
mimeType: string;
|
|
90
|
+
dataUrl: string;
|
|
91
|
+
}[];
|
|
92
|
+
}[];
|
|
93
|
+
customLogo?: {
|
|
94
|
+
fileName: string;
|
|
95
|
+
mimeType: string;
|
|
96
|
+
dataUrl: string;
|
|
97
|
+
tone: "dark" | "light";
|
|
98
|
+
} | undefined;
|
|
99
|
+
}, {
|
|
100
|
+
documents: {
|
|
101
|
+
fileName: string;
|
|
102
|
+
markdown: string;
|
|
103
|
+
attachments?: {
|
|
104
|
+
fileName: string;
|
|
105
|
+
mimeType: string;
|
|
106
|
+
dataUrl: string;
|
|
107
|
+
}[] | undefined;
|
|
108
|
+
}[];
|
|
109
|
+
customLogo?: {
|
|
110
|
+
fileName: string;
|
|
111
|
+
mimeType: string;
|
|
112
|
+
dataUrl: string;
|
|
113
|
+
tone?: "dark" | "light" | undefined;
|
|
114
|
+
} | undefined;
|
|
115
|
+
}>;
|
|
116
|
+
export type FreeConvertAttachmentInput = z.infer<typeof attachmentSchema>;
|
|
117
|
+
export type FreeConvertCustomLogoInput = z.infer<typeof customLogoSchema>;
|
|
118
|
+
export type PreparedFreeConvertRequest = {
|
|
119
|
+
sourceName: string;
|
|
120
|
+
fileName: string;
|
|
121
|
+
markdownChars: number;
|
|
122
|
+
attachmentsCount: number;
|
|
123
|
+
attachmentsTotalBytes: number;
|
|
124
|
+
documents: Array<{
|
|
125
|
+
markdown: string;
|
|
126
|
+
sourceName: string;
|
|
127
|
+
attachments: FreeConvertAttachmentInput[];
|
|
128
|
+
}>;
|
|
129
|
+
customLogo: FreeConvertCustomLogoInput | null;
|
|
130
|
+
};
|
|
131
|
+
export declare function extractDataUrlInfo(dataUrl: string): {
|
|
132
|
+
mimeType: string;
|
|
133
|
+
bytes: number;
|
|
134
|
+
} | null;
|
|
135
|
+
export declare function normalizeMimeType(fileName: string, mimeType: string): string;
|
|
136
|
+
export declare function sanitizeSourceName(fileName?: string): string;
|
|
137
|
+
export declare function validateFreeConvertRequest(body: unknown, requestBytes?: number): PreparedFreeConvertRequest;
|
|
138
|
+
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { FREE_LIMITS, formatBytes } from "./free-limits.js";
|
|
3
|
+
const dataUrlPattern = /^data:([^;,]+)(?:;[^,]+)*;base64,([A-Za-z0-9+/=]+)$/;
|
|
4
|
+
const attachmentSchema = z.object({
|
|
5
|
+
fileName: z.string().trim().min(1).max(FREE_LIMITS.fileName.maxChars),
|
|
6
|
+
mimeType: z.string().trim().min(1),
|
|
7
|
+
dataUrl: z.string().trim().min(1)
|
|
8
|
+
});
|
|
9
|
+
const customLogoSchema = attachmentSchema.extend({
|
|
10
|
+
tone: z.enum(["dark", "light"]).default("dark")
|
|
11
|
+
});
|
|
12
|
+
const documentSchema = z.object({
|
|
13
|
+
markdown: z.string().trim().min(1).max(FREE_LIMITS.markdown.maxChars),
|
|
14
|
+
fileName: z.string().trim().min(1).max(FREE_LIMITS.fileName.maxChars),
|
|
15
|
+
attachments: z
|
|
16
|
+
.array(attachmentSchema)
|
|
17
|
+
.max(FREE_LIMITS.attachments.maxFilesPerDocument)
|
|
18
|
+
.default([])
|
|
19
|
+
});
|
|
20
|
+
export const freeConvertRequestSchema = z.object({
|
|
21
|
+
documents: z.array(documentSchema).min(1).max(FREE_LIMITS.documents.maxFiles),
|
|
22
|
+
customLogo: customLogoSchema.optional()
|
|
23
|
+
});
|
|
24
|
+
export function extractDataUrlInfo(dataUrl) {
|
|
25
|
+
const match = dataUrlPattern.exec(dataUrl);
|
|
26
|
+
if (!match) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const mimeType = match[1].toLowerCase();
|
|
30
|
+
const base64 = match[2];
|
|
31
|
+
const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
|
|
32
|
+
const bytes = Math.floor((base64.length * 3) / 4) - padding;
|
|
33
|
+
return { mimeType, bytes };
|
|
34
|
+
}
|
|
35
|
+
export function normalizeMimeType(fileName, mimeType) {
|
|
36
|
+
const normalized = mimeType.trim().toLowerCase();
|
|
37
|
+
if (normalized) {
|
|
38
|
+
return normalized;
|
|
39
|
+
}
|
|
40
|
+
const lowerName = fileName.toLowerCase();
|
|
41
|
+
if (lowerName.endsWith(".svg"))
|
|
42
|
+
return "image/svg+xml";
|
|
43
|
+
if (lowerName.endsWith(".png"))
|
|
44
|
+
return "image/png";
|
|
45
|
+
if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg"))
|
|
46
|
+
return "image/jpeg";
|
|
47
|
+
if (lowerName.endsWith(".webp"))
|
|
48
|
+
return "image/webp";
|
|
49
|
+
return normalized;
|
|
50
|
+
}
|
|
51
|
+
export function sanitizeSourceName(fileName) {
|
|
52
|
+
const base = (fileName ?? "documento")
|
|
53
|
+
.replace(/\.md$/i, "")
|
|
54
|
+
.replace(/[^\w.\- ]+/g, " ")
|
|
55
|
+
.trim()
|
|
56
|
+
.slice(0, FREE_LIMITS.fileName.maxChars);
|
|
57
|
+
return base.length > 0 ? base : "documento";
|
|
58
|
+
}
|
|
59
|
+
export function validateFreeConvertRequest(body, requestBytes = 0) {
|
|
60
|
+
if (requestBytes > FREE_LIMITS.request.maxBodyBytes) {
|
|
61
|
+
throw new Error(`payload_too_large: Payload acima do limite (${formatBytes(FREE_LIMITS.request.maxBodyBytes)}).`);
|
|
62
|
+
}
|
|
63
|
+
const parsed = freeConvertRequestSchema.safeParse(body);
|
|
64
|
+
if (!parsed.success) {
|
|
65
|
+
throw new Error("invalid_payload: Revise os limites de documentos, markdown, nome de arquivo e anexos.");
|
|
66
|
+
}
|
|
67
|
+
const sourceName = sanitizeSourceName(parsed.data.documents[0]?.fileName);
|
|
68
|
+
const markdownChars = parsed.data.documents.reduce((sum, item) => sum + item.markdown.length, 0);
|
|
69
|
+
const attachmentsCount = parsed.data.documents.reduce((sum, item) => sum + item.attachments.length, 0);
|
|
70
|
+
if (markdownChars > FREE_LIMITS.documents.maxTotalChars) {
|
|
71
|
+
throw new Error(`markdown_too_large: Total de markdown excede ${FREE_LIMITS.documents.maxTotalChars.toLocaleString("pt-BR")} caracteres.`);
|
|
72
|
+
}
|
|
73
|
+
if (attachmentsCount > FREE_LIMITS.attachments.maxFiles) {
|
|
74
|
+
throw new Error(`too_many_attachments: Total de anexos excede ${FREE_LIMITS.attachments.maxFiles}.`);
|
|
75
|
+
}
|
|
76
|
+
let attachmentsTotalBytes = 0;
|
|
77
|
+
for (const document of parsed.data.documents) {
|
|
78
|
+
for (const attachment of document.attachments) {
|
|
79
|
+
const dataUrl = extractDataUrlInfo(attachment.dataUrl);
|
|
80
|
+
const normalizedMimeType = normalizeMimeType(attachment.fileName, attachment.mimeType);
|
|
81
|
+
if (!dataUrl) {
|
|
82
|
+
throw new Error(`invalid_attachment_data: Anexo "${attachment.fileName}" com data URL inválida.`);
|
|
83
|
+
}
|
|
84
|
+
if (!FREE_LIMITS.attachments.allowedMimeTypes.includes(dataUrl.mimeType)) {
|
|
85
|
+
throw new Error(`unsupported_attachment_type: Formato não permitido em "${attachment.fileName}". Tipos aceitos: ${FREE_LIMITS.attachments.allowedMimeTypes.join(", ")}.`);
|
|
86
|
+
}
|
|
87
|
+
if (normalizedMimeType !== dataUrl.mimeType) {
|
|
88
|
+
throw new Error(`mime_mismatch: Tipo MIME inconsistente no anexo "${attachment.fileName}".`);
|
|
89
|
+
}
|
|
90
|
+
if (dataUrl.bytes > FREE_LIMITS.attachments.maxFileBytes) {
|
|
91
|
+
throw new Error(`attachment_too_large: Anexo "${attachment.fileName}" excede ${formatBytes(FREE_LIMITS.attachments.maxFileBytes)}.`);
|
|
92
|
+
}
|
|
93
|
+
attachmentsTotalBytes += dataUrl.bytes;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (attachmentsTotalBytes > FREE_LIMITS.attachments.maxTotalBytes) {
|
|
97
|
+
throw new Error(`attachments_too_large: Total de anexos excede ${formatBytes(FREE_LIMITS.attachments.maxTotalBytes)}.`);
|
|
98
|
+
}
|
|
99
|
+
const customLogo = parsed.data.customLogo;
|
|
100
|
+
if (customLogo) {
|
|
101
|
+
const logoDataUrl = extractDataUrlInfo(customLogo.dataUrl);
|
|
102
|
+
const normalizedLogoMimeType = normalizeMimeType(customLogo.fileName, customLogo.mimeType);
|
|
103
|
+
if (!logoDataUrl) {
|
|
104
|
+
throw new Error(`invalid_logo_data: Logo "${customLogo.fileName}" com data URL inválida.`);
|
|
105
|
+
}
|
|
106
|
+
if (!FREE_LIMITS.branding.allowedMimeTypes.includes(logoDataUrl.mimeType)) {
|
|
107
|
+
throw new Error(`unsupported_logo_type: Formato não permitido em "${customLogo.fileName}". Tipos aceitos: ${FREE_LIMITS.branding.allowedMimeTypes.join(", ")}.`);
|
|
108
|
+
}
|
|
109
|
+
if (normalizedLogoMimeType !== logoDataUrl.mimeType) {
|
|
110
|
+
throw new Error(`logo_mime_mismatch: Tipo MIME inconsistente na logo "${customLogo.fileName}".`);
|
|
111
|
+
}
|
|
112
|
+
if (logoDataUrl.bytes > FREE_LIMITS.branding.maxLogoBytes) {
|
|
113
|
+
throw new Error(`logo_too_large: Logo "${customLogo.fileName}" excede ${formatBytes(FREE_LIMITS.branding.maxLogoBytes)}.`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
sourceName,
|
|
118
|
+
fileName: `${sourceName}.pdf`,
|
|
119
|
+
markdownChars,
|
|
120
|
+
attachmentsCount,
|
|
121
|
+
attachmentsTotalBytes,
|
|
122
|
+
documents: parsed.data.documents.map((document) => ({
|
|
123
|
+
markdown: document.markdown,
|
|
124
|
+
sourceName: sanitizeSourceName(document.fileName),
|
|
125
|
+
attachments: document.attachments
|
|
126
|
+
})),
|
|
127
|
+
customLogo: customLogo ?? null
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=free-convert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"free-convert.js","sourceRoot":"","sources":["../src/free-convert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const FREE_LIMITS: {
|
|
2
|
+
readonly documents: {
|
|
3
|
+
readonly maxFiles: 3;
|
|
4
|
+
readonly maxTotalChars: 180000;
|
|
5
|
+
};
|
|
6
|
+
readonly markdown: {
|
|
7
|
+
readonly maxChars: 120000;
|
|
8
|
+
};
|
|
9
|
+
readonly branding: {
|
|
10
|
+
readonly maxLogoBytes: number;
|
|
11
|
+
readonly allowedMimeTypes: readonly ["image/png", "image/jpeg", "image/webp", "image/svg+xml"];
|
|
12
|
+
};
|
|
13
|
+
readonly attachments: {
|
|
14
|
+
readonly maxFiles: 8;
|
|
15
|
+
readonly maxFilesPerDocument: 4;
|
|
16
|
+
readonly maxFileBytes: number;
|
|
17
|
+
readonly maxTotalBytes: number;
|
|
18
|
+
readonly allowedMimeTypes: readonly ["image/png", "image/jpeg", "image/webp"];
|
|
19
|
+
};
|
|
20
|
+
readonly request: {
|
|
21
|
+
readonly maxBodyBytes: number;
|
|
22
|
+
};
|
|
23
|
+
readonly fileName: {
|
|
24
|
+
readonly maxChars: 120;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export declare function formatBytes(bytes: number): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const FREE_LIMITS = {
|
|
2
|
+
documents: {
|
|
3
|
+
maxFiles: 3,
|
|
4
|
+
maxTotalChars: 180_000
|
|
5
|
+
},
|
|
6
|
+
markdown: {
|
|
7
|
+
maxChars: 120_000
|
|
8
|
+
},
|
|
9
|
+
branding: {
|
|
10
|
+
maxLogoBytes: 2 * 1024 * 1024,
|
|
11
|
+
allowedMimeTypes: ["image/png", "image/jpeg", "image/webp", "image/svg+xml"]
|
|
12
|
+
},
|
|
13
|
+
attachments: {
|
|
14
|
+
maxFiles: 8,
|
|
15
|
+
maxFilesPerDocument: 4,
|
|
16
|
+
maxFileBytes: 4 * 1024 * 1024,
|
|
17
|
+
maxTotalBytes: 16 * 1024 * 1024,
|
|
18
|
+
allowedMimeTypes: ["image/png", "image/jpeg", "image/webp"]
|
|
19
|
+
},
|
|
20
|
+
request: {
|
|
21
|
+
maxBodyBytes: 22 * 1024 * 1024
|
|
22
|
+
},
|
|
23
|
+
fileName: {
|
|
24
|
+
maxChars: 120
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export function formatBytes(bytes) {
|
|
28
|
+
if (bytes < 1024) {
|
|
29
|
+
return `${bytes} B`;
|
|
30
|
+
}
|
|
31
|
+
const units = ["KB", "MB", "GB"];
|
|
32
|
+
let value = bytes / 1024;
|
|
33
|
+
let unitIndex = 0;
|
|
34
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
35
|
+
value /= 1024;
|
|
36
|
+
unitIndex += 1;
|
|
37
|
+
}
|
|
38
|
+
return `${value.toFixed(value >= 10 ? 0 : 1)} ${units[unitIndex]}`;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=free-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"free-limits.js","sourceRoot":"","sources":["../src/free-limits.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS,EAAE;QACT,QAAQ,EAAE,CAAC;QACX,aAAa,EAAE,OAAO;KACvB;IACD,QAAQ,EAAE;QACR,QAAQ,EAAE,OAAO;KAClB;IACD,QAAQ,EAAE;QACR,YAAY,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;QAC7B,gBAAgB,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,CAAU;KACtF;IACD,WAAW,EAAE;QACX,QAAQ,EAAE,CAAC;QACX,mBAAmB,EAAE,CAAC;QACtB,YAAY,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;QAC7B,aAAa,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;QAC/B,gBAAgB,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,YAAY,CAAU;KACrE;IACD,OAAO,EAAE;QACP,YAAY,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;KAC/B;IACD,QAAQ,EAAE;QACR,QAAQ,EAAE,GAAG;KACd;CACO,CAAC;AAEX,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC;QACjB,OAAO,GAAG,KAAK,IAAI,CAAC;IACtB,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;IAC1C,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;IACzB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO,KAAK,IAAI,IAAI,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,KAAK,IAAI,IAAI,CAAC;QACd,SAAS,IAAI,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;AACrE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nexo-md-to-pdf-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI to convert Markdown files into corporate-ready PDFs with the NEXO document layout.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"nexo": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"assets/brand",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://nexo.speck-solutions.com.br",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/DaviSpeck/nexo-cli.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/DaviSpeck/nexo-cli/issues"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"markdown",
|
|
25
|
+
"markdown-to-pdf",
|
|
26
|
+
"pdf-generation",
|
|
27
|
+
"cli",
|
|
28
|
+
"nodejs",
|
|
29
|
+
"playwright",
|
|
30
|
+
"developer-tools",
|
|
31
|
+
"technical-writing",
|
|
32
|
+
"docs-as-code",
|
|
33
|
+
"release-notes"
|
|
34
|
+
],
|
|
35
|
+
"author": "Davi Speck",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=22"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
42
|
+
"build": "yarn clean && tsc -p tsconfig.json",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"prepack": "yarn build"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"zod": "3.24.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "22.10.2",
|
|
51
|
+
"typescript": "5.8.2"
|
|
52
|
+
}
|
|
53
|
+
}
|