@teleporthq/teleport-plugin-next-workflows 0.44.0 → 0.44.1

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 (158) hide show
  1. package/__tests__/_helpers/fake-store-database.ts +428 -0
  2. package/__tests__/_helpers/invoice-store.ts +382 -0
  3. package/__tests__/email-locale-senders.test.ts +3 -1
  4. package/__tests__/email-sender-name.test.ts +513 -0
  5. package/__tests__/graph-utils-topological-order.test.ts +155 -1
  6. package/__tests__/invoice-billing-details.test.ts +107 -1
  7. package/__tests__/invoice-data-access-replace.test.ts +236 -2
  8. package/__tests__/invoice-order-items-settle.test.ts +1 -1
  9. package/__tests__/invoice-payment-email.test.ts +191 -0
  10. package/__tests__/invoice-regenerate-email.test.ts +288 -0
  11. package/__tests__/invoice-regenerate-route.test.ts +9 -7
  12. package/__tests__/invoice-reservation.test.ts +1 -1
  13. package/__tests__/invoice-tender.test.ts +1 -1
  14. package/__tests__/segment-splitter-checkout-order.test.ts +306 -0
  15. package/__tests__/streaming-on-end-env-filter.test.ts +18 -18
  16. package/__tests__/streaming-on-end-order.test.ts +387 -0
  17. package/dist/cjs/account-delete-route-generator.d.ts +1 -0
  18. package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
  19. package/dist/cjs/account-delete-route-generator.js +2 -1
  20. package/dist/cjs/account-delete-route-generator.js.map +1 -1
  21. package/dist/cjs/auth-generator.d.ts +1 -0
  22. package/dist/cjs/auth-generator.d.ts.map +1 -1
  23. package/dist/cjs/auth-generator.js +2 -1
  24. package/dist/cjs/auth-generator.js.map +1 -1
  25. package/dist/cjs/executor-generator.d.ts.map +1 -1
  26. package/dist/cjs/executor-generator.js +9 -26
  27. package/dist/cjs/executor-generator.js.map +1 -1
  28. package/dist/cjs/graph-utils.d.ts +31 -1
  29. package/dist/cjs/graph-utils.d.ts.map +1 -1
  30. package/dist/cjs/graph-utils.js +112 -10
  31. package/dist/cjs/graph-utils.js.map +1 -1
  32. package/dist/cjs/invoice/api-routes-code.d.ts +12 -3
  33. package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
  34. package/dist/cjs/invoice/api-routes-code.js +152 -21
  35. package/dist/cjs/invoice/api-routes-code.js.map +1 -1
  36. package/dist/cjs/invoice/data-access-code.d.ts.map +1 -1
  37. package/dist/cjs/invoice/data-access-code.js +133 -21
  38. package/dist/cjs/invoice/data-access-code.js.map +1 -1
  39. package/dist/cjs/invoice/email-sender-code.d.ts.map +1 -1
  40. package/dist/cjs/invoice/email-sender-code.js +15 -25
  41. package/dist/cjs/invoice/email-sender-code.js.map +1 -1
  42. package/dist/cjs/invoice/index.js +1 -1
  43. package/dist/cjs/invoice/index.js.map +1 -1
  44. package/dist/cjs/invoice/invoice-assembly-code.d.ts.map +1 -1
  45. package/dist/cjs/invoice/invoice-assembly-code.js +10 -6
  46. package/dist/cjs/invoice/invoice-assembly-code.js.map +1 -1
  47. package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
  48. package/dist/cjs/invoice/invoice-html-code.js +3 -0
  49. package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
  50. package/dist/cjs/nodes/email/email-mailgun.d.ts.map +1 -1
  51. package/dist/cjs/nodes/email/email-mailgun.js +4 -2
  52. package/dist/cjs/nodes/email/email-mailgun.js.map +1 -1
  53. package/dist/cjs/nodes/email/email-postmark.d.ts.map +1 -1
  54. package/dist/cjs/nodes/email/email-postmark.js +5 -2
  55. package/dist/cjs/nodes/email/email-postmark.js.map +1 -1
  56. package/dist/cjs/nodes/email/email-resend.d.ts.map +1 -1
  57. package/dist/cjs/nodes/email/email-resend.js +5 -2
  58. package/dist/cjs/nodes/email/email-resend.js.map +1 -1
  59. package/dist/cjs/nodes/email/email-sendgrid.d.ts.map +1 -1
  60. package/dist/cjs/nodes/email/email-sendgrid.js +8 -2
  61. package/dist/cjs/nodes/email/email-sendgrid.js.map +1 -1
  62. package/dist/cjs/nodes/storage/storage-local-remove.d.ts.map +1 -1
  63. package/dist/cjs/nodes/storage/storage-local-remove.js +2 -0
  64. package/dist/cjs/nodes/storage/storage-local-remove.js.map +1 -1
  65. package/dist/cjs/nodes/storage/storage-local-set.d.ts.map +1 -1
  66. package/dist/cjs/nodes/storage/storage-local-set.js +4 -0
  67. package/dist/cjs/nodes/storage/storage-local-set.js.map +1 -1
  68. package/dist/cjs/segment-splitter.d.ts.map +1 -1
  69. package/dist/cjs/segment-splitter.js +65 -27
  70. package/dist/cjs/segment-splitter.js.map +1 -1
  71. package/dist/cjs/transactional-email-code.d.ts.map +1 -1
  72. package/dist/cjs/transactional-email-code.js +32 -18
  73. package/dist/cjs/transactional-email-code.js.map +1 -1
  74. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  75. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  76. package/dist/cjs/workflow-project-plugin.js +2 -0
  77. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  78. package/dist/esm/account-delete-route-generator.d.ts +1 -0
  79. package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
  80. package/dist/esm/account-delete-route-generator.js +2 -1
  81. package/dist/esm/account-delete-route-generator.js.map +1 -1
  82. package/dist/esm/auth-generator.d.ts +1 -0
  83. package/dist/esm/auth-generator.d.ts.map +1 -1
  84. package/dist/esm/auth-generator.js +2 -1
  85. package/dist/esm/auth-generator.js.map +1 -1
  86. package/dist/esm/executor-generator.d.ts.map +1 -1
  87. package/dist/esm/executor-generator.js +9 -26
  88. package/dist/esm/executor-generator.js.map +1 -1
  89. package/dist/esm/graph-utils.d.ts +31 -1
  90. package/dist/esm/graph-utils.d.ts.map +1 -1
  91. package/dist/esm/graph-utils.js +109 -9
  92. package/dist/esm/graph-utils.js.map +1 -1
  93. package/dist/esm/invoice/api-routes-code.d.ts +12 -3
  94. package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
  95. package/dist/esm/invoice/api-routes-code.js +152 -21
  96. package/dist/esm/invoice/api-routes-code.js.map +1 -1
  97. package/dist/esm/invoice/data-access-code.d.ts.map +1 -1
  98. package/dist/esm/invoice/data-access-code.js +133 -21
  99. package/dist/esm/invoice/data-access-code.js.map +1 -1
  100. package/dist/esm/invoice/email-sender-code.d.ts.map +1 -1
  101. package/dist/esm/invoice/email-sender-code.js +15 -25
  102. package/dist/esm/invoice/email-sender-code.js.map +1 -1
  103. package/dist/esm/invoice/index.js +1 -1
  104. package/dist/esm/invoice/index.js.map +1 -1
  105. package/dist/esm/invoice/invoice-assembly-code.d.ts.map +1 -1
  106. package/dist/esm/invoice/invoice-assembly-code.js +10 -6
  107. package/dist/esm/invoice/invoice-assembly-code.js.map +1 -1
  108. package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
  109. package/dist/esm/invoice/invoice-html-code.js +3 -0
  110. package/dist/esm/invoice/invoice-html-code.js.map +1 -1
  111. package/dist/esm/nodes/email/email-mailgun.d.ts.map +1 -1
  112. package/dist/esm/nodes/email/email-mailgun.js +4 -2
  113. package/dist/esm/nodes/email/email-mailgun.js.map +1 -1
  114. package/dist/esm/nodes/email/email-postmark.d.ts.map +1 -1
  115. package/dist/esm/nodes/email/email-postmark.js +5 -2
  116. package/dist/esm/nodes/email/email-postmark.js.map +1 -1
  117. package/dist/esm/nodes/email/email-resend.d.ts.map +1 -1
  118. package/dist/esm/nodes/email/email-resend.js +5 -2
  119. package/dist/esm/nodes/email/email-resend.js.map +1 -1
  120. package/dist/esm/nodes/email/email-sendgrid.d.ts.map +1 -1
  121. package/dist/esm/nodes/email/email-sendgrid.js +8 -2
  122. package/dist/esm/nodes/email/email-sendgrid.js.map +1 -1
  123. package/dist/esm/nodes/storage/storage-local-remove.d.ts.map +1 -1
  124. package/dist/esm/nodes/storage/storage-local-remove.js +2 -0
  125. package/dist/esm/nodes/storage/storage-local-remove.js.map +1 -1
  126. package/dist/esm/nodes/storage/storage-local-set.d.ts.map +1 -1
  127. package/dist/esm/nodes/storage/storage-local-set.js +4 -0
  128. package/dist/esm/nodes/storage/storage-local-set.js.map +1 -1
  129. package/dist/esm/segment-splitter.d.ts.map +1 -1
  130. package/dist/esm/segment-splitter.js +66 -28
  131. package/dist/esm/segment-splitter.js.map +1 -1
  132. package/dist/esm/transactional-email-code.d.ts.map +1 -1
  133. package/dist/esm/transactional-email-code.js +32 -18
  134. package/dist/esm/transactional-email-code.js.map +1 -1
  135. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  136. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  137. package/dist/esm/workflow-project-plugin.js +2 -0
  138. package/dist/esm/workflow-project-plugin.js.map +1 -1
  139. package/package.json +3 -3
  140. package/src/account-delete-route-generator.ts +3 -1
  141. package/src/auth-generator.ts +3 -1
  142. package/src/executor-generator.ts +9 -26
  143. package/src/graph-utils.ts +143 -11
  144. package/src/invoice/api-routes-code.ts +166 -21
  145. package/src/invoice/data-access-code.ts +139 -21
  146. package/src/invoice/email-sender-code.ts +15 -25
  147. package/src/invoice/index.ts +1 -1
  148. package/src/invoice/invoice-assembly-code.ts +10 -6
  149. package/src/invoice/invoice-html-code.ts +3 -0
  150. package/src/nodes/email/email-mailgun.ts +11 -2
  151. package/src/nodes/email/email-postmark.ts +12 -2
  152. package/src/nodes/email/email-resend.ts +12 -2
  153. package/src/nodes/email/email-sendgrid.ts +15 -2
  154. package/src/nodes/storage/storage-local-remove.ts +4 -0
  155. package/src/nodes/storage/storage-local-set.ts +6 -0
  156. package/src/segment-splitter.ts +90 -36
  157. package/src/transactional-email-code.ts +32 -21
  158. package/src/workflow-project-plugin.ts +2 -0
