@medicus.ai/medicus-report-pdf-generator 1.3.14 → 1.3.16

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.
Files changed (169) hide show
  1. package/.vscode/settings.json +3 -3
  2. package/README.md +26 -26
  3. package/app/i18n.config.js +20 -20
  4. package/app/i18n_wellbeing.config.js +20 -20
  5. package/app/services/localeService.js +28 -28
  6. package/assets/Mediclinic/css/nasco_report.css +6297 -6297
  7. package/assets/Mediclinic/css/nasco_report_rtl.css +851 -851
  8. package/assets/Mediclinic/css/style.css +33 -33
  9. package/assets/Mediclinic/js/js.js +112 -112
  10. package/assets/Mediclinic/js/raphael.js +8437 -8437
  11. package/assets/arabic.css +275 -275
  12. package/assets/charts.min.js +7 -7
  13. package/assets/corporate_report/css/report.css +582 -582
  14. package/assets/corporate_report/css/report_rtl.css +144 -144
  15. package/assets/corporate_report/js/js.js +14 -14
  16. package/assets/data/data.json +124 -124
  17. package/assets/data/data2.json +675 -675
  18. package/assets/data/pdf_data_with_history.json +1255 -1255
  19. package/assets/doctor-note-insight-icon.svg +11 -11
  20. package/assets/imc/css/style.css +61 -61
  21. package/assets/jquery-1.4.min.js +151 -151
  22. package/assets/jquery-2.1.0.min.js +3 -3
  23. package/assets/js.js +201 -201
  24. package/assets/medicus_pdf/arabic.css +444 -444
  25. package/assets/medicus_pdf/styles.css +2427 -2427
  26. package/assets/print.css +4 -4
  27. package/assets/qr-code-style.css +68 -68
  28. package/assets/qrcode.min.js +3 -3
  29. package/assets/raphael-min.js +10 -10
  30. package/assets/sanusx/css/sanusx_report.css +707 -707
  31. package/assets/sizing.js +2 -2
  32. package/assets/styles.css +1545 -1545
  33. package/assets/styles.min.css +1358 -1358
  34. package/assets/translation.js +30 -30
  35. package/assets/wellbeing/css/nasco_report.css +3472 -3472
  36. package/assets/wellbeing/css/nasco_report_rtl.css +679 -679
  37. package/assets/wellbeing/js/js.js +111 -111
  38. package/assets/wellbeing/js/raphael.js +8437 -8437
  39. package/base64/cairo-font.js +2 -2
  40. package/config/Mediclinic.json +37 -37
  41. package/config/Najeeb.ai.json +35 -35
  42. package/config/Pha.json +64 -64
  43. package/config/bionext.json +37 -37
  44. package/config/default.json +35 -35
  45. package/config/diagnostikare.json +34 -34
  46. package/config/maisonsante.json +39 -39
  47. package/config/nasco.json +35 -35
  48. package/config/sanitas.json +35 -35
  49. package/config/sanusx.json +34 -34
  50. package/config/test.txt +4 -4
  51. package/data converter.js +53 -53
  52. package/downloadfile.js +6 -6
  53. package/example.txt +1188 -1188
  54. package/index.js +481 -481
  55. package/lib/big_integral_questionnaire.js +367 -298
  56. package/lib/corporate_report_generator.js +399 -399
  57. package/lib/pdf_generator.min.js +525 -525
  58. package/lib/sanusx_report_generator.js +533 -533
  59. package/lib/sendEmail.js +343 -343
  60. package/lib/template.js +2227 -2227
  61. package/lib/wellbeing_report_generator.js +2164 -2134
  62. package/locales/ar-AE.json +169 -169
  63. package/locales/ar-SA.json +169 -169
  64. package/locales/ar.json +397 -397
  65. package/locales/de.json +169 -169
  66. package/locales/en.json +229 -229
  67. package/locales/fr.json +168 -168
  68. package/locales/pt.json +165 -165
  69. package/locales/wellbeing/ar-AE.json +149 -149
  70. package/locales/wellbeing/ar-SA.json +257 -257
  71. package/locales/wellbeing/de.json +301 -301
  72. package/locales/wellbeing/en.json +423 -423
  73. package/locales/wellbeing/es.json +133 -133
  74. package/locales/wellbeing/fr.json +121 -121
  75. package/locales/wellbeing/it-IT.json +121 -121
  76. package/locales/wellbeing/pt.json +121 -121
  77. package/locales/wellbeing/tr.json +121 -121
  78. package/locales/wellbeing/zh-CN.json +121 -121
  79. package/locales/zh-CN.json +165 -165
  80. package/package.json +47 -47
  81. package/preview-big-integral.js +75 -75
  82. package/run.js +15 -15
  83. package/templates/Mediclinic/blocks/first-section.html +205 -205
  84. package/templates/Mediclinic/blocks/footer.html +7 -7
  85. package/templates/Mediclinic/blocks/header-template.html +5 -5
  86. package/templates/Mediclinic/blocks/header.html +20 -20
  87. package/templates/Mediclinic/blocks/patient-table.html +38 -38
  88. package/templates/Mediclinic/blocks/pdf-header.html +9 -9
  89. package/templates/Mediclinic/blocks/tips.html +8 -8
  90. package/templates/Mediclinic/ltr_no_pages.html +37 -37
  91. package/templates/Mediclinic/rtl_no_pages.html +42 -42
  92. package/templates/Mediclinic/wellbeing_template.html +41 -41
  93. package/templates/Pha/blocks/first-section.html +207 -207
  94. package/templates/Pha/blocks/footer.html +7 -7
  95. package/templates/Pha/blocks/header-template.html +5 -5
  96. package/templates/Pha/blocks/header.html +20 -20
  97. package/templates/Pha/blocks/patient-table.html +38 -38
  98. package/templates/Pha/blocks/pdf-header.html +8 -8
  99. package/templates/Pha/blocks/tips.html +8 -8
  100. package/templates/Pha/ltr_no_pages.html +37 -37
  101. package/templates/Pha/rtl_no_pages.html +42 -42
  102. package/templates/Pha/wellbeing_template.html +41 -41
  103. package/templates/base.html +23 -23
  104. package/templates/blocks/ar-first-page-header.html +68 -68
  105. package/templates/blocks/ar-footer.html +54 -54
  106. package/templates/blocks/ar-header.html +67 -67
  107. package/templates/blocks/biomarker-compact-ar.html +27 -27
  108. package/templates/blocks/biomarker-compact.html +27 -27
  109. package/templates/blocks/biomarker-details.html +41 -41
  110. package/templates/blocks/biomarker-insight.html +22 -22
  111. package/templates/blocks/biomarker-min.html +9 -9
  112. package/templates/blocks/doctor-note.html +11 -11
  113. package/templates/blocks/footer.html +35 -35
  114. package/templates/blocks/header-first-page.html +46 -46
  115. package/templates/blocks/header.html +49 -49
  116. package/templates/blocks/panel-compact.html +38 -38
  117. package/templates/blocks/panel-details.html +16 -16
  118. package/templates/blocks/report-summary.html +16 -16
  119. package/templates/blocks/section-title.html +4 -4
  120. package/templates/blocks/signature.html +16 -16
  121. package/templates/blocks/summary-insight.html +15 -15
  122. package/templates/blocks/summary.html +9 -9
  123. package/templates/corporate_report/cover_page.html +23 -23
  124. package/templates/corporate_report/footer.html +9 -9
  125. package/templates/corporate_report/ltr_no_pages.html +20 -20
  126. package/templates/corporate_report/page.html +24 -24
  127. package/templates/corporate_report/participant_analytics.html +5 -5
  128. package/templates/corporate_report/rtl_no_pages.html +20 -20
  129. package/templates/empty.html +10 -10
  130. package/templates/first_page_head.html +157 -157
  131. package/templates/imc/first-header-template.html +53 -53
  132. package/templates/ltr.html +1368 -1368
  133. package/templates/ltr_no_pages.html +89 -89
  134. package/templates/maisonsante/blocks/first-section.html +151 -207
  135. package/templates/maisonsante/blocks/footer.html +7 -7
  136. package/templates/maisonsante/blocks/header-template.html +5 -5
  137. package/templates/maisonsante/blocks/header.html +20 -20
  138. package/templates/maisonsante/blocks/patient-table.html +38 -38
  139. package/templates/maisonsante/blocks/pdf-header.html +8 -8
  140. package/templates/maisonsante/blocks/tips.html +8 -8
  141. package/templates/maisonsante/ltr_no_pages.html +38 -38
  142. package/templates/maisonsante/rtl_no_pages.html +43 -43
  143. package/templates/maisonsante/wellbeing_template.html +41 -41
  144. package/templates/no_pages.html +1224 -1224
  145. package/templates/popup/popup-template.html +129 -129
  146. package/templates/rtl_no_pages.html +92 -92
  147. package/templates/sanusx/blocks/footer.html +6 -6
  148. package/templates/sanusx/blocks/header.html +20 -20
  149. package/templates/sanusx/blocks/personal-details.html +123 -123
  150. package/templates/sanusx/blocks/predictions-section.html +57 -57
  151. package/templates/sanusx/blocks/recommendations-section.html +6 -6
  152. package/templates/sanusx/blocks/super-power-section.html +29 -29
  153. package/templates/sanusx/blocks/tips.html +8 -8
  154. package/templates/sanusx/ltr_no_pages.html +26 -26
  155. package/templates/sanusx/rtl_no_pages.html +36 -36
  156. package/templates/template.html +1377 -1377
  157. package/templates/wellbeing/blocks/first-section.html +106 -106
  158. package/templates/wellbeing/blocks/footer.html +7 -7
  159. package/templates/wellbeing/blocks/header.html +37 -37
  160. package/templates/wellbeing/blocks/tips.html +8 -8
  161. package/templates/wellbeing/ltr_no_pages.html +35 -35
  162. package/templates/wellbeing/rtl_no_pages.html +36 -36
  163. package/templates/wellbeing/wellbeing_template.html +43 -43
  164. package/test.js +74 -74
  165. package/.claude/settings.local.json +0 -16
  166. package/testing-reports/mediclinic/arabic-data.js +0 -439
  167. package/testing-reports/mediclinic/doctor-data.js +0 -523
  168. package/testing-reports/mediclinic/with-wellbeing.js +0 -415
  169. package/testing-reports/pha/notes-example.js +0 -397
