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/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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
@@ -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
+ }