@@ -56,6 +56,39 @@ async function invoiceCaller(req) {
56
56
  userId: userId != null ? String(userId) : null,
57
57
  };
58
58
  }`;
59
+ /**
60
+ * The order-history line of an invoice email the provider accepted: an
61
+ * `order-email-sent` line of the email's purpose, keyed on the invoice, so the
62
+ * email is on its order's history once, whichever route sent it. The strings
63
+ * are data in the merchant's database, owned by teleport-gui's
64
+ * `order-event-types.ts` and `EmailTemplatePurpose.INVOICE_EMAIL`.
65
+ */
66
+ const INVOICE_EMAIL_EVENT = { type: 'order-email-sent', purpose: 'invoice-email' };
67
+ /** Who sent an invoice email, as the order's history names them. */
68
+ const INVOICE_EMAIL_SENDERS = {
69
+ // The store's own code: the payment webhook's invoice step, the checkout.
70
+ store: { actor: '', actorType: 'system' },
71
+ // A signed-in admin: the admin panel's Regenerate, or an invoice issued by hand.
72
+ admin: { actor: 'Store admin', actorType: 'merchant' },
73
+ };
74
+ /** `recordInvoiceEmailSent(invoiceData, sender)`, as emitted source; needs `dataAccess`. */
75
+ const RECORD_INVOICE_EMAIL_CODE = `
76
+ var INVOICE_EMAIL_EVENT = ${JSON.stringify(INVOICE_EMAIL_EVENT)};
77
+ var INVOICE_EMAIL_SENDERS = ${JSON.stringify(INVOICE_EMAIL_SENDERS)};
78
+
79
+ // Writes the order's history line for an invoice email the provider accepted.
80
+ // The key is the invoice's, so the line is written once per invoice email.
81
+ async function recordInvoiceEmailSent(invoiceData, sender) {
82
+ if (!invoiceData.orderId) return;
83
+ await dataAccess.recordOrderEvent({
84
+ type: INVOICE_EMAIL_EVENT.type,
85
+ dedupeKey: INVOICE_EMAIL_EVENT.type + ':' + invoiceData.id + ':' + INVOICE_EMAIL_EVENT.purpose,
86
+ orderId: invoiceData.orderId,
87
+ payload: { purpose: INVOICE_EMAIL_EVENT.purpose, to: invoiceData.customerEmail },
88
+ actor: sender.actor,
89
+ actorType: sender.actorType,
90
+ });
91
+ }`;
59
92
  const generateInvoiceGenerateRouteCode = (settings) => {
60
93
  var _a;
61
94
  const prefix = settings.invoicePrefix || 'INV-';
@@ -89,6 +122,7 @@ var INVOICE_PREFIX = ${JSON.stringify(prefix)};
89
122
  var UNFINISHED_INVOICE_STALE_SECONDS = 900;
90
123
 
91
124
  ${INVOICE_CALLER_CODE}
125
+ ${emailEnabled ? RECORD_INVOICE_EMAIL_CODE : ''}
92
126
 
93
127
  // ---------------------------------------------------------------------------
94
128
  // Waiting for the order's line items to be fully written.
@@ -124,6 +158,21 @@ function sleepMs(ms) {
124
158
  return new Promise(function (resolve) { setTimeout(resolve, ms); });
125
159
  }
126
160
 
161
+ // The answer for an invoice the order already has: its number and its PDF.
162
+ function issuedInvoiceAnswer(invoice, currency) {
163
+ var pdfUrl = invoice.pdf_url || ('/api/invoices/' + invoice.id + '/pdf');
164
+ return {
165
+ success: true,
166
+ alreadyIssued: true,
167
+ invoiceId: invoice.id,
168
+ invoiceNumber: invoice.invoice_number,
169
+ storageUrl: pdfUrl.indexOf('/api/invoices/') === 0 ? '' : pdfUrl,
170
+ pdfUrl: pdfUrl,
171
+ total: Number(invoice.total) || 0,
172
+ currency: invoice.currency || currency,
173
+ };
174
+ }
175
+
127
176
  async function hydrateOrderWhenSettled(orderId) {
128
177
  var deadline = Date.now() + SETTLE_TIMEOUT_MS;
129
178
  var lastCount = -1;
@@ -264,17 +313,7 @@ module.exports = async function handler(req, res) {
264
313
  if (!reservation.created) {
265
314
  if (Number(held.pdf_size_bytes) > 0) {
266
315
  console.info('[invoice] Order ' + body.orderId + ' already has invoice ' + held.invoice_number + ' — returning it');
267
- var heldPdfUrl = held.pdf_url || ('/api/invoices/' + held.id + '/pdf');
268
- res.status(200).json({
269
- success: true,
270
- alreadyIssued: true,
271
- invoiceId: held.id,
272
- invoiceNumber: held.invoice_number,
273
- storageUrl: heldPdfUrl.indexOf('/api/invoices/') === 0 ? '' : heldPdfUrl,
274
- pdfUrl: heldPdfUrl,
275
- total: Number(held.total) || 0,
276
- currency: held.currency || currency,
277
- });
316
+ res.status(200).json(issuedInvoiceAnswer(held, currency));
278
317
  return;
279
318
  }
280
319
  // Reserved, never finished: another request is rendering it now, or the
@@ -308,7 +347,18 @@ ${emailEnabled
308
347
  console.info('[invoice] PDF generated: ' + pdfBuffer.length + ' bytes for ' + invoiceData.invoiceNumber);
309
348
 
310
349
  invoiceData.pdfUrl = '/api/invoices/' + invoiceData.id + '/pdf';
311
- await dataAccess.storeInvoicePdf(invoiceData.id, pdfBuffer, invoiceData.pdfUrl);
350
+ // The PDF is written only on an invoice that has none, and the invoice's
351
+ // first PDF is what its email is claimed by (see storeInvoicePdf). A
352
+ // regeneration that gave a reserved invoice its PDF while this request
353
+ // rendered it — a retried payment finishing a stale reservation — emailed
354
+ // the buyer itself, so this request answers with that invoice and sends
355
+ // nothing.
356
+ var stored = await dataAccess.storeInvoicePdf(invoiceData.id, pdfBuffer, invoiceData.pdfUrl);
357
+ if (!stored.firstPdf) {
358
+ console.info('[invoice] Invoice ' + invoiceNumber + ' was given its PDF by a regeneration meanwhile — returning it');
359
+ res.status(200).json(issuedInvoiceAnswer((await dataAccess.getInvoiceById(invoiceData.id)) || held, currency));
360
+ return;
361
+ }
312
362
  console.info('[invoice] PDF stored — teleport_invoices.id=' + invoiceData.id + ', number=' + invoiceData.invoiceNumber + ', pdf_size_bytes=' + pdfBuffer.length + ', items=' + items.length + ' (accessible at ' + invoiceData.pdfUrl + ')');
313
363
 
314
364
  var safeFileName = String(invoiceNumber || invoiceData.id).replace(/[^a-zA-Z0-9._-]/g, '_') + '.pdf';
@@ -376,9 +426,11 @@ ${emailEnabled
376
426
  ${emailEnabled
377
427
  ? `
