@medicus.ai/medicus-report-pdf-generator 1.3.8 → 1.3.9
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/index.js +60 -30
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -7,10 +7,18 @@ const {
|
|
|
7
7
|
} = require("./lib/wellbeing_report_generator");
|
|
8
8
|
const { generateSanusXReport, generateHTMLSanusXReport } = require("./lib/sanusx_report_generator");
|
|
9
9
|
const fs = require('fs');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const crypto = require('crypto');
|
|
10
12
|
const { sendNascoEmail, sendEmailNotification } = require('./lib/sendEmail')
|
|
11
13
|
const path = require('path');
|
|
12
14
|
const { generatePDFCorporateReport, generateHTMLCorporateReport } = require('./lib/corporate_report_generator')
|
|
13
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
|
+
|
|
14
22
|
module.exports = {
|
|
15
23
|
|
|
16
24
|
generateHTMLStaging,
|
|
@@ -187,10 +195,19 @@ module.exports = {
|
|
|
187
195
|
let reportData = JSON.parse(data);
|
|
188
196
|
let base64Object = reportData.data;
|
|
189
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
|
+
|
|
190
207
|
let LOGS = '';
|
|
191
|
-
const LOGS_FILE_PATH =
|
|
192
|
-
|
|
193
|
-
|
|
208
|
+
const LOGS_FILE_PATH = isDebugging
|
|
209
|
+
? path.join(__dirname, 'output', `LOGS-${callId}.txt`)
|
|
210
|
+
: null;
|
|
194
211
|
|
|
195
212
|
const mailConfig = {
|
|
196
213
|
host: reportData.host,
|
|
@@ -201,12 +218,6 @@ module.exports = {
|
|
|
201
218
|
secure: reportData.secure,
|
|
202
219
|
};
|
|
203
220
|
|
|
204
|
-
if (isDebugging) {
|
|
205
|
-
if (fs.existsSync(LOGS_FILE_PATH)) fs.unlinkSync(LOGS_FILE_PATH);
|
|
206
|
-
if (fs.existsSync(PDF_FILE_PATH)) fs.unlinkSync(PDF_FILE_PATH);
|
|
207
|
-
if (fs.existsSync(ENCRYPTED_PDF_PATH)) fs.unlinkSync(ENCRYPTED_PDF_PATH);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
221
|
if (isDebugging) {
|
|
211
222
|
console.log('2: save json string');
|
|
212
223
|
LOGS += '2: save json string\n===============\n' + base64Object + '\n\n\n';
|
|
@@ -242,45 +253,64 @@ module.exports = {
|
|
|
242
253
|
LOGS += '3: save PDF buffer\n===============\n' + '[binary content omitted]' + '\n\n\n';
|
|
243
254
|
}
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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);
|
|
248
261
|
|
|
249
|
-
return await (async () => {
|
|
250
262
|
const qpdf = await import('node-qpdf2');
|
|
251
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.
|
|
252
267
|
await qpdf.encrypt({
|
|
253
|
-
input:
|
|
254
|
-
output:
|
|
268
|
+
input: tmpInputPath,
|
|
269
|
+
output: tmpEncryptedPath,
|
|
255
270
|
keyLength: 256,
|
|
256
271
|
password: reportData.pdfPassword,
|
|
257
|
-
})
|
|
258
|
-
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const encryptedBuffer = await fs.promises.readFile(tmpEncryptedPath);
|
|
259
275
|
|
|
260
|
-
|
|
261
|
-
const base64data = Buffer.from(encryptedBuffer).toString('base64');
|
|
276
|
+
const base64data = encryptedBuffer.toString('base64');
|
|
262
277
|
if (isDebugging) {
|
|
263
278
|
console.log('4: save encoded base64');
|
|
264
279
|
LOGS += '4: save encoded base64\n===============\n' + base64data + '\n\n\n';
|
|
265
280
|
}
|
|
266
281
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
+
}
|
|
270
286
|
|
|
271
287
|
if (isDownloadable) {
|
|
272
288
|
return encryptedBuffer;
|
|
273
|
-
} else {
|
|
274
|
-
if (shouldSendEmail) {
|
|
275
|
-
return await sendNascoEmail(decodedJSON.wellbeing, ENCRYPTED_PDF_PATH, mailConfig, reportData.client);
|
|
276
|
-
} else {
|
|
277
|
-
return base64data;
|
|
278
|
-
}
|
|
279
289
|
}
|
|
280
290
|
|
|
281
|
-
|
|
282
|
-
|
|
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
|
+
}
|
|
283
305
|
|
|
306
|
+
return base64data;
|
|
307
|
+
} finally {
|
|
308
|
+
await Promise.all([
|
|
309
|
+
safeUnlink(tmpInputPath),
|
|
310
|
+
safeUnlink(tmpEncryptedPath),
|
|
311
|
+
safeUnlink(tmpEmailAttachmentPath),
|
|
312
|
+
]);
|
|
313
|
+
}
|
|
284
314
|
},
|
|
285
315
|
|
|
286
316
|
generateSanuxPDF: async (data, isDebugging, isDownloadable, shouldSendEmail) => {
|