package/index.js CHANGED
@@ -1,481 +1,481 @@
1
- const { generateHTMLStaging, generatePDF, generatePatientQR } = require("./lib/pdf_generator.min");
2
- const {
3
- generateHTMLWellbeingReport,
4
- generatePDFWellbeingReport,
5
- generateHTMLWellbeingReportWithSmartReport,
6
- generatePDFReport
7
- } = require("./lib/wellbeing_report_generator");
8
- const { generateSanusXReport, generateHTMLSanusXReport } = require("./lib/sanusx_report_generator");
9
- const fs = require('fs');
10
- const os = require('os');
11
- const crypto = require('crypto');
12
- const { sendNascoEmail, sendEmailNotification } = require('./lib/sendEmail')
13
- const path = require('path');
14
- const { generatePDFCorporateReport, generateHTMLCorporateReport } = require('./lib/corporate_report_generator')
15
-
16
- // Best-effort fire-and-forget cleanup for per-call temp files. Never throws.
17
- const safeUnlink = (filePath) => {
18
- if (!filePath) return Promise.resolve();
19
- return fs.promises.unlink(filePath).catch(() => { });
20
- };
21
-
22
- module.exports = {
23
-
24
- generateHTMLStaging,
25
-
26
- generateMedicusPDF: async (base64Object, isDebugging, isDownloadable, onlyHTML) => {
27
- let LOGS = '';
28
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
29
- let PDF_FILE_PATH = __dirname + '/output/sample.pdf';
30
- if (isDebugging) {
31
- if (fs.existsSync(LOGS_FILE_PATH)) {
32
- fs.unlinkSync(LOGS_FILE_PATH);
33
- }
34
- if (fs.existsSync(PDF_FILE_PATH)) {
35
- fs.unlinkSync(PDF_FILE_PATH);
36
- }
37
- }
38
- // 1: save incoming base64
39
- if (isDebugging) {
40
- console.log('1: save incoming base64');
41
- LOGS += '1: save incoming base64' + '\n' + '=============' + '\n';
42
- // LOGS += base64Object + '\n\n\n';
43
- }
44
-
45
-
46
- // 2: save decoded json string
47
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
48
- if (isDebugging) {
49
- console.log('2: save decoded json string');
50
- LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
51
- LOGS += json + '\n\n\n';
52
- }
53
-
54
-
55
- // 3: save decoded json
56
- const decodedJSON = JSON.parse(json);
57
- if (isDebugging) {
58
- console.log('3: save decoded json string')
59
- LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
60
- LOGS += decodedJSON + '\n\n\n';
61
- }
62
-
63
-
64
- let html = await generateHTMLStaging(decodedJSON, isDebugging);
65
- let fileBuffer, base64data = ''
66
- if (!onlyHTML) {
67
- // 4: save PDF buffer
68
- const startDate = Date.now();
69
- fileBuffer = await generatePDF(html);
70
- console.log(`Took ${Date.now() - startDate} ms.`);
71
- if (isDebugging) {
72
- console.log('4: save PDF buffer')
73
- LOGS += '4: save PDF buffer' + '\n' + '=============' + '\n';
74
- LOGS += fileBuffer + '\n\n\n';
75
- }
76
-
77
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
78
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
79
-
80
- // 5: save encoded base64
81
- base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
82
- if (isDebugging) {
83
- console.log('5: save encoded base64');
84
- LOGS += '5: save encoded base64' + '\n' + '=============' + '\n';
85
- LOGS += base64data + '\n\n\n';
86
- }
87
- }
88
- if (onlyHTML) {
89
- return html;
90
- } else {
91
- if (isDownloadable) {
92
- return fileBuffer;
93
- } else {
94
- return base64data;
95
- }
96
- }
97
-
98
- },
99
-
100
- generateNascoPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
101
- let reportData = JSON.parse(data)
102
- let base64Object = reportData.data
103
- let LOGS = '';
104
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
105
- let PDF_FILE_PATH = __dirname + '/output/nasco-sample.pdf';
106
-
107
- let mailConfig = {
108
- host: reportData.host,
109
- port: reportData.port,
110
- authUser: reportData.authUser,
111
- authPass: reportData.authPass,
112
- sendFromEmail: reportData.sendFromEmail,
113
- secure: reportData.secure
114
- }
115
- if (isDebugging) {
116
- if (fs.existsSync(LOGS_FILE_PATH)) {
117
- fs.unlinkSync(LOGS_FILE_PATH);
118
- }
119
-
120
- if (fs.existsSync(PDF_FILE_PATH)) {
121
- fs.unlinkSync(PDF_FILE_PATH);
122
- }
123
- }
124
-
125
- // 1: save decoded json string
126
- if (isDebugging) {
127
- console.log('2: save json string');
128
- LOGS += '2: save json string' + '\n' + '=============' + '\n';
129
- LOGS += base64Object + '\n\n\n';
130
- }
131
- // 2: save decoded json string
132
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
133
- if (isDebugging) {
134
- console.log('2: save decoded json string');
135
- LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
136
- LOGS += json + '\n\n\n';
137
- }
138
-
139
- // 3: save decoded json
140
- const decodedJSON = JSON.parse(json);
141
- if (isDebugging) {
142
- console.log('3: save decoded json string')
143
- LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
144
- LOGS += decodedJSON + '\n\n\n';
145
- }
146
- let html = await generateHTMLWellbeingReport(decodedJSON, isDebugging, reportData.client, reportData.language);
147
-
148
- // 3: save PDF buffer
149
- let fileBuffer = await generatePDFWellbeingReport(html);
150
- if (isDebugging) {
151
- console.log('3: save PDF buffer')
152
- LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
153
- LOGS += fileBuffer + '\n\n\n';
154
- }
155
-
156
- console.log("PDF_FILE_PATH", PDF_FILE_PATH)
157
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
158
-
159
- // 4: save encoded base64
160
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
161
- if (isDebugging) {
162
- console.log('4: save encoded base64');
163
- LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
164
- LOGS += base64data + '\n\n\n';
165
- }
166
-
167
-
168
- // 5: save logs to file
169
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
170
- if (isDebugging) {
171
- console.log('5: save logs to file');
172
- }
173
-
174
- if (isDownloadable) {
175
- return fileBuffer;
176
- } else {
177
- if (shouldSendEmail)
178
- return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
179
- else
180
- return base64data;
181
- }
182
- },
183
-
184
- /**
185
- * Generate full PDF report with encryption
186
- * @param {string} data - JSON string containing report data with base64 encoded content
187
- * @param {boolean} isDebugging - Enable debug mode (saves logs and keeps output files)
188
- * @param {boolean} isDownloadable - If true, returns PDF buffer; otherwise returns base64 string
189
- * @param {boolean} shouldSendEmail - If true, sends email with PDF attachment and returns email result
190
- * @param {Array<string>} [selectedLabs=[]] - Array of selected lab names for header logos
191
- * @param {boolean} [showHeaderLogo=true] - Whether to display logo in PDF header
192
- * @returns {Promise<Buffer|string|object>} Returns encrypted PDF buffer if isDownloadable, base64 string if not sending email, or email result if shouldSendEmail
193
- */
194
- generateFullPdf: async (data, isDebugging, isDownloadable, shouldSendEmail, selectedLabs = [], showHeaderLogo = true) => {
195
- let reportData = JSON.parse(data);
196
- let base64Object = reportData.data;
197
-
198
- // Per-call unique identifiers so concurrent callers never share a path.
199
- // Even when two requests overlap, each one owns its own input/output
200
- // files and email attachment, eliminating cross-user PDF swapping.
201
- const callId = crypto.randomUUID();
202
- const tmpDir = os.tmpdir();
203
- const tmpInputPath = path.join(tmpDir, `wb-${callId}-in.pdf`);
204
- const tmpEncryptedPath = path.join(tmpDir, `wb-${callId}-enc.pdf`);
205
- let tmpEmailAttachmentPath = null;
206
-
207
- let LOGS = '';
208
- const LOGS_FILE_PATH = isDebugging
209
- ? path.join(__dirname, 'output', `LOGS-${callId}.txt`)
210
- : null;
211
-
212
- const mailConfig = {
213
- host: reportData.host,
214
- port: reportData.port,
215
- authUser: reportData.authUser,
216
- authPass: reportData.authPass,
217
- sendFromEmail: reportData.sendFromEmail,
218
- secure: reportData.secure,
219
- };
220
-
221
- if (isDebugging) {
222
- console.log('2: save json string');
223
- LOGS += '2: save json string\n===============\n' + base64Object + '\n\n\n';
224
- }
225
-
226
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
227
-
228
- if (isDebugging) {
229
- console.log('2: save decoded json string');
230
- LOGS += '2: save decoded json string\n===============\n' + json + '\n\n\n';
231
- }
232
-
233
- const decodedJSON = JSON.parse(json);
234
-
235
- if (isDebugging) {
236
- console.log('3: save decoded json string');
237
- LOGS += '3: save decoded json\n===============\n' + JSON.stringify(decodedJSON, null, 2) + '\n\n\n';
238
- }
239
-
240
- const html = await generateHTMLWellbeingReportWithSmartReport(
241
- decodedJSON,
242
- isDebugging,
243
- reportData.client,
244
- reportData.language,
245
- selectedLabs || [],
246
- showHeaderLogo || true
247
- );
248
-
249
- const fileBuffer = await generatePDFReport({ ...html, client: reportData.client, footer: decodedJSON?.footer });
250
-
251
- if (isDebugging) {
252
- console.log('3: save PDF buffer');
253
- LOGS += '3: save PDF buffer\n===============\n' + '[binary content omitted]' + '\n\n\n';
254
- }
255
-
256
- try {
257
- // Write the unencrypted PDF to a per-call temp file.
258
- // qpdf needs a real input path; using a uuid-suffixed file in
259
- // os.tmpdir() guarantees no concurrent caller can overwrite it.
260
- await fs.promises.writeFile(tmpInputPath, fileBuffer);
261
-
262
- const qpdf = await import('node-qpdf2');
263
-
264
- // Encrypt to a per-call output file. We can't use qpdf's stdout
265
- // mode (output omitted) because node-qpdf2's spawn helper joins
266
- // stdout chunks as strings, which corrupts binary PDF bytes.
267
- await qpdf.encrypt({
268
- input: tmpInputPath,
269
- output: tmpEncryptedPath,
270
- keyLength: 256,
271
- password: reportData.pdfPassword,
272
- });
273
-
274
- const encryptedBuffer = await fs.promises.readFile(tmpEncryptedPath);
275
-
276
- const base64data = encryptedBuffer.toString('base64');
277
- if (isDebugging) {
278
- console.log('4: save encoded base64');
279
- LOGS += '4: save encoded base64\n===============\n' + base64data + '\n\n\n';
280
- }
281
-
282
- if (isDebugging && LOGS_FILE_PATH) {
283
- await fs.promises.writeFile(LOGS_FILE_PATH, LOGS, 'utf8');
284
- console.log('5: save logs to file');
285
- }
286
-
287
- if (isDownloadable) {
288
- return encryptedBuffer;
289
- }
290
-
291
- if (shouldSendEmail) {
292
- // Write the encrypted buffer to a dedicated per-call file just
293
- // for the email attachment. sendNascoEmail expects a path
294
- // (nodemailer reads it from disk), so we materialize it once,
295
- // pass it in, then unlink in the finally block.
296
- tmpEmailAttachmentPath = path.join(tmpDir, `wb-${callId}-mail.pdf`);
297
- await fs.promises.writeFile(tmpEmailAttachmentPath, encryptedBuffer);
298
- return await sendNascoEmail(
299
- decodedJSON.wellbeing,
300
- tmpEmailAttachmentPath,
301
- mailConfig,
302
- reportData.client
303
- );
304
- }
305
-
306
- return base64data;
307
- } finally {
308
- await Promise.all([
309
- safeUnlink(tmpInputPath),
310
- safeUnlink(tmpEncryptedPath),
311
- safeUnlink(tmpEmailAttachmentPath),
312
- ]);
313
- }
314
- },
315
-
316
- //not used
317
- generateSanuxPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
318
- let reportData = JSON.parse(data)
319
- let base64Object = reportData.data
320
- let LOGS = '';
321
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
322
- let PDF_FILE_PATH = __dirname + '/output/sanusx-sample.pdf';
323
-
324
- let mailConfig = {
325
- host: reportData.host,
326
- port: reportData.port,
327
- authUser: reportData.authUser,
328
- authPass: reportData.authPass,
329
- sendFromEmail: reportData.sendFromEmail,
330
- secure: reportData.secure
331
- }
332
- if (isDebugging) {
333
- if (fs.existsSync(LOGS_FILE_PATH)) {
334
- fs.unlinkSync(LOGS_FILE_PATH);
335
- }
336
-
337
- if (fs.existsSync(PDF_FILE_PATH)) {
338
- fs.unlinkSync(PDF_FILE_PATH);
339
- }
340
- }
341
-
342
- // 1: save decoded json string
343
- if (isDebugging) {
344
- console.log('2: save json string');
345
- LOGS += '2: save json string' + '\n' + '=============' + '\n';
346
- LOGS += base64Object + '\n\n\n';
347
- }
348
- // 2: save decoded json string
349
- const json = Buffer.from(base64Object, 'base64').toString('utf8');
350
- if (isDebugging) {
351
- console.log('2: save decoded json string');
352
- LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
353
- LOGS += json + '\n\n\n';
354
- }
355
-
356
- // 3: save decoded json
357
- const decodedJSON = JSON.parse(json);
358
- if (isDebugging) {
359
- console.log('3: save decoded json string')
360
- LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
361
- LOGS += decodedJSON + '\n\n\n';
362
- }
363
- let html = await generateHTMLSanusXReport(decodedJSON, isDebugging, reportData.client, reportData.language);
364
-
365
- // 3: save PDF buffer
366
- let fileBuffer = await generateSanusXReport(html);
367
- if (isDebugging) {
368
- console.log('3: save PDF buffer')
369
- LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
370
- LOGS += fileBuffer + '\n\n\n';
371
- }
372
-
373
- console.log("PDF_FILE_PATH", PDF_FILE_PATH)
374
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
375
-
376
- // 4: save encoded base64
377
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
378
- if (isDebugging) {
379
- console.log('4: save encoded base64');
380
- LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
381
- LOGS += base64data + '\n\n\n';
382
- }
383
-
384
-
385
- // 5: save logs to file
386
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
387
- if (isDebugging) {
388
- console.log('5: save logs to file');
389
- }
390
-
391
- if (isDownloadable) {
392
- return fileBuffer;
393
- } else {
394
- if (shouldSendEmail)
395
- return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
396
- else
397
- return base64data;
398
- }
399
- },
400
- //not used
401
- sendEmail: async (json) => {
402
- const decodedJSON = JSON.parse(json);
403
- const email = await sendEmailNotification(decodedJSON)
404
- return email
405
- },
406
- //not used
407
- generateQrCode: async (json) => {
408
- let fileBuffer = await generatePatientQR(json)
409
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
410
- return base64data
411
- },
412
- //not used
413
- generateCorporateReportPDF: async (json, isDebugging, isDownloadable) => {
414
-
415
- let LOGS = '';
416
- let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
417
- let PDF_FILE_PATH = __dirname + '/output/corporate-report-sample.pdf';
418
-
419
- if (isDebugging) {
420
- if (fs.existsSync(LOGS_FILE_PATH)) {
421
- fs.unlinkSync(LOGS_FILE_PATH);
422
- }
423
-
424
- if (fs.existsSync(PDF_FILE_PATH)) {
425
- fs.unlinkSync(PDF_FILE_PATH);
426
- }
427
- }
428
-
429
- // 1: save decoded json string
430
- if (isDebugging) {
431
- console.log('2: save json string');
432
- LOGS += '2: save json string' + '\n' + '=============' + '\n';
433
- LOGS += json + '\n\n\n';
434
- }
435
-
436
-
437
- // 2: save decoded json
438
- const decodedJSON = JSON.parse(json);
439
- if (isDebugging) {
440
- console.log('2: save decoded json string')
441
- LOGS += '2: save decoded json' + '\n' + '=============' + '\n';
442
- LOGS += decodedJSON + '\n\n\n';
443
- }
444
-
445
-
446
- let html = await generateHTMLCorporateReport(decodedJSON, isDebugging);
447
-
448
-
449
- // 3: save PDF buffer
450
- let fileBuffer = await generatePDFCorporateReport(html);
451
- if (isDebugging) {
452
- console.log('3: save PDF buffer')
453
- LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
454
- LOGS += fileBuffer + '\n\n\n';
455
- }
456
-
457
-
458
- fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
459
-
460
- // 4: save encoded base64
461
- const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
462
- if (isDebugging) {
463
- console.log('4: save encoded base64');
464
- LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
465
- LOGS += base64data + '\n\n\n';
466
- }
467
-
468
-
469
- // 5: save logs to file
470
- fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
471
- if (isDebugging) {
472
- console.log('5: save logs to file');
473
- }
474
-
475
- if (isDownloadable) {
476
- return fileBuffer;
477
- } else {
478
- return base64data;
479
- }
480
- },
481
- }
1
+ const { generateHTMLStaging, generatePDF, generatePatientQR } = require("./lib/pdf_generator.min");
2
+ const {
3
+ generateHTMLWellbeingReport,
4
+ generatePDFWellbeingReport,
5
+ generateHTMLWellbeingReportWithSmartReport,
6
+ generatePDFReport
7
+ } = require("./lib/wellbeing_report_generator");
8
+ const { generateSanusXReport, generateHTMLSanusXReport } = require("./lib/sanusx_report_generator");
9
+ const fs = require('fs');
10
+ const os = require('os');
11
+ const crypto = require('crypto');
12
+ const { sendNascoEmail, sendEmailNotification } = require('./lib/sendEmail')
13
+ const path = require('path');
14
+ const { generatePDFCorporateReport, generateHTMLCorporateReport } = require('./lib/corporate_report_generator')
15
+
16
+ // Best-effort fire-and-forget cleanup for per-call temp files. Never throws.
17
+ const safeUnlink = (filePath) => {
18
+ if (!filePath) return Promise.resolve();
19
+ return fs.promises.unlink(filePath).catch(() => { });
20
+ };
21
+
22
+ module.exports = {
23
+
24
+ generateHTMLStaging,
25
+
26
+ generateMedicusPDF: async (base64Object, isDebugging, isDownloadable, onlyHTML) => {
27
+ let LOGS = '';
28
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
29
+ let PDF_FILE_PATH = __dirname + '/output/sample.pdf';
30
+ if (isDebugging) {
31
+ if (fs.existsSync(LOGS_FILE_PATH)) {
32
+ fs.unlinkSync(LOGS_FILE_PATH);
33
+ }
34
+ if (fs.existsSync(PDF_FILE_PATH)) {
35
+ fs.unlinkSync(PDF_FILE_PATH);
36
+ }
37
+ }
38
+ // 1: save incoming base64
39
+ if (isDebugging) {
40
+ console.log('1: save incoming base64');
41
+ LOGS += '1: save incoming base64' + '\n' + '=============' + '\n';
42
+ // LOGS += base64Object + '\n\n\n';
43
+ }
44
+
45
+
46
+ // 2: save decoded json string
47
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
48
+ if (isDebugging) {
49
+ console.log('2: save decoded json string');
50
+ LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
51
+ LOGS += json + '\n\n\n';
52
+ }
53
+
54
+
55
+ // 3: save decoded json
56
+ const decodedJSON = JSON.parse(json);
57
+ if (isDebugging) {
58
+ console.log('3: save decoded json string')
59
+ LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
60
+ LOGS += decodedJSON + '\n\n\n';
61
+ }
62
+
63
+
64
+ let html = await generateHTMLStaging(decodedJSON, isDebugging);
65
+ let fileBuffer, base64data = ''
66
+ if (!onlyHTML) {
67
+ // 4: save PDF buffer
68
+ const startDate = Date.now();
69
+ fileBuffer = await generatePDF(html);
70
+ console.log(`Took ${Date.now() - startDate} ms.`);
71
+ if (isDebugging) {
72
+ console.log('4: save PDF buffer')
73
+ LOGS += '4: save PDF buffer' + '\n' + '=============' + '\n';
74
+ LOGS += fileBuffer + '\n\n\n';
75
+ }
76
+
77
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
78
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
79
+
80
+ // 5: save encoded base64
81
+ base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
82
+ if (isDebugging) {
83
+ console.log('5: save encoded base64');
84
+ LOGS += '5: save encoded base64' + '\n' + '=============' + '\n';
85
+ LOGS += base64data + '\n\n\n';
86
+ }
87
+ }
88
+ if (onlyHTML) {
89
+ return html;
90
+ } else {
91
+ if (isDownloadable) {
92
+ return fileBuffer;
93
+ } else {
94
+ return base64data;
95
+ }
96
+ }
97
+
98
+ },
99
+
100
+ generateNascoPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
101
+ let reportData = JSON.parse(data)
102
+ let base64Object = reportData.data
103
+ let LOGS = '';
104
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
105
+ let PDF_FILE_PATH = __dirname + '/output/nasco-sample.pdf';
106
+
107
+ let mailConfig = {
108
+ host: reportData.host,
109
+ port: reportData.port,
110
+ authUser: reportData.authUser,
111
+ authPass: reportData.authPass,
112
+ sendFromEmail: reportData.sendFromEmail,
113
+ secure: reportData.secure
114
+ }
115
+ if (isDebugging) {
116
+ if (fs.existsSync(LOGS_FILE_PATH)) {
117
+ fs.unlinkSync(LOGS_FILE_PATH);
118
+ }
119
+
120
+ if (fs.existsSync(PDF_FILE_PATH)) {
121
+ fs.unlinkSync(PDF_FILE_PATH);
122
+ }
123
+ }
124
+
125
+ // 1: save decoded json string
126
+ if (isDebugging) {
127
+ console.log('2: save json string');
128
+ LOGS += '2: save json string' + '\n' + '=============' + '\n';
129
+ LOGS += base64Object + '\n\n\n';
130
+ }
131
+ // 2: save decoded json string
132
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
133
+ if (isDebugging) {
134
+ console.log('2: save decoded json string');
135
+ LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
136
+ LOGS += json + '\n\n\n';
137
+ }
138
+
139
+ // 3: save decoded json
140
+ const decodedJSON = JSON.parse(json);
141
+ if (isDebugging) {
142
+ console.log('3: save decoded json string')
143
+ LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
144
+ LOGS += decodedJSON + '\n\n\n';
145
+ }
146
+ let html = await generateHTMLWellbeingReport(decodedJSON, isDebugging, reportData.client, reportData.language);
147
+
148
+ // 3: save PDF buffer
149
+ let fileBuffer = await generatePDFWellbeingReport(html);
150
+ if (isDebugging) {
151
+ console.log('3: save PDF buffer')
152
+ LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
153
+ LOGS += fileBuffer + '\n\n\n';
154
+ }
155
+
156
+ console.log("PDF_FILE_PATH", PDF_FILE_PATH)
157
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
158
+
159
+ // 4: save encoded base64
160
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
161
+ if (isDebugging) {
162
+ console.log('4: save encoded base64');
163
+ LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
164
+ LOGS += base64data + '\n\n\n';
165
+ }
166
+
167
+
168
+ // 5: save logs to file
169
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
170
+ if (isDebugging) {
171
+ console.log('5: save logs to file');
172
+ }
173
+
174
+ if (isDownloadable) {
175
+ return fileBuffer;
176
+ } else {
177
+ if (shouldSendEmail)
178
+ return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
179
+ else
180
+ return base64data;
181
+ }
182
+ },
183
+
184
+ /**
185
+ * Generate full PDF report with encryption
186
+ * @param {string} data - JSON string containing report data with base64 encoded content
187
+ * @param {boolean} isDebugging - Enable debug mode (saves logs and keeps output files)
188
+ * @param {boolean} isDownloadable - If true, returns PDF buffer; otherwise returns base64 string
189
+ * @param {boolean} shouldSendEmail - If true, sends email with PDF attachment and returns email result
190
+ * @param {Array<string>} [selectedLabs=[]] - Array of selected lab names for header logos
191
+ * @param {boolean} [showHeaderLogo=true] - Whether to display logo in PDF header
192
+ * @returns {Promise<Buffer|string|object>} Returns encrypted PDF buffer if isDownloadable, base64 string if not sending email, or email result if shouldSendEmail
193
+ */
194
+ generateFullPdf: async (data, isDebugging, isDownloadable, shouldSendEmail, selectedLabs = [], showHeaderLogo = true) => {
195
+ let reportData = JSON.parse(data);
196
+ let base64Object = reportData.data;
197
+
198
+ // Per-call unique identifiers so concurrent callers never share a path.
199
+ // Even when two requests overlap, each one owns its own input/output
200
+ // files and email attachment, eliminating cross-user PDF swapping.
201
+ const callId = crypto.randomUUID();
202
+ const tmpDir = os.tmpdir();
203
+ const tmpInputPath = path.join(tmpDir, `wb-${callId}-in.pdf`);
204
+ const tmpEncryptedPath = path.join(tmpDir, `wb-${callId}-enc.pdf`);
205
+ let tmpEmailAttachmentPath = null;
206
+
207
+ let LOGS = '';
208
+ const LOGS_FILE_PATH = isDebugging
209
+ ? path.join(__dirname, 'output', `LOGS-${callId}.txt`)
210
+ : null;
211
+
212
+ const mailConfig = {
213
+ host: reportData.host,
214
+ port: reportData.port,
215
+ authUser: reportData.authUser,
216
+ authPass: reportData.authPass,
217
+ sendFromEmail: reportData.sendFromEmail,
218
+ secure: reportData.secure,
219
+ };
220
+
221
+ if (isDebugging) {
222
+ console.log('2: save json string');
223
+ LOGS += '2: save json string\n===============\n' + base64Object + '\n\n\n';
224
+ }
225
+
226
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
227
+
228
+ if (isDebugging) {
229
+ console.log('2: save decoded json string');
230
+ LOGS += '2: save decoded json string\n===============\n' + json + '\n\n\n';
231
+ }
232
+
233
+ const decodedJSON = JSON.parse(json);
234
+
235
+ if (isDebugging) {
236
+ console.log('3: save decoded json string');
237
+ LOGS += '3: save decoded json\n===============\n' + JSON.stringify(decodedJSON, null, 2) + '\n\n\n';
238
+ }
239
+
240
+ const html = await generateHTMLWellbeingReportWithSmartReport(
241
+ decodedJSON,
242
+ isDebugging,
243
+ reportData.client,
244
+ reportData.language,
245
+ selectedLabs || [],
246
+ showHeaderLogo || true
247
+ );
248
+
249
+ const fileBuffer = await generatePDFReport({ ...html, client: reportData.client, footer: decodedJSON?.footer });
250
+
251
+ if (isDebugging) {
252
+ console.log('3: save PDF buffer');
253
+ LOGS += '3: save PDF buffer\n===============\n' + '[binary content omitted]' + '\n\n\n';
254
+ }
255
+
256
+ try {
257
+ // Write the unencrypted PDF to a per-call temp file.
258
+ // qpdf needs a real input path; using a uuid-suffixed file in
259
+ // os.tmpdir() guarantees no concurrent caller can overwrite it.
260
+ await fs.promises.writeFile(tmpInputPath, fileBuffer);
261
+
262
+ const qpdf = await import('node-qpdf2');
263
+
264
+ // Encrypt to a per-call output file. We can't use qpdf's stdout
265
+ // mode (output omitted) because node-qpdf2's spawn helper joins
266
+ // stdout chunks as strings, which corrupts binary PDF bytes.
267
+ await qpdf.encrypt({
268
+ input: tmpInputPath,
269
+ output: tmpEncryptedPath,
270
+ keyLength: 256,
271
+ password: reportData.pdfPassword,
272
+ });
273
+
274
+ const encryptedBuffer = await fs.promises.readFile(tmpEncryptedPath);
275
+
276
+ const base64data = encryptedBuffer.toString('base64');
277
+ if (isDebugging) {
278
+ console.log('4: save encoded base64');
279
+ LOGS += '4: save encoded base64\n===============\n' + base64data + '\n\n\n';
280
+ }
281
+
282
+ if (isDebugging && LOGS_FILE_PATH) {
283
+ await fs.promises.writeFile(LOGS_FILE_PATH, LOGS, 'utf8');
284
+ console.log('5: save logs to file');
285
+ }
286
+
287
+ if (isDownloadable) {
288
+ return encryptedBuffer;
289
+ }
290
+
291
+ if (shouldSendEmail) {
292
+ // Write the encrypted buffer to a dedicated per-call file just
293
+ // for the email attachment. sendNascoEmail expects a path
294
+ // (nodemailer reads it from disk), so we materialize it once,
295
+ // pass it in, then unlink in the finally block.
296
+ tmpEmailAttachmentPath = path.join(tmpDir, `wb-${callId}-mail.pdf`);
297
+ await fs.promises.writeFile(tmpEmailAttachmentPath, encryptedBuffer);
298
+ return await sendNascoEmail(
299
+ decodedJSON.wellbeing,
300
+ tmpEmailAttachmentPath,
301
+ mailConfig,
302
+ reportData.client
303
+ );
304
+ }
305
+
306
+ return base64data;
307
+ } finally {
308
+ await Promise.all([
309
+ safeUnlink(tmpInputPath),
310
+ safeUnlink(tmpEncryptedPath),
311
+ safeUnlink(tmpEmailAttachmentPath),
312
+ ]);
313
+ }
314
+ },
315
+
316
+ //not used
317
+ generateSanuxPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
318
+ let reportData = JSON.parse(data)
319
+ let base64Object = reportData.data
320
+ let LOGS = '';
321
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
322
+ let PDF_FILE_PATH = __dirname + '/output/sanusx-sample.pdf';
323
+
324
+ let mailConfig = {
325
+ host: reportData.host,
326
+ port: reportData.port,
327
+ authUser: reportData.authUser,
328
+ authPass: reportData.authPass,
329
+ sendFromEmail: reportData.sendFromEmail,
330
+ secure: reportData.secure
331
+ }
332
+ if (isDebugging) {
333
+ if (fs.existsSync(LOGS_FILE_PATH)) {
334
+ fs.unlinkSync(LOGS_FILE_PATH);
335
+ }
336
+
337
+ if (fs.existsSync(PDF_FILE_PATH)) {
338
+ fs.unlinkSync(PDF_FILE_PATH);
339
+ }
340
+ }
341
+
342
+ // 1: save decoded json string
343
+ if (isDebugging) {
344
+ console.log('2: save json string');
345
+ LOGS += '2: save json string' + '\n' + '=============' + '\n';
346
+ LOGS += base64Object + '\n\n\n';
347
+ }
348
+ // 2: save decoded json string
349
+ const json = Buffer.from(base64Object, 'base64').toString('utf8');
350
+ if (isDebugging) {
351
+ console.log('2: save decoded json string');
352
+ LOGS += '2: save decoded json string' + '\n' + '=============' + '\n';
353
+ LOGS += json + '\n\n\n';
354
+ }
355
+
356
+ // 3: save decoded json
357
+ const decodedJSON = JSON.parse(json);
358
+ if (isDebugging) {
359
+ console.log('3: save decoded json string')
360
+ LOGS += '3: save decoded json' + '\n' + '=============' + '\n';
361
+ LOGS += decodedJSON + '\n\n\n';
362
+ }
363
+ let html = await generateHTMLSanusXReport(decodedJSON, isDebugging, reportData.client, reportData.language);
364
+
365
+ // 3: save PDF buffer
366
+ let fileBuffer = await generateSanusXReport(html);
367
+ if (isDebugging) {
368
+ console.log('3: save PDF buffer')
369
+ LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
370
+ LOGS += fileBuffer + '\n\n\n';
371
+ }
372
+
373
+ console.log("PDF_FILE_PATH", PDF_FILE_PATH)
374
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
375
+
376
+ // 4: save encoded base64
377
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
378
+ if (isDebugging) {
379
+ console.log('4: save encoded base64');
380
+ LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
381
+ LOGS += base64data + '\n\n\n';
382
+ }
383
+
384
+
385
+ // 5: save logs to file
386
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
387
+ if (isDebugging) {
388
+ console.log('5: save logs to file');
389
+ }
390
+
391
+ if (isDownloadable) {
392
+ return fileBuffer;
393
+ } else {
394
+ if (shouldSendEmail)
395
+ return await sendNascoEmail(decodedJSON, PDF_FILE_PATH, mailConfig, reportData.client)
396
+ else
397
+ return base64data;
398
+ }
399
+ },
400
+ //not used
401
+ sendEmail: async (json) => {
402
+ const decodedJSON = JSON.parse(json);
403
+ const email = await sendEmailNotification(decodedJSON)
404
+ return email
405
+ },
406
+ //not used
407
+ generateQrCode: async (json) => {
408
+ let fileBuffer = await generatePatientQR(json)
409
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
410
+ return base64data
411
+ },
412
+ //not used
413
+ generateCorporateReportPDF: async (json, isDebugging, isDownloadable) => {
414
+
415
+ let LOGS = '';
416
+ let LOGS_FILE_PATH = __dirname + '/output/LOGS.txt';
417
+ let PDF_FILE_PATH = __dirname + '/output/corporate-report-sample.pdf';
418
+
419
+ if (isDebugging) {
420
+ if (fs.existsSync(LOGS_FILE_PATH)) {
421
+ fs.unlinkSync(LOGS_FILE_PATH);
422
+ }
423
+
424
+ if (fs.existsSync(PDF_FILE_PATH)) {
425
+ fs.unlinkSync(PDF_FILE_PATH);
426
+ }
427
+ }
428
+
429
+ // 1: save decoded json string
430
+ if (isDebugging) {
431
+ console.log('2: save json string');
432
+ LOGS += '2: save json string' + '\n' + '=============' + '\n';
433
+ LOGS += json + '\n\n\n';
434
+ }
435
+
436
+
437
+ // 2: save decoded json
438
+ const decodedJSON = JSON.parse(json);
439
+ if (isDebugging) {
440
+ console.log('2: save decoded json string')
441
+ LOGS += '2: save decoded json' + '\n' + '=============' + '\n';
442
+ LOGS += decodedJSON + '\n\n\n';
443
+ }
444
+
445
+
446
+ let html = await generateHTMLCorporateReport(decodedJSON, isDebugging);
447
+
448
+
449
+ // 3: save PDF buffer
450
+ let fileBuffer = await generatePDFCorporateReport(html);
451
+ if (isDebugging) {
452
+ console.log('3: save PDF buffer')
453
+ LOGS += '3: save PDF buffer' + '\n' + '=============' + '\n';
454
+ LOGS += fileBuffer + '\n\n\n';
455
+ }
456
+
457
+
458
+ fs.writeFileSync(PDF_FILE_PATH, fileBuffer, 'utf8');
459
+
460
+ // 4: save encoded base64
461
+ const base64data = Buffer.from(fileBuffer, 'utf8').toString('base64');
462
+ if (isDebugging) {
463
+ console.log('4: save encoded base64');
464
+ LOGS += '4: save encoded base64' + '\n' + '=============' + '\n';
465
+ LOGS += base64data + '\n\n\n';
466
+ }
467
+
468
+
469
+ // 5: save logs to file
470
+ fs.writeFileSync(LOGS_FILE_PATH, LOGS, 'utf8');
471
+ if (isDebugging) {
472
+ console.log('5: save logs to file');
473
+ }
474
+
475
+ if (isDownloadable) {
476
+ return fileBuffer;
477
+ } else {
478
+ return base64data;
479
+ }
480
+ },
481
+ }