378
428
  if (invoiceData.customerEmail) {
429
+ var emailed = false;
379
430
  try {
380
431
  var emailResult = await emailSender.sendInvoiceEmail(invoiceData, pdfBuffer);
381
- if (emailResult && emailResult.success) {
432
+ emailed = !!(emailResult && emailResult.success);
433
+ if (emailed) {
382
434
  console.info('[invoice] Email delivery OK — to=' + invoiceData.customerEmail + ', messageId=' + (emailResult.messageId || '(empty)'));
383
435
  } else {
384
436
  console.error('[invoice] Email delivery FAILED — to=' + invoiceData.customerEmail + ', error=' + (emailResult && emailResult.error ? emailResult.error : 'unknown'));
@@ -386,6 +438,13 @@ ${emailEnabled
386
438
  } catch (emailErr) {
387
439
  console.error('[invoice] Email delivery threw — to=' + invoiceData.customerEmail + ', error=' + (emailErr && emailErr.message ? emailErr.message : emailErr));
388
440
  }
441
+ if (emailed) {
442
+ try {
443
+ await recordInvoiceEmailSent(invoiceData, caller.admin ? INVOICE_EMAIL_SENDERS.admin : INVOICE_EMAIL_SENDERS.store);
444
+ } catch (recordErr) {
445
+ console.error('[invoice] Invoice ' + invoiceNumber + ' was emailed, but the order history could not record it — ' + (recordErr && recordErr.message));
446
+ }
447
+ }
389
448
  } else {
390
449
  console.info('[invoice] Skipping email delivery — invoiceData.customerEmail is empty. (Check teleport_orders.billing_email for order ' + (body.orderId || '(no orderId)') + ')');
391
450
  }
@@ -440,6 +499,36 @@ ${emailEnabled
440
499
  exports.generateInvoiceGenerateRouteCode = generateInvoiceGenerateRouteCode;
441
500
  /** The roles allowed to rebuild an invoice (the admin panel is the only caller). */
442
501
  const REGENERATE_INVOICE_ROLES = INVOICE_ADMIN_ROLES;
502
+ /** The regenerate route's `emailFirstInvoice`, as emitted source. */
503
+ const generateFirstInvoiceEmailCode = () => `${RECORD_INVOICE_EMAIL_CODE}
504
+
505
+ var REGENERATE_SOURCE_REF = 'api/invoices/[id]/regenerate';
506
+
507
+ // The invoice email the payment would have sent: the same sender, template,
508
+ // attachment and link, in the buyer's language — the one stamped on the order
509
+ // at checkout, else the store's main language, never the language of this
510
+ // request, which is the merchant's. The sender records it in the sent-email
511
+ // ledger; the order's history records it once the provider accepted it. A
512
+ // failure is logged and goes no further: the merchant has the PDF either way.
513
+ async function emailFirstInvoice(invoiceData, pdfBuffer, order) {
514
+ if (!invoiceData.customerEmail) return;
515
+ invoiceData.locale = emailLocale.normalizeEmailLocale(order && order.locale) || emailLocale.DEFAULT_EMAIL_LOCALE;
516
+ try {
517
+ var sent = await emailSender.sendInvoiceEmail(invoiceData, pdfBuffer, REGENERATE_SOURCE_REF);
518
+ if (!sent || !sent.success) {
519
+ throw new Error((sent && sent.error) || 'the email provider did not accept it');
520
+ }
521
+ } catch (sendErr) {
522
+ console.error('[invoice] Regenerate: invoice ' + invoiceData.invoiceNumber + ' could not be emailed to its customer — ' + (sendErr && sendErr.message));
523
+ return;
524
+ }
525
+ try {
526
+ await recordInvoiceEmailSent(invoiceData, INVOICE_EMAIL_SENDERS.admin);
527
+ } catch (recordErr) {
528
+ console.error('[invoice] Regenerate: invoice ' + invoiceData.invoiceNumber + ' was emailed, but the order history could not record it — ' + (recordErr && recordErr.message));
529
+ }
530
+ }
531
+ `;
443
532
  /**
444
533
  * POST /api/invoices/[id]/regenerate — the admin panel's "Regenerate" action.
445
534
  *
@@ -449,23 +538,43 @@ const REGENERATE_INVOICE_ROLES = INVOICE_ADMIN_ROLES;
449
538
  * against it keep pointing at a valid invoice. What a merchant corrected on the
450
539
  * invoice itself (customer details, notes, payment method) wins over the order;
451
540
  * the lines and every figure are recomputed from the order. The old PDF is
452
- * replaced — and its runtime-storage copy deleted — and the customer is never
453
- * emailed.
541
+ * replaced — and its runtime-storage copy deleted.
542
+ *
543
+ * The customer is emailed once: by the regeneration that gives an invoice its
544
+ * FIRST PDF — one whose PDF failed at payment, so the payment's invoice email
545
+ * never went out — and only when the store emails invoices (Invoice Email
546
+ * Delivery). It is the payment's email: the same sender, template, attachment,
547
+ * link and language, recorded in the sent-email ledger and on the order's
548
+ * history. Which write gives the first PDF, the database decides (see
549
+ * `replaceInvoice` and `storeInvoicePdf`), so a second regeneration, a double
550
+ * click, two requests at once or a retried payment finishing the same invoice
551
+ * never send it again; a failed send costs the merchant nothing.
454
552
  *
455
553
  * Unlike `/generate`, which the payment webhook calls server-to-server, this
456
554
  * route is reached from the merchant's browser only, so it checks the session
457
555
  * itself: signed in, with an admin role.
458
556
  */
459
- const generateInvoiceRegenerateRouteCode = () => {
557
+ const generateInvoiceRegenerateRouteCode = (settings) => {
558
+ var _a;
559
+ const emailEnabled = ((_a = settings.emailDelivery) === null || _a === void 0 ? void 0 : _a.enabled) === true;
460
560
  return `/**
461
561
  * POST /api/invoices/[id]/regenerate
462
562
  * Rebuilds one invoice from its order, in place, for the admin panel. Same
463
- * number, id and dates; a freshly rendered PDF replaces the old one; no email.
563
+ * number, id and dates; a freshly rendered PDF replaces the old one.${emailEnabled
564
+ ? `
565
+ * The first PDF an invoice ever gets is emailed to its customer, once.`
566
+ : `
567
+ * No email: this store does not email invoices.`}
464
568
  */
465
569
 
466
570
  var dataAccess = require('../../../../utils/invoices/data-access');
467
571
  var pdfGenerator = require('../../../../utils/invoices/pdf-generator');
468
572
  var invoiceAssembly = require('../../../../utils/invoices/invoice-assembly');
573
+ ${emailEnabled
574
+ ? `var emailSender = require('../../../../utils/invoices/email-sender');
575
+ var sentEmailLog = require('../../../../utils/email/sent-email-log');
576
+ var emailLocale = require('../../../../utils/email/email-locale');`
577
+ : ''}
469
578
 
470
579
  ${(0, session_cookie_resolver_1.generateCommonJsSessionTokenResolverCode)()}
471
580
  ${workflow_auth_generator_1.ROLE_OF_TOKEN_CODE}
@@ -551,7 +660,7 @@ async function findInvoice(invoiceId) {
551
660
  throw err;
552
661
  }
553
662
  }
554
-
663
+ ${emailEnabled ? generateFirstInvoiceEmailCode() : ''}
555
664
  module.exports = async function handler(req, res) {
556
665
  if (req.method !== 'POST') {
557
666
  res.setHeader('Allow', 'POST');
@@ -610,7 +719,12 @@ module.exports = async function handler(req, res) {
610
719
  invoiceData.pdfSizeBytes = pdfBuffer.length;
611
720
  invoiceData.pdfUrl = '/api/invoices/' + invoiceData.id + '/pdf';
612
721
 
613
- await dataAccess.replaceInvoice(invoiceData.id, invoiceData, invoiceData.items);
722
+ ${emailEnabled
723
+ ? ` var replaced = await dataAccess.replaceInvoice(invoiceData.id, invoiceData, invoiceData.items);
724
+ // This regeneration gave the invoice its first PDF, so the payment's
725
+ // invoice email never went out: this one sends it.
726
+ var emailsCustomer = !!(replaced && replaced.firstPdf);`
727
+ : ` await dataAccess.replaceInvoice(invoiceData.id, invoiceData, invoiceData.items);`}
614
728
  console.info('[invoice] Regenerated ' + invoiceData.invoiceNumber + ' (id=' + invoiceData.id + ', items=' + invoiceData.items.length + ', pdf_size_bytes=' + pdfBuffer.length + ')');
615
729
 
616
730
  // The new PDF's public copy. The row already serves the new bytes through
@@ -633,7 +747,15 @@ module.exports = async function handler(req, res) {
633
747
  if (storageKey) {
634
748
  await invoiceAssembly.deleteStoredInvoicePdf(storageKey);
635
749
  }
636
- res.status(500).json({ success: false, error: MESSAGES.orderNotUpdated });
750
+ ${emailEnabled
751
+ ? ` // The invoice has its first PDF all the same — served from the database,
752
+ // its public copy just went — and no later regeneration will send it.
753
+ if (emailsCustomer) {
754
+ await emailFirstInvoice(invoiceData, pdfBuffer, hydrated.order);
755
+ }
756
+ await sentEmailLog.settleSentEmailLog();
757
+ `
758
+ : ''} res.status(500).json({ success: false, error: MESSAGES.orderNotUpdated });
637
759
  return;
638
760
  }
639
761
 
@@ -651,7 +773,16 @@ module.exports = async function handler(req, res) {
651
773
  if (previousStorageKey && previousStorageKey !== storageKey) {
652
774
  await invoiceAssembly.deleteStoredInvoicePdf(previousStorageKey);
653
775
  }
654
-
776
+ ${emailEnabled
777
+ ? `
778
+ if (emailsCustomer) {
779
+ await emailFirstInvoice(invoiceData, pdfBuffer, hydrated.order);
780
+ }
781
+ // The email's ledger row is written in the background — land it before
782
+ // replying, a serverless function may be frozen the instant it responds.
783
+ await sentEmailLog.settleSentEmailLog();
784
+ `
785
+ : ''}
655
786
  res.status(200).json({
656
787
  success: true,
657
788
  invoiceId: invoiceData.id,
@@ -1 +1 @@
1
- {"version":3,"file":"api-routes-code.js","sourceRoot":"","sources":["../../../src/invoice/api-routes-code.ts"],"names":[],"mappings":";;;AACA,wEAAqF;AACrF,wEAA+D;AAE/D;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,CAAC,OAAO,CAAC,CAAA;AAErC;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAG,GAAG,IAAA,kEAAwC,GAAE;EACvE,4CAAkB;;4BAEQ,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiC7D,CAAA;AAEK,MAAM,gCAAgC,GAAG,CAAC,QAA6B,EAAU,EAAE;;IACxF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,IAAI,MAAM,CAAA;IAC/C,MAAM,YAAY,GAAG,QAAQ,CAAC,qBAAqB,KAAK,KAAK,CAAA;IAC7D,MAAM,YAAY,GAAG,CAAA,MAAA,QAAQ,CAAC,aAAa,0CAAE,OAAO,MAAK,IAAI,CAAA;IAE7D,OAAO;;;;;;;;;;;;;;;;EAiBP,YAAY;QACV,CAAC,CAAC;;gEAE0D;QAC5D,CAAC,CAAC,EACN;;uBAEuB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;;;;;EAK3C,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2MnB,YAAY;QACV,CAAC,CAAC;;;;;;;;;;CAUL;QACG,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwEE,YAAY;QACV,CAAC,CAAC;;;;;;;;;;;;;;;CAeL;QACG,CAAC,CAAC;;CAGN;;;;;;;;;;;EAYE,YAAY;QACV,CAAC,CAAC;;;CAGL;QACG,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;EAqBE,YAAY;QACV,CAAC,CAAC;CACL;QACG,CAAC,CAAC,EACN;;;;CAIC,CAAA;AACD,CAAC,CAAA;AAtYY,QAAA,gCAAgC,oCAsY5C;AAED,oFAAoF;AACpF,MAAM,wBAAwB,GAAG,mBAAmB,CAAA;AAEpD;;;;;;;;;;;;;;;GAeG;AACI,MAAM,kCAAkC,GAAG,GAAW,EAAE;IAC7D,OAAO;;;;;;;;;;EAUP,IAAA,kEAAwC,GAAE;EAC1C,4CAAkB;;iCAEa,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoMxE,CAAA;AACD,CAAC,CAAA;AAnNY,QAAA,kCAAkC,sCAmN9C;AAED;;;;;;;;GAQG;AACI,MAAM,2BAA2B,GAAG,GAAW,EAAE;IACtD,OAAO;;;;;;;EAOP,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EpB,CAAA;AACD,CAAC,CAAA;AAtFY,QAAA,2BAA2B,+BAsFvC"}
1
+ {"version":3,"file":"api-routes-code.js","sourceRoot":"","sources":["../../../src/invoice/api-routes-code.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-access-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhF,eAAO,MAAM,sBAAsB,aACvB,mBAAmB,kBACb,cAAc,GAAG,IAAI,oBACnB,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KAC/C,MA2CF,CAAA;AAgqBD,eAAO,MAAM,oBAAoB,YAAa,MAAM,KAAG,MAsItD,CAAA"}
1
+ {"version":3,"file":"data-access-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhF,eAAO,MAAM,sBAAsB,aACvB,mBAAmB,kBACb,cAAc,GAAG,IAAI,oBACnB,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KAC/C,MA8CF,CAAA;AAmxBD,eAAO,MAAM,oBAAoB,YAAa,MAAM,KAAG,MAsItD,CAAA"}
@@ -24,7 +24,7 @@ ${generateGetInvoiceByIdCode(dsType, invoicesTable)}
24
24
 
25
25
  ${generateUpdateInvoiceCode(dsType, invoicesTable)}
26
26
 
27
- ${generateStoreInvoicePdfCode(dsType)}
27
+ ${generateStoreInvoicePdfCode(dsType, invoicesTable)}
28
28
 
29
29
  ${generateGetOrderWithItemsCode(dsType)}
30
30
 
@@ -32,6 +32,8 @@ ${generateReplaceInvoiceCode(dsType, invoicesTable, invoiceItemsTable)}
32
32
 
33
33
  ${generateLinkOrderToInvoiceCode(dsType)}
34
34
 
35
+ ${generateRecordOrderEventCode(dsType)}
36
+
35
37
  module.exports = {
36
38
  getClient: getClient,
37
39
  reserveInvoice: reserveInvoice,
@@ -42,6 +44,7 @@ module.exports = {
42
44
  getOrderWithItems: getOrderWithItems,
43
45
  replaceInvoice: replaceInvoice,
44
46
  linkOrderToInvoice: linkOrderToInvoice,
47
+ recordOrderEvent: recordOrderEvent,
45
48
  };
46
49
  `;
47
50
  };
@@ -338,18 +341,45 @@ ${cutoff}
338
341
  return result.rowCount > 0;
339
342
  }`;
340
343
  }
341
- // Puts the rendered PDF on the reserved row; `pdf_size_bytes` is what marks
342
- // the invoice finished (see `claimStaleInvoice`).
343
- function generateStoreInvoicePdfCode(dsType) {
344
- const pdfData = dsType === 'supabase' ? `pdfBuffer.toString('base64')` : 'pdfBuffer';
345
- return `
344
+ // Puts the rendered PDF on the reserved row — only while the row has none —
345
+ // and resolves to `{ firstPdf }`: whether this write gave the invoice its
346
+ // first PDF. `pdf_size_bytes` marks the invoice finished (see
347
+ // `claimStaleInvoice`), and the invoice's first PDF is what its email is
348
+ // claimed by: `replaceInvoice` writes first under the same condition, so of a
349
+ // retried payment finishing a stale invoice and a regeneration racing it, one
350
+ // writes the PDF and emails the buyer, and the other is told it was not first.
351
+ function generateStoreInvoicePdfCode(dsType, table) {
352
+ if (dsType === 'supabase') {
353
+ return `
346
354
  async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
347
- return updateInvoice(invoiceId, {
348
- pdf_data: ${pdfData},
355
+ var result = await getClient().from('${table}').update({
356
+ pdf_data: pdfBuffer.toString('base64'),
349
357
  pdf_size_bytes: pdfBuffer.length,
350
358
  pdf_content_type: 'application/pdf',
351
359
  pdf_url: pdfUrl,
352
- });
360
+ updated_at: new Date().toISOString(),
361
+ }).eq('id', invoiceId).is('pdf_size_bytes', null).select('id');
362
+ if (result.error) throw new Error(result.error.message);
363
+ return { firstPdf: !!(result.data && result.data.length > 0) };
364
+ }`;
365
+ }
366
+ if (dsType === 'mysql' || dsType === 'mariadb' || dsType === 'tidb') {
367
+ return `
368
+ async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
369
+ var [result] = await getClient().execute(
370
+ 'UPDATE ${table} SET pdf_data = ?, pdf_size_bytes = ?, pdf_content_type = ?, pdf_url = ?, updated_at = ? WHERE id = ? AND pdf_size_bytes IS NULL',
371
+ [pdfBuffer, pdfBuffer.length, 'application/pdf', pdfUrl, new Date().toISOString(), invoiceId]
372
+ );
373
+ return { firstPdf: !!(result && result.affectedRows > 0) };
374
+ }`;
375
+ }
376
+ return `
377
+ async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
378
+ var result = await getClient().query(
379
+ 'UPDATE ${table} SET pdf_data = $1, pdf_size_bytes = $2, pdf_content_type = $3, pdf_url = $4, updated_at = $5 WHERE id = $6 AND pdf_size_bytes IS NULL',
380
+ [pdfBuffer, pdfBuffer.length, 'application/pdf', pdfUrl, new Date().toISOString(), invoiceId]
381
+ );
382
+ return { firstPdf: result.rowCount > 0 };
353
383
  }`;
354
384
  }
355
385
  function generateInsertInvoiceItemsCode(dsType, table) {
@@ -534,6 +564,15 @@ async function getOrderWithItems(orderId) {
534
564
  // points at it (the order, the sent-email ledger) stays valid. Postgres and
535
565
  // MySQL do it in one transaction, and Supabase undoes its steps, so a failure
536
566
  // leaves the old invoice whole.
567
+ //
568
+ // Resolves to `{ firstPdf }`: whether this write gave the invoice its first
569
+ // PDF — one whose PDF never came at payment, so its buyer was never emailed
570
+ // it. The database decides: the row is first written only where it has no PDF
571
+ // (the `pdf_size_bytes IS NULL` that `claimStaleInvoice` reads as
572
+ // "unfinished"), and of two regenerations racing for the same invoice the
573
+ // second waits for the first's row lock, then finds the PDF and matches
574
+ // nothing. `storeInvoicePdf` writes the payment's PDF under the same
575
+ // condition, so exactly one write is ever told `firstPdf: true`.
537
576
  function generateReplaceInvoiceCode(dsType, table, itemsTable) {
538
577
  if (dsType === 'supabase') {
539
578
  return `
@@ -553,18 +592,23 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
553
592
  var insertedIds = (inserted || []).map(function (row) { return row.id; });
554
593
  var written = null;
555
594
  try {
556
- var record = await writeInvoiceRecord(mapInvoiceReplacementToRecord(invoiceData), async function (fields) {
557
- var result = await client.from('${table}').update(fields).eq('id', invoiceId).select('id');
558
- if (result.error) throw new Error(result.error.message);
559
- if (!result.data || result.data.length === 0) throw new Error('Invoice ' + invoiceId + ' no longer exists');
595
+ var outcome = await writeInvoiceRecord(mapInvoiceReplacementToRecord(invoiceData), async function (fields) {
596
+ var first = await client.from('${table}').update(fields).eq('id', invoiceId).is('pdf_size_bytes', null).select('id');
597
+ if (first.error) throw new Error(first.error.message);
598
+ var firstPdf = !!(first.data && first.data.length > 0);
599
+ if (!firstPdf) {
600
+ var result = await client.from('${table}').update(fields).eq('id', invoiceId).select('id');
601
+ if (result.error) throw new Error(result.error.message);
602
+ if (!result.data || result.data.length === 0) throw new Error('Invoice ' + invoiceId + ' no longer exists');
603
+ }
560
604
  written = fields;
561
- return fields;
605
+ return { firstPdf: firstPdf };
562
606
  });
563
607
  if (previousIds.length > 0) {
564
608
  var removed = await client.from('${itemsTable}').delete().in('id', previousIds);
565
609
  if (removed.error) throw new Error(removed.error.message);
566
610
  }
567
- return record;
611
+ return outcome;
568
612
  } catch (err) {
569
613
  if (written) {
570
614
  var restored = {};
@@ -592,12 +636,17 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
592
636
  var setClauses = columns.map(function(k) { return quoteIdent(k) + ' = ?'; }).join(', ');
593
637
  var values = columns.map(function(k) { return fields[k]; });
594
638
  values.push(invoiceId);
595
- var [updated] = await conn.execute('UPDATE ${table} SET ' + setClauses + ' WHERE id = ?', values);
596
- if (!updated || !updated.affectedRows) throw new Error('Invoice ' + invoiceId + ' no longer exists');
639
+ var update = 'UPDATE ${table} SET ' + setClauses + ' WHERE id = ?';
640
+ var [first] = await conn.execute(update + ' AND pdf_size_bytes IS NULL', values);
641
+ var firstPdf = !!(first && first.affectedRows > 0);
642
+ if (!firstPdf) {
643
+ var [updated] = await conn.execute(update, values);
644
+ if (!updated || !updated.affectedRows) throw new Error('Invoice ' + invoiceId + ' no longer exists');
645
+ }
597
646
  await conn.execute('DELETE FROM ${itemsTable} WHERE invoice_id = ?', [invoiceId]);
598
647
  await insertInvoiceItemRows(conn, invoiceId, items);
599
648
  await conn.commit();
600
- return fields;
649
+ return { firstPdf: firstPdf };
601
650
  } catch (err) {
602
651
  try { await conn.rollback(); } catch (_rollbackErr) {}
603
652
  throw err;
@@ -620,12 +669,16 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
620
669
  values.push(invoiceId);
621
670
  // The UPDATE takes the row lock first, so two regenerations of the same
622
671
  // invoice run one after the other instead of interleaving their lines.
623
- var updated = await client.query('UPDATE ${table} SET ' + setClauses + ' WHERE id = $' + values.length, values);
624
- if (!updated.rowCount) throw new Error('Invoice ' + invoiceId + ' no longer exists');
672
+ var update = 'UPDATE ${table} SET ' + setClauses + ' WHERE id = $' + values.length;
673
+ var firstPdf = (await client.query(update + ' AND pdf_size_bytes IS NULL', values)).rowCount > 0;
674
+ if (!firstPdf) {
675
+ var updated = await client.query(update, values);
676
+ if (!updated.rowCount) throw new Error('Invoice ' + invoiceId + ' no longer exists');
677
+ }
625
678
  await client.query('DELETE FROM ${itemsTable} WHERE invoice_id = $1', [invoiceId]);
626
679
  await insertInvoiceItemRows(client, invoiceId, items);
627
680
  await client.query('COMMIT');
628
- return fields;
681
+ return { firstPdf: firstPdf };
629
682
  } catch (err) {
630
683
  try { await client.query('ROLLBACK'); } catch (_rollbackErr) {}
631
684
  throw err;
@@ -682,6 +735,65 @@ async function linkOrderToInvoice(orderId, invoiceId, invoiceNumber, pdfUrl) {
682
735
  return result.rowCount > 0;
683
736
  }`;
684
737
  }
738
+ // One line of an order's history: a row of the activity log the editor
739
+ // provisions (`teleport_events`) and both order timelines read. Written like
740
+ // every line the store's workflows write — teleport-gui's
741
+ // `constants/order-event-types.ts` owns the vocabulary — so a replay collides
742
+ // on the UNIQUE `dedupe_key` and adds nothing. `event` is
743
+ // `{ type, dedupeKey, orderId, payload, actor, actorType }`.
744
+ function generateRecordOrderEventCode(dsType) {
745
+ const row = `
746
+ var ORDER_EVENTS_TABLE = 'teleport_events';
747
+ var ORDER_EVENT_DEDUPE_KEY_MAX_LENGTH = 255;
748
+
749
+ function orderEventRow(event) {
750
+ return {
751
+ id: require('crypto').randomUUID(),
752
+ event_type: event.type,
753
+ dedupe_key: String(event.dedupeKey).slice(0, ORDER_EVENT_DEDUPE_KEY_MAX_LENGTH),
754
+ order_id: event.orderId || null,
755
+ payload: JSON.stringify(event.payload || {}),
756
+ actor: event.actor || '',
757
+ actor_type: event.actorType,
758
+ // Logged; a dispatcher claims the rows it delivers itself.
759
+ status: 'recorded',
760
+ };
761
+ }`;
762
+ if (dsType === 'supabase') {
763
+ return `${row}
764
+
765
+ async function recordOrderEvent(event) {
766
+ var result = await getClient()
767
+ .from(ORDER_EVENTS_TABLE)
768
+ .upsert(orderEventRow(event), { onConflict: 'dedupe_key', ignoreDuplicates: true });
769
+ if (result.error) throw new Error(result.error.message);
770
+ }`;
771
+ }
772
+ if (dsType === 'mysql' || dsType === 'mariadb' || dsType === 'tidb') {
773
+ return `${row}
774
+
775
+ async function recordOrderEvent(event) {
776
+ var record = orderEventRow(event);
777
+ var columns = Object.keys(record);
778
+ var placeholders = columns.map(function() { return '?'; }).join(', ');
779
+ await getClient().execute(
780
+ 'INSERT INTO ' + ORDER_EVENTS_TABLE + ' (' + columns.join(', ') + ') VALUES (' + placeholders + ') ON DUPLICATE KEY UPDATE dedupe_key = dedupe_key',
781
+ columns.map(function(k) { return record[k]; })
782
+ );
783
+ }`;
784
+ }
785
+ return `${row}
786
+
787
+ async function recordOrderEvent(event) {
788
+ var record = orderEventRow(event);
789
+ var columns = Object.keys(record);
790
+ var placeholders = columns.map(function(_, i) { return '$' + (i + 1); }).join(', ');
791
+ await getClient().query(
792
+ 'INSERT INTO ' + ORDER_EVENTS_TABLE + ' (' + columns.join(', ') + ') VALUES (' + placeholders + ') ON CONFLICT (dedupe_key) DO NOTHING',
793
+ columns.map(function(k) { return record[k]; })
794
+ );
795
+ }`;
796
+ }
685
797
  const getRecordMappingCode = (dsType) => `
686
798
  function mapInvoiceToRecord(data) {
687
799
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"data-access-code.js","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-access-code.js","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"email-sender-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/email-sender-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAErE,eAAO,MAAM,uBAAuB,kBAAmB,wBAAwB,KAAG,MAqGjF,CAAA;AAqND,eAAO,MAAM,4BAA4B,aAAc,MAAM,GAAG,IAAI,KAAG,OAAO,MAAM,EAAE,MAAM,CAkB3F,CAAA"}
1
+ {"version":3,"file":"email-sender-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/email-sender-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAGrE,eAAO,MAAM,uBAAuB,kBAAmB,wBAAwB,KAAG,MA2GjF,CAAA;AAoMD,eAAO,MAAM,4BAA4B,aAAc,MAAM,GAAG,IAAI,KAAG,OAAO,MAAM,EAAE,MAAM,CAkB3F,CAAA"}