@teleporthq/teleport-plugin-next-workflows 0.43.75 → 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.
- package/__tests__/_helpers/fake-store-database.ts +428 -0
- package/__tests__/_helpers/invoice-store.ts +382 -0
- package/__tests__/booking-calendar-feed-route.test.ts +494 -0
- package/__tests__/custom-node-result-taken-branch.test.ts +107 -0
- package/__tests__/data-api-date-parser.test.ts +45 -0
- package/__tests__/email-locale-senders.test.ts +3 -1
- package/__tests__/email-sender-name.test.ts +513 -0
- package/__tests__/graph-utils-topological-order.test.ts +155 -1
- package/__tests__/invoice-billing-details.test.ts +384 -0
- package/__tests__/invoice-data-access-replace.test.ts +236 -2
- package/__tests__/invoice-order-items-settle.test.ts +1 -1
- package/__tests__/invoice-payment-email.test.ts +191 -0
- package/__tests__/invoice-regenerate-email.test.ts +288 -0
- package/__tests__/invoice-regenerate-route.test.ts +9 -7
- package/__tests__/invoice-reservation.test.ts +1 -1
- package/__tests__/invoice-tender.test.ts +1 -1
- package/__tests__/middleware-admin-panel-roles.test.ts +127 -0
- package/__tests__/page-arrival-remount.test.ts +247 -0
- package/__tests__/payment-drivers-module.test.ts +19 -0
- package/__tests__/raw-query-error-code.test.ts +47 -0
- package/__tests__/runtime-template-token-resolution.test.ts +16 -0
- package/__tests__/segment-reply-changed-keys.test.ts +31 -0
- package/__tests__/segment-route-skipped-branch.test.ts +101 -0
- package/__tests__/segment-splitter-checkout-order.test.ts +306 -0
- package/__tests__/streaming-on-end-env-filter.test.ts +18 -18
- package/__tests__/streaming-on-end-order.test.ts +387 -0
- package/dist/cjs/account-delete-route-generator.d.ts +1 -0
- package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
- package/dist/cjs/account-delete-route-generator.js +2 -1
- package/dist/cjs/account-delete-route-generator.js.map +1 -1
- package/dist/cjs/api-route-generator.d.ts.map +1 -1
- package/dist/cjs/api-route-generator.js +23 -13
- package/dist/cjs/api-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts +1 -0
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +77 -28
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/booking-calendar-feed-route-generator.d.ts +28 -0
- package/dist/cjs/booking-calendar-feed-route-generator.d.ts.map +1 -0
- package/dist/cjs/booking-calendar-feed-route-generator.js +296 -0
- package/dist/cjs/booking-calendar-feed-route-generator.js.map +1 -0
- package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
- package/dist/cjs/data-api-route-generator.js +6 -1
- package/dist/cjs/data-api-route-generator.js.map +1 -1
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +39 -28
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/graph-utils.d.ts +31 -1
- package/dist/cjs/graph-utils.d.ts.map +1 -1
- package/dist/cjs/graph-utils.js +112 -10
- package/dist/cjs/graph-utils.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/invoice/api-routes-code.d.ts +12 -3
- package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/cjs/invoice/api-routes-code.js +152 -21
- package/dist/cjs/invoice/api-routes-code.js.map +1 -1
- package/dist/cjs/invoice/data-access-code.d.ts.map +1 -1
- package/dist/cjs/invoice/data-access-code.js +133 -21
- package/dist/cjs/invoice/data-access-code.js.map +1 -1
- package/dist/cjs/invoice/email-sender-code.d.ts.map +1 -1
- package/dist/cjs/invoice/email-sender-code.js +15 -25
- package/dist/cjs/invoice/email-sender-code.js.map +1 -1
- package/dist/cjs/invoice/index.js +1 -1
- package/dist/cjs/invoice/index.js.map +1 -1
- package/dist/cjs/invoice/invoice-assembly-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-assembly-code.js +50 -6
- package/dist/cjs/invoice/invoice-assembly-code.js.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.js +13 -2
- package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
- package/dist/cjs/nodes/data/data-raw-query.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-raw-query.js +11 -1
- package/dist/cjs/nodes/data/data-raw-query.js.map +1 -1
- package/dist/cjs/nodes/email/email-mailgun.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-mailgun.js +4 -2
- package/dist/cjs/nodes/email/email-mailgun.js.map +1 -1
- package/dist/cjs/nodes/email/email-postmark.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-postmark.js +5 -2
- package/dist/cjs/nodes/email/email-postmark.js.map +1 -1
- package/dist/cjs/nodes/email/email-resend.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-resend.js +5 -2
- package/dist/cjs/nodes/email/email-resend.js.map +1 -1
- package/dist/cjs/nodes/email/email-sendgrid.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-sendgrid.js +8 -2
- package/dist/cjs/nodes/email/email-sendgrid.js.map +1 -1
- package/dist/cjs/nodes/general/general-custom-js.d.ts.map +1 -1
- package/dist/cjs/nodes/general/general-custom-js.js +11 -0
- package/dist/cjs/nodes/general/general-custom-js.js.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-remove.d.ts.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-remove.js +2 -0
- package/dist/cjs/nodes/storage/storage-local-remove.js.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-set.d.ts.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-set.js +4 -0
- package/dist/cjs/nodes/storage/storage-local-set.js.map +1 -1
- package/dist/cjs/page-arrival.d.ts +10 -0
- package/dist/cjs/page-arrival.d.ts.map +1 -0
- package/dist/cjs/page-arrival.js +86 -0
- package/dist/cjs/page-arrival.js.map +1 -0
- package/dist/cjs/payments/index.d.ts +10 -4
- package/dist/cjs/payments/index.d.ts.map +1 -1
- package/dist/cjs/payments/index.js +18 -7
- package/dist/cjs/payments/index.js.map +1 -1
- package/dist/cjs/segment-splitter.d.ts.map +1 -1
- package/dist/cjs/segment-splitter.js +65 -27
- package/dist/cjs/segment-splitter.js.map +1 -1
- package/dist/cjs/transactional-email-code.d.ts.map +1 -1
- package/dist/cjs/transactional-email-code.js +32 -18
- package/dist/cjs/transactional-email-code.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/workflow-component-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-component-plugin.js +35 -149
- package/dist/cjs/workflow-component-plugin.js.map +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +16 -4
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/cjs/workflow-scope.d.ts +19 -0
- package/dist/cjs/workflow-scope.d.ts.map +1 -0
- package/dist/cjs/workflow-scope.js +147 -0
- package/dist/cjs/workflow-scope.js.map +1 -0
- package/dist/esm/account-delete-route-generator.d.ts +1 -0
- package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
- package/dist/esm/account-delete-route-generator.js +2 -1
- package/dist/esm/account-delete-route-generator.js.map +1 -1
- package/dist/esm/api-route-generator.d.ts.map +1 -1
- package/dist/esm/api-route-generator.js +23 -13
- package/dist/esm/api-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts +1 -0
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +77 -28
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/booking-calendar-feed-route-generator.d.ts +28 -0
- package/dist/esm/booking-calendar-feed-route-generator.d.ts.map +1 -0
- package/dist/esm/booking-calendar-feed-route-generator.js +291 -0
- package/dist/esm/booking-calendar-feed-route-generator.js.map +1 -0
- package/dist/esm/data-api-route-generator.d.ts.map +1 -1
- package/dist/esm/data-api-route-generator.js +6 -1
- package/dist/esm/data-api-route-generator.js.map +1 -1
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +39 -28
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/graph-utils.d.ts +31 -1
- package/dist/esm/graph-utils.d.ts.map +1 -1
- package/dist/esm/graph-utils.js +109 -9
- package/dist/esm/graph-utils.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/invoice/api-routes-code.d.ts +12 -3
- package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/esm/invoice/api-routes-code.js +152 -21
- package/dist/esm/invoice/api-routes-code.js.map +1 -1
- package/dist/esm/invoice/data-access-code.d.ts.map +1 -1
- package/dist/esm/invoice/data-access-code.js +133 -21
- package/dist/esm/invoice/data-access-code.js.map +1 -1
- package/dist/esm/invoice/email-sender-code.d.ts.map +1 -1
- package/dist/esm/invoice/email-sender-code.js +15 -25
- package/dist/esm/invoice/email-sender-code.js.map +1 -1
- package/dist/esm/invoice/index.js +1 -1
- package/dist/esm/invoice/index.js.map +1 -1
- package/dist/esm/invoice/invoice-assembly-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-assembly-code.js +50 -6
- package/dist/esm/invoice/invoice-assembly-code.js.map +1 -1
- package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-html-code.js +13 -2
- package/dist/esm/invoice/invoice-html-code.js.map +1 -1
- package/dist/esm/nodes/data/data-raw-query.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-raw-query.js +11 -1
- package/dist/esm/nodes/data/data-raw-query.js.map +1 -1
- package/dist/esm/nodes/email/email-mailgun.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-mailgun.js +4 -2
- package/dist/esm/nodes/email/email-mailgun.js.map +1 -1
- package/dist/esm/nodes/email/email-postmark.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-postmark.js +5 -2
- package/dist/esm/nodes/email/email-postmark.js.map +1 -1
- package/dist/esm/nodes/email/email-resend.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-resend.js +5 -2
- package/dist/esm/nodes/email/email-resend.js.map +1 -1
- package/dist/esm/nodes/email/email-sendgrid.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-sendgrid.js +8 -2
- package/dist/esm/nodes/email/email-sendgrid.js.map +1 -1
- package/dist/esm/nodes/general/general-custom-js.d.ts.map +1 -1
- package/dist/esm/nodes/general/general-custom-js.js +11 -0
- package/dist/esm/nodes/general/general-custom-js.js.map +1 -1
- package/dist/esm/nodes/storage/storage-local-remove.d.ts.map +1 -1
- package/dist/esm/nodes/storage/storage-local-remove.js +2 -0
- package/dist/esm/nodes/storage/storage-local-remove.js.map +1 -1
- package/dist/esm/nodes/storage/storage-local-set.d.ts.map +1 -1
- package/dist/esm/nodes/storage/storage-local-set.js +4 -0
- package/dist/esm/nodes/storage/storage-local-set.js.map +1 -1
- package/dist/esm/page-arrival.d.ts +10 -0
- package/dist/esm/page-arrival.d.ts.map +1 -0
- package/dist/esm/page-arrival.js +81 -0
- package/dist/esm/page-arrival.js.map +1 -0
- package/dist/esm/payments/index.d.ts +10 -4
- package/dist/esm/payments/index.d.ts.map +1 -1
- package/dist/esm/payments/index.js +16 -6
- package/dist/esm/payments/index.js.map +1 -1
- package/dist/esm/segment-splitter.d.ts.map +1 -1
- package/dist/esm/segment-splitter.js +66 -28
- package/dist/esm/segment-splitter.js.map +1 -1
- package/dist/esm/transactional-email-code.d.ts.map +1 -1
- package/dist/esm/transactional-email-code.js +32 -18
- package/dist/esm/transactional-email-code.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/workflow-component-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-component-plugin.js +32 -146
- package/dist/esm/workflow-component-plugin.js.map +1 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +16 -4
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/dist/esm/workflow-scope.d.ts +19 -0
- package/dist/esm/workflow-scope.d.ts.map +1 -0
- package/dist/esm/workflow-scope.js +142 -0
- package/dist/esm/workflow-scope.js.map +1 -0
- package/package.json +4 -4
- package/src/account-delete-route-generator.ts +3 -1
- package/src/api-route-generator.ts +23 -13
- package/src/auth-generator.ts +83 -26
- package/src/booking-calendar-feed-route-generator.ts +293 -0
- package/src/data-api-route-generator.ts +6 -1
- package/src/executor-generator.ts +39 -28
- package/src/graph-utils.ts +143 -11
- package/src/index.ts +1 -0
- package/src/invoice/api-routes-code.ts +166 -21
- package/src/invoice/data-access-code.ts +139 -21
- package/src/invoice/email-sender-code.ts +15 -25
- package/src/invoice/index.ts +1 -1
- package/src/invoice/invoice-assembly-code.ts +50 -6
- package/src/invoice/invoice-html-code.ts +13 -2
- package/src/nodes/data/data-raw-query.ts +11 -1
- package/src/nodes/email/email-mailgun.ts +11 -2
- package/src/nodes/email/email-postmark.ts +12 -2
- package/src/nodes/email/email-resend.ts +12 -2
- package/src/nodes/email/email-sendgrid.ts +15 -2
- package/src/nodes/general/general-custom-js.ts +10 -0
- package/src/nodes/storage/storage-local-remove.ts +4 -0
- package/src/nodes/storage/storage-local-set.ts +6 -0
- package/src/page-arrival.ts +115 -0
- package/src/payments/index.ts +18 -5
- package/src/segment-splitter.ts +90 -36
- package/src/transactional-email-code.ts +32 -21
- package/src/workflow-component-plugin.ts +43 -188
- package/src/workflow-project-plugin.ts +17 -4
- package/src/workflow-scope.ts +184 -0
|
@@ -27,7 +27,7 @@ ${generateGetInvoiceByIdCode(dsType, invoicesTable)}
|
|
|
27
27
|
|
|
28
28
|
${generateUpdateInvoiceCode(dsType, invoicesTable)}
|
|
29
29
|
|
|
30
|
-
${generateStoreInvoicePdfCode(dsType)}
|
|
30
|
+
${generateStoreInvoicePdfCode(dsType, invoicesTable)}
|
|
31
31
|
|
|
32
32
|
${generateGetOrderWithItemsCode(dsType)}
|
|
33
33
|
|
|
@@ -35,6 +35,8 @@ ${generateReplaceInvoiceCode(dsType, invoicesTable, invoiceItemsTable)}
|
|
|
35
35
|
|
|
36
36
|
${generateLinkOrderToInvoiceCode(dsType)}
|
|
37
37
|
|
|
38
|
+
${generateRecordOrderEventCode(dsType)}
|
|
39
|
+
|
|
38
40
|
module.exports = {
|
|
39
41
|
getClient: getClient,
|
|
40
42
|
reserveInvoice: reserveInvoice,
|
|
@@ -45,6 +47,7 @@ module.exports = {
|
|
|
45
47
|
getOrderWithItems: getOrderWithItems,
|
|
46
48
|
replaceInvoice: replaceInvoice,
|
|
47
49
|
linkOrderToInvoice: linkOrderToInvoice,
|
|
50
|
+
recordOrderEvent: recordOrderEvent,
|
|
48
51
|
};
|
|
49
52
|
`
|
|
50
53
|
}
|
|
@@ -356,18 +359,47 @@ ${cutoff}
|
|
|
356
359
|
}`
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
// Puts the rendered PDF on the reserved row
|
|
360
|
-
// the invoice
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
362
|
+
// Puts the rendered PDF on the reserved row — only while the row has none —
|
|
363
|
+
// and resolves to `{ firstPdf }`: whether this write gave the invoice its
|
|
364
|
+
// first PDF. `pdf_size_bytes` marks the invoice finished (see
|
|
365
|
+
// `claimStaleInvoice`), and the invoice's first PDF is what its email is
|
|
366
|
+
// claimed by: `replaceInvoice` writes first under the same condition, so of a
|
|
367
|
+
// retried payment finishing a stale invoice and a regeneration racing it, one
|
|
368
|
+
// writes the PDF and emails the buyer, and the other is told it was not first.
|
|
369
|
+
function generateStoreInvoicePdfCode(dsType: string, table: string): string {
|
|
370
|
+
if (dsType === 'supabase') {
|
|
371
|
+
return `
|
|
364
372
|
async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
|
|
365
|
-
|
|
366
|
-
pdf_data:
|
|
373
|
+
var result = await getClient().from('${table}').update({
|
|
374
|
+
pdf_data: pdfBuffer.toString('base64'),
|
|
367
375
|
pdf_size_bytes: pdfBuffer.length,
|
|
368
376
|
pdf_content_type: 'application/pdf',
|
|
369
377
|
pdf_url: pdfUrl,
|
|
370
|
-
|
|
378
|
+
updated_at: new Date().toISOString(),
|
|
379
|
+
}).eq('id', invoiceId).is('pdf_size_bytes', null).select('id');
|
|
380
|
+
if (result.error) throw new Error(result.error.message);
|
|
381
|
+
return { firstPdf: !!(result.data && result.data.length > 0) };
|
|
382
|
+
}`
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (dsType === 'mysql' || dsType === 'mariadb' || dsType === 'tidb') {
|
|
386
|
+
return `
|
|
387
|
+
async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
|
|
388
|
+
var [result] = await getClient().execute(
|
|
389
|
+
'UPDATE ${table} SET pdf_data = ?, pdf_size_bytes = ?, pdf_content_type = ?, pdf_url = ?, updated_at = ? WHERE id = ? AND pdf_size_bytes IS NULL',
|
|
390
|
+
[pdfBuffer, pdfBuffer.length, 'application/pdf', pdfUrl, new Date().toISOString(), invoiceId]
|
|
391
|
+
);
|
|
392
|
+
return { firstPdf: !!(result && result.affectedRows > 0) };
|
|
393
|
+
}`
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return `
|
|
397
|
+
async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
|
|
398
|
+
var result = await getClient().query(
|
|
399
|
+
'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',
|
|
400
|
+
[pdfBuffer, pdfBuffer.length, 'application/pdf', pdfUrl, new Date().toISOString(), invoiceId]
|
|
401
|
+
);
|
|
402
|
+
return { firstPdf: result.rowCount > 0 };
|
|
371
403
|
}`
|
|
372
404
|
}
|
|
373
405
|
|
|
@@ -565,6 +597,15 @@ async function getOrderWithItems(orderId) {
|
|
|
565
597
|
// points at it (the order, the sent-email ledger) stays valid. Postgres and
|
|
566
598
|
// MySQL do it in one transaction, and Supabase undoes its steps, so a failure
|
|
567
599
|
// leaves the old invoice whole.
|
|
600
|
+
//
|
|
601
|
+
// Resolves to `{ firstPdf }`: whether this write gave the invoice its first
|
|
602
|
+
// PDF — one whose PDF never came at payment, so its buyer was never emailed
|
|
603
|
+
// it. The database decides: the row is first written only where it has no PDF
|
|
604
|
+
// (the `pdf_size_bytes IS NULL` that `claimStaleInvoice` reads as
|
|
605
|
+
// "unfinished"), and of two regenerations racing for the same invoice the
|
|
606
|
+
// second waits for the first's row lock, then finds the PDF and matches
|
|
607
|
+
// nothing. `storeInvoicePdf` writes the payment's PDF under the same
|
|
608
|
+
// condition, so exactly one write is ever told `firstPdf: true`.
|
|
568
609
|
function generateReplaceInvoiceCode(dsType: string, table: string, itemsTable: string): string {
|
|
569
610
|
if (dsType === 'supabase') {
|
|
570
611
|
return `
|
|
@@ -584,18 +625,23 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
|
|
|
584
625
|
var insertedIds = (inserted || []).map(function (row) { return row.id; });
|
|
585
626
|
var written = null;
|
|
586
627
|
try {
|
|
587
|
-
var
|
|
588
|
-
var
|
|
589
|
-
if (
|
|
590
|
-
|
|
628
|
+
var outcome = await writeInvoiceRecord(mapInvoiceReplacementToRecord(invoiceData), async function (fields) {
|
|
629
|
+
var first = await client.from('${table}').update(fields).eq('id', invoiceId).is('pdf_size_bytes', null).select('id');
|
|
630
|
+
if (first.error) throw new Error(first.error.message);
|
|
631
|
+
var firstPdf = !!(first.data && first.data.length > 0);
|
|
632
|
+
if (!firstPdf) {
|
|
633
|
+
var result = await client.from('${table}').update(fields).eq('id', invoiceId).select('id');
|
|
634
|
+
if (result.error) throw new Error(result.error.message);
|
|
635
|
+
if (!result.data || result.data.length === 0) throw new Error('Invoice ' + invoiceId + ' no longer exists');
|
|
636
|
+
}
|
|
591
637
|
written = fields;
|
|
592
|
-
return
|
|
638
|
+
return { firstPdf: firstPdf };
|
|
593
639
|
});
|
|
594
640
|
if (previousIds.length > 0) {
|
|
595
641
|
var removed = await client.from('${itemsTable}').delete().in('id', previousIds);
|
|
596
642
|
if (removed.error) throw new Error(removed.error.message);
|
|
597
643
|
}
|
|
598
|
-
return
|
|
644
|
+
return outcome;
|
|
599
645
|
} catch (err) {
|
|
600
646
|
if (written) {
|
|
601
647
|
var restored = {};
|
|
@@ -624,12 +670,17 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
|
|
|
624
670
|
var setClauses = columns.map(function(k) { return quoteIdent(k) + ' = ?'; }).join(', ');
|
|
625
671
|
var values = columns.map(function(k) { return fields[k]; });
|
|
626
672
|
values.push(invoiceId);
|
|
627
|
-
var
|
|
628
|
-
|
|
673
|
+
var update = 'UPDATE ${table} SET ' + setClauses + ' WHERE id = ?';
|
|
674
|
+
var [first] = await conn.execute(update + ' AND pdf_size_bytes IS NULL', values);
|
|
675
|
+
var firstPdf = !!(first && first.affectedRows > 0);
|
|
676
|
+
if (!firstPdf) {
|
|
677
|
+
var [updated] = await conn.execute(update, values);
|
|
678
|
+
if (!updated || !updated.affectedRows) throw new Error('Invoice ' + invoiceId + ' no longer exists');
|
|
679
|
+
}
|
|
629
680
|
await conn.execute('DELETE FROM ${itemsTable} WHERE invoice_id = ?', [invoiceId]);
|
|
630
681
|
await insertInvoiceItemRows(conn, invoiceId, items);
|
|
631
682
|
await conn.commit();
|
|
632
|
-
return
|
|
683
|
+
return { firstPdf: firstPdf };
|
|
633
684
|
} catch (err) {
|
|
634
685
|
try { await conn.rollback(); } catch (_rollbackErr) {}
|
|
635
686
|
throw err;
|
|
@@ -653,12 +704,16 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
|
|
|
653
704
|
values.push(invoiceId);
|
|
654
705
|
// The UPDATE takes the row lock first, so two regenerations of the same
|
|
655
706
|
// invoice run one after the other instead of interleaving their lines.
|
|
656
|
-
var
|
|
657
|
-
|
|
707
|
+
var update = 'UPDATE ${table} SET ' + setClauses + ' WHERE id = $' + values.length;
|
|
708
|
+
var firstPdf = (await client.query(update + ' AND pdf_size_bytes IS NULL', values)).rowCount > 0;
|
|
709
|
+
if (!firstPdf) {
|
|
710
|
+
var updated = await client.query(update, values);
|
|
711
|
+
if (!updated.rowCount) throw new Error('Invoice ' + invoiceId + ' no longer exists');
|
|
712
|
+
}
|
|
658
713
|
await client.query('DELETE FROM ${itemsTable} WHERE invoice_id = $1', [invoiceId]);
|
|
659
714
|
await insertInvoiceItemRows(client, invoiceId, items);
|
|
660
715
|
await client.query('COMMIT');
|
|
661
|
-
return
|
|
716
|
+
return { firstPdf: firstPdf };
|
|
662
717
|
} catch (err) {
|
|
663
718
|
try { await client.query('ROLLBACK'); } catch (_rollbackErr) {}
|
|
664
719
|
throw err;
|
|
@@ -719,6 +774,69 @@ async function linkOrderToInvoice(orderId, invoiceId, invoiceNumber, pdfUrl) {
|
|
|
719
774
|
}`
|
|
720
775
|
}
|
|
721
776
|
|
|
777
|
+
// One line of an order's history: a row of the activity log the editor
|
|
778
|
+
// provisions (`teleport_events`) and both order timelines read. Written like
|
|
779
|
+
// every line the store's workflows write — teleport-gui's
|
|
780
|
+
// `constants/order-event-types.ts` owns the vocabulary — so a replay collides
|
|
781
|
+
// on the UNIQUE `dedupe_key` and adds nothing. `event` is
|
|
782
|
+
// `{ type, dedupeKey, orderId, payload, actor, actorType }`.
|
|
783
|
+
function generateRecordOrderEventCode(dsType: string): string {
|
|
784
|
+
const row = `
|
|
785
|
+
var ORDER_EVENTS_TABLE = 'teleport_events';
|
|
786
|
+
var ORDER_EVENT_DEDUPE_KEY_MAX_LENGTH = 255;
|
|
787
|
+
|
|
788
|
+
function orderEventRow(event) {
|
|
789
|
+
return {
|
|
790
|
+
id: require('crypto').randomUUID(),
|
|
791
|
+
event_type: event.type,
|
|
792
|
+
dedupe_key: String(event.dedupeKey).slice(0, ORDER_EVENT_DEDUPE_KEY_MAX_LENGTH),
|
|
793
|
+
order_id: event.orderId || null,
|
|
794
|
+
payload: JSON.stringify(event.payload || {}),
|
|
795
|
+
actor: event.actor || '',
|
|
796
|
+
actor_type: event.actorType,
|
|
797
|
+
// Logged; a dispatcher claims the rows it delivers itself.
|
|
798
|
+
status: 'recorded',
|
|
799
|
+
};
|
|
800
|
+
}`
|
|
801
|
+
|
|
802
|
+
if (dsType === 'supabase') {
|
|
803
|
+
return `${row}
|
|
804
|
+
|
|
805
|
+
async function recordOrderEvent(event) {
|
|
806
|
+
var result = await getClient()
|
|
807
|
+
.from(ORDER_EVENTS_TABLE)
|
|
808
|
+
.upsert(orderEventRow(event), { onConflict: 'dedupe_key', ignoreDuplicates: true });
|
|
809
|
+
if (result.error) throw new Error(result.error.message);
|
|
810
|
+
}`
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (dsType === 'mysql' || dsType === 'mariadb' || dsType === 'tidb') {
|
|
814
|
+
return `${row}
|
|
815
|
+
|
|
816
|
+
async function recordOrderEvent(event) {
|
|
817
|
+
var record = orderEventRow(event);
|
|
818
|
+
var columns = Object.keys(record);
|
|
819
|
+
var placeholders = columns.map(function() { return '?'; }).join(', ');
|
|
820
|
+
await getClient().execute(
|
|
821
|
+
'INSERT INTO ' + ORDER_EVENTS_TABLE + ' (' + columns.join(', ') + ') VALUES (' + placeholders + ') ON DUPLICATE KEY UPDATE dedupe_key = dedupe_key',
|
|
822
|
+
columns.map(function(k) { return record[k]; })
|
|
823
|
+
);
|
|
824
|
+
}`
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
return `${row}
|
|
828
|
+
|
|
829
|
+
async function recordOrderEvent(event) {
|
|
830
|
+
var record = orderEventRow(event);
|
|
831
|
+
var columns = Object.keys(record);
|
|
832
|
+
var placeholders = columns.map(function(_, i) { return '$' + (i + 1); }).join(', ');
|
|
833
|
+
await getClient().query(
|
|
834
|
+
'INSERT INTO ' + ORDER_EVENTS_TABLE + ' (' + columns.join(', ') + ') VALUES (' + placeholders + ') ON CONFLICT (dedupe_key) DO NOTHING',
|
|
835
|
+
columns.map(function(k) { return record[k]; })
|
|
836
|
+
);
|
|
837
|
+
}`
|
|
838
|
+
}
|
|
839
|
+
|
|
722
840
|
export const getRecordMappingCode = (dsType?: string): string => `
|
|
723
841
|
function mapInvoiceToRecord(data) {
|
|
724
842
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UIDLInvoiceEmailDelivery } from '@teleporthq/teleport-types'
|
|
2
|
+
import { EmailSender } from '@teleporthq/teleport-shared'
|
|
2
3
|
|
|
3
4
|
export const generateEmailSenderCode = (emailDelivery: UIDLInvoiceEmailDelivery): string => {
|
|
4
5
|
if (!emailDelivery || !emailDelivery.enabled || !emailDelivery.provider) {
|
|
@@ -33,6 +34,8 @@ var BODY_TEMPLATE = ${JSON.stringify(bodyTemplate)};
|
|
|
33
34
|
// Per-language copies of the subject/body (main language excluded), chosen by
|
|
34
35
|
// the locale the generate route resolved for the invoice (the order's).
|
|
35
36
|
var LOCALIZED_TEMPLATES = ${JSON.stringify(localizedTemplates)};
|
|
37
|
+
${EmailSender.generateEmailSenderHelperCode()}
|
|
38
|
+
var SENDER = __emailSender(${JSON.stringify({ from: fromEmail, name: fromName })});
|
|
36
39
|
|
|
37
40
|
function resolveSecretKey(keyName) {
|
|
38
41
|
var envName = SECRET_KEYS[keyName];
|
|
@@ -52,7 +55,8 @@ function buildEmailData(invoiceData) {
|
|
|
52
55
|
subject: replacePlaceholders(copy.subject, data),
|
|
53
56
|
body: replacePlaceholders(copy.body, data),
|
|
54
57
|
to: invoiceData.customerEmail || '',
|
|
55
|
-
from:
|
|
58
|
+
from: SENDER.header,
|
|
59
|
+
sender: SENDER,
|
|
56
60
|
templateData: data,
|
|
57
61
|
};
|
|
58
62
|
}
|
|
@@ -63,7 +67,9 @@ function attachmentName(invoiceData) {
|
|
|
63
67
|
|
|
64
68
|
${generateProviderSendFunction(emailDelivery.provider)}
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
// sourceRef names the route that sent it in the ledger: the payment's
|
|
71
|
+
// generate route unless the caller says otherwise.
|
|
72
|
+
async function sendInvoiceEmail(invoiceData, pdfBuffer, sourceRef) {
|
|
67
73
|
var emailData = buildEmailData(invoiceData);
|
|
68
74
|
if (!emailData.to) return { success: false, error: 'No customer email provided' };
|
|
69
75
|
var result;
|
|
@@ -77,6 +83,7 @@ async function sendInvoiceEmail(invoiceData, pdfBuffer) {
|
|
|
77
83
|
audience: 'customer',
|
|
78
84
|
to: emailData.to,
|
|
79
85
|
from: emailData.from,
|
|
86
|
+
fromName: emailData.sender.name,
|
|
80
87
|
subject: emailData.subject,
|
|
81
88
|
html: emailData.body,
|
|
82
89
|
payload: emailData.templateData,
|
|
@@ -91,7 +98,7 @@ async function sendInvoiceEmail(invoiceData, pdfBuffer) {
|
|
|
91
98
|
status: result && result.success ? 'sent' : 'failed',
|
|
92
99
|
error: result && !result.success ? result.error : null,
|
|
93
100
|
source: 'invoice',
|
|
94
|
-
sourceRef: 'api/invoices/generate',
|
|
101
|
+
sourceRef: sourceRef || 'api/invoices/generate',
|
|
95
102
|
orderId: invoiceData.orderId,
|
|
96
103
|
referenceType: 'invoice',
|
|
97
104
|
referenceId: invoiceData.id,
|
|
@@ -139,9 +146,12 @@ async function sendInvoiceEmailWithProvider(emailData, invoiceData, pdfBuffer) {
|
|
|
139
146
|
var apiKey = resolveSecretKey('apiKey');
|
|
140
147
|
if (!apiKey) return { success: false, error: 'SendGrid API key not configured' };
|
|
141
148
|
sgMail.setApiKey(apiKey);
|
|
149
|
+
// SendGrid reads a "Name <email>" string's name verbatim, quotes included,
|
|
150
|
+
// so a named sender goes as its two parts.
|
|
151
|
+
var sender = emailData.sender;
|
|
142
152
|
var msg = {
|
|
143
153
|
to: emailData.to,
|
|
144
|
-
from:
|
|
154
|
+
from: sender.name ? { email: sender.email, name: sender.name } : sender.email,
|
|
145
155
|
subject: emailData.subject,
|
|
146
156
|
html: emailData.body,
|
|
147
157
|
attachments: [{
|
|
@@ -217,26 +227,6 @@ async function sendInvoiceEmailWithProvider(emailData, invoiceData, pdfBuffer) {
|
|
|
217
227
|
|
|
218
228
|
case 'mailersend':
|
|
219
229
|
return `
|
|
220
|
-
// Pulls "name" and "email" out of the RFC-5322-ish \`from\` string the
|
|
221
|
-
// builder assembles. Three shapes in the wild:
|
|
222
|
-
// 1. "Acme Billing <billing@acme.com>" → name="Acme Billing", email="billing@acme.com"
|
|
223
|
-
// 2. "billing@acme.com" → name="", email="billing@acme.com"
|
|
224
|
-
// 3. "" → {}, caller handles the fallback
|
|
225
|
-
// The old implementation used naive \`.replace()\` chains that produced
|
|
226
|
-
// \`name="billing@acme.com"\` in case (2) — MailerSend accepts that but the
|
|
227
|
-
// email then appears in the recipient's client with itself as the sender
|
|
228
|
-
// name, which is ugly. Kept as a pure helper (no fallbacks baked in) so
|
|
229
|
-
// the caller decides what to do when a field is missing.
|
|
230
|
-
function parseFromString(from) {
|
|
231
|
-
var str = String(from || '').trim();
|
|
232
|
-
if (!str) return { name: '', email: '' };
|
|
233
|
-
var m = /^(.*)<([^<>]+)>\\s*$/.exec(str);
|
|
234
|
-
if (m) {
|
|
235
|
-
return { name: m[1].trim(), email: m[2].trim() };
|
|
236
|
-
}
|
|
237
|
-
return { name: '', email: str };
|
|
238
|
-
}
|
|
239
|
-
|
|
240
230
|
async function sendInvoiceEmailWithProvider(emailData, invoiceData, pdfBuffer) {
|
|
241
231
|
var invoiceNumber = invoiceData && invoiceData.invoiceNumber ? invoiceData.invoiceNumber : '(no number)';
|
|
242
232
|
try {
|
|
@@ -256,7 +246,7 @@ async function sendInvoiceEmailWithProvider(emailData, invoiceData, pdfBuffer) {
|
|
|
256
246
|
|
|
257
247
|
var mailerSend = new MailerSend({ apiKey: apiKey });
|
|
258
248
|
|
|
259
|
-
var parsedFrom =
|
|
249
|
+
var parsedFrom = emailData.sender;
|
|
260
250
|
if (!parsedFrom.email) {
|
|
261
251
|
console.error('[invoice-email][mailersend] skip — from address is empty (set invoiceSettings.emailDelivery.fromEmail)');
|
|
262
252
|
return { success: false, error: 'Sender email not configured' };
|
package/src/invoice/index.ts
CHANGED
|
@@ -33,6 +33,36 @@ var TEMPLATE_DOCUMENT = ${templateDocumentJson};
|
|
|
33
33
|
${REGIONAL_INVOICE_TAX_CODE}
|
|
34
34
|
${ProductOptions.generateProductOptionsHelperCode()}
|
|
35
35
|
|
|
36
|
+
// The invoice details an order's metadata (JSON text) carries beside its
|
|
37
|
+
// billing columns — the keys \`ORDER_BILLING_METADATA_KEYS\` (teleport-gui)
|
|
38
|
+
// writes: the address in its parts, the company and the buyer's tax or VAT
|
|
39
|
+
// number. Every part is '' when the order has none or its metadata is no JSON
|
|
40
|
+
// object.
|
|
41
|
+
function readOrderBillingMetadata(raw) {
|
|
42
|
+
var parsed = raw;
|
|
43
|
+
if (typeof raw === 'string') {
|
|
44
|
+
try {
|
|
45
|
+
parsed = JSON.parse(raw);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
parsed = null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var meta = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
51
|
+
function part(key) {
|
|
52
|
+
var value = meta[key];
|
|
53
|
+
return value === null || value === undefined ? '' : String(value).trim();
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
taxId: part('billingTaxId'),
|
|
57
|
+
company: part('billingCompany'),
|
|
58
|
+
street: part('billingStreet'),
|
|
59
|
+
city: part('billingCity'),
|
|
60
|
+
postalCode: part('billingPostalCode'),
|
|
61
|
+
region: part('billingRegion'),
|
|
62
|
+
country: part('billingCountry'),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
36
66
|
// The product options an order line was bought with: the short one-line label
|
|
37
67
|
// (after the name) and every answer in full, one per line (the description).
|
|
38
68
|
// Same rule as the order emails: a current snapshot names its options, while
|
|
@@ -416,15 +446,28 @@ function assembleInvoiceData(body, hydratedOrder, hydratedItems) {
|
|
|
416
446
|
// field but the order has one, use it. Kept permissive on field
|
|
417
447
|
// names (billing_* wins, falls back to shipping_*) because a buyer
|
|
418
448
|
// who checked "bill to a different address" has both on the order.
|
|
449
|
+
//
|
|
450
|
+
// An order whose buyer gave invoice details of their own (a booking's
|
|
451
|
+
// "Add invoice details", a store checkout's "Billing Details") carries them
|
|
452
|
+
// in its metadata as well: the address in its parts, the company and the tax
|
|
453
|
+
// or VAT number. Those parts are the invoice's address — never mixed with a
|
|
454
|
+
// shipping address — the company is printed under the buyer's name, and the
|
|
455
|
+
// number is the buyer's VAT.
|
|
419
456
|
var orderRow = orderShippingSource;
|
|
457
|
+
var orderBilling = readOrderBillingMetadata(orderRow.metadata);
|
|
458
|
+
var billedApart = !!(orderBilling.street || orderBilling.city || orderBilling.country);
|
|
420
459
|
var fallbackCustomerName =
|
|
421
460
|
orderRow.billing_name || orderRow.shipping_name || orderRow.customer_name || '';
|
|
422
461
|
var fallbackCustomerEmail = orderRow.billing_email || orderRow.customer_email || '';
|
|
423
|
-
var fallbackCustomerAddress =
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
var
|
|
427
|
-
var
|
|
462
|
+
var fallbackCustomerAddress = billedApart
|
|
463
|
+
? orderBilling.street
|
|
464
|
+
: orderRow.billing_address || orderRow.shipping_address || '';
|
|
465
|
+
var fallbackCustomerCity = billedApart ? orderBilling.city : orderRow.shipping_city || '';
|
|
466
|
+
var fallbackCustomerState = billedApart ? orderBilling.region : orderRow.shipping_state || '';
|
|
467
|
+
var fallbackCustomerZip = billedApart ? orderBilling.postalCode : orderRow.shipping_zip || '';
|
|
468
|
+
var fallbackCustomerCountry = billedApart
|
|
469
|
+
? orderBilling.country
|
|
470
|
+
: orderRow.shipping_country || '';
|
|
428
471
|
var fallbackPaymentMethod = orderRow.payment_method || '';
|
|
429
472
|
var fallbackPaymentProvider = orderRow.payment_provider || '';
|
|
430
473
|
var fallbackPaymentIntentId = orderRow.payment_intent_id || '';
|
|
@@ -446,7 +489,8 @@ function assembleInvoiceData(body, hydratedOrder, hydratedItems) {
|
|
|
446
489
|
customerState: body.customerState || fallbackCustomerState || '',
|
|
447
490
|
customerZip: body.customerZip || fallbackCustomerZip || '',
|
|
448
491
|
customerCountry: body.customerCountry || fallbackCustomerCountry || '',
|
|
449
|
-
customerVat: body.customerVat || '',
|
|
492
|
+
customerVat: body.customerVat || orderBilling.taxId || '',
|
|
493
|
+
customerCompany: body.customerCompany || orderBilling.company || '',
|
|
450
494
|
companyName: pdfGenerator.COMPANY_DETAILS.companyName || '',
|
|
451
495
|
companyAddress: pdfGenerator.COMPANY_DETAILS.companyAddress || '',
|
|
452
496
|
companyCity: pdfGenerator.COMPANY_DETAILS.companyCity || '',
|
|
@@ -355,9 +355,13 @@ function buildInvoiceDataScope(invoiceData) {
|
|
|
355
355
|
// sample — right for a company address, wrong for a code or a card tail: an
|
|
356
356
|
// order without a voucher must not print the designer's "SAVE20".
|
|
357
357
|
var realInvoiceNeverSampled = { voucherCode: voucherCode, giftCardLast4: giftCardLast4 };
|
|
358
|
+
// The buyer and their payment are never sampled either: an order with no
|
|
359
|
+
// city (a booking, a pickup, a download) must not print the designer's
|
|
360
|
+
// sample customer's, nor a card it was not paid with.
|
|
358
361
|
|
|
359
362
|
var realCustomer = {
|
|
360
363
|
name: invoiceData.customerName || '',
|
|
364
|
+
company: invoiceData.customerCompany || '',
|
|
361
365
|
email: invoiceData.customerEmail || '',
|
|
362
366
|
address: invoiceData.customerAddress || '',
|
|
363
367
|
city: invoiceData.customerCity || '',
|
|
@@ -366,6 +370,12 @@ function buildInvoiceDataScope(invoiceData) {
|
|
|
366
370
|
country: invoiceData.customerCountry || '',
|
|
367
371
|
vat: invoiceData.customerVat || '',
|
|
368
372
|
};
|
|
373
|
+
// The "Bill to" lines a buyer may leave out show only when they did not
|
|
374
|
+
// (string flags: the template compares strings, as with \`hasShipping\`).
|
|
375
|
+
realCustomer.hasCompany = realCustomer.company ? 'true' : 'false';
|
|
376
|
+
realCustomer.hasZip = realCustomer.zip ? 'true' : 'false';
|
|
377
|
+
realCustomer.hasCountry = realCustomer.country ? 'true' : 'false';
|
|
378
|
+
realCustomer.hasVat = realCustomer.vat ? 'true' : 'false';
|
|
369
379
|
|
|
370
380
|
var realPayment = {
|
|
371
381
|
method: invoiceData.paymentMethod || '',
|
|
@@ -462,8 +472,8 @@ function buildInvoiceDataScope(invoiceData) {
|
|
|
462
472
|
invoiceData: {
|
|
463
473
|
Company: mergeWithDefaults(realCompany, defaults.Company),
|
|
464
474
|
Invoice: Object.assign(mergeWithDefaults(realInvoice, defaults.Invoice), realInvoiceNeverSampled),
|
|
465
|
-
Customer:
|
|
466
|
-
Payment:
|
|
475
|
+
Customer: realCustomer,
|
|
476
|
+
Payment: realPayment,
|
|
467
477
|
Products: realProducts.length > 0 ? realProducts : (defaults.Products || []),
|
|
468
478
|
},
|
|
469
479
|
};
|
|
@@ -972,6 +982,7 @@ function buildFallbackInvoiceHtml(scope) {
|
|
|
972
982
|
escapeHtml(comp.city || '') + '<br/>' +
|
|
973
983
|
escapeHtml(comp.email || '') + '</div>');
|
|
974
984
|
parts.push('<div style="flex:1;"><strong>' + escapeHtml(cust.name || '') + '</strong><br/>' +
|
|
985
|
+
(cust.company ? escapeHtml(cust.company) + '<br/>' : '') +
|
|
975
986
|
escapeHtml(cust.email || '') + '<br/>' +
|
|
976
987
|
escapeHtml(cust.address || '') + '<br/>' +
|
|
977
988
|
escapeHtml(cust.city || '') + '</div>');
|
|
@@ -36,7 +36,17 @@ async function data_raw_query(config: any, context: any) {
|
|
|
36
36
|
const data = await response.json()
|
|
37
37
|
|
|
38
38
|
if (!response.ok) {
|
|
39
|
-
|
|
39
|
+
const failure: Record<string, unknown> = {
|
|
40
|
+
rows: [],
|
|
41
|
+
result: [],
|
|
42
|
+
error: data.error || 'Raw query failed',
|
|
43
|
+
}
|
|
44
|
+
// The database's SQLSTATE (the route keeps its message in the server log): a
|
|
45
|
+
// statement that raises on purpose is told apart from a broken one by it.
|
|
46
|
+
if (data.code) {
|
|
47
|
+
failure.code = data.code
|
|
48
|
+
}
|
|
49
|
+
return failure
|
|
40
50
|
}
|
|
41
51
|
const rows = data.rows || []
|
|
42
52
|
return { rows, result: rows }
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import { EmailSender } from '@teleporthq/teleport-shared'
|
|
1
2
|
import { NodeHandlerGenerator, handlerToString } from '../types'
|
|
3
|
+
import { assertHandlerHasNoModuleRefs } from '../analytics/commerce-tracking'
|
|
4
|
+
|
|
5
|
+
// Ambient, not imported: a serialized handler has no module scope, so
|
|
6
|
+
// generateHandler appends the helper's source (EmailSender, teleport-shared).
|
|
7
|
+
declare function __emailSender(sender: EmailSender.EmailSenderInput): EmailSender.EmailSenderParts
|
|
2
8
|
|
|
3
9
|
async function email_mailgun(config: any, context: Record<string, unknown>) {
|
|
4
10
|
const apiKey = config.apiKey
|
|
@@ -25,7 +31,7 @@ async function email_mailgun(config: any, context: Record<string, unknown>) {
|
|
|
25
31
|
}
|
|
26
32
|
const mg = mailgun.client(clientOpts)
|
|
27
33
|
|
|
28
|
-
const fromField =
|
|
34
|
+
const fromField = __emailSender({ from, name: fromName }).header
|
|
29
35
|
const toField = Array.isArray(to) ? to : [to]
|
|
30
36
|
|
|
31
37
|
const msgPayload: Record<string, any> = {
|
|
@@ -61,6 +67,9 @@ export const emailMailgun: NodeHandlerGenerator = {
|
|
|
61
67
|
'form-data': '^4.0.0',
|
|
62
68
|
},
|
|
63
69
|
generateHandler(): string {
|
|
64
|
-
return
|
|
70
|
+
return assertHandlerHasNoModuleRefs(
|
|
71
|
+
handlerToString(email_mailgun) + '\n' + EmailSender.generateEmailSenderHelperCode(),
|
|
72
|
+
'email-mailgun'
|
|
73
|
+
)
|
|
65
74
|
},
|
|
66
75
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { EmailSender } from '@teleporthq/teleport-shared'
|
|
1
2
|
import { NodeHandlerGenerator, handlerToString } from '../types'
|
|
3
|
+
import { assertHandlerHasNoModuleRefs } from '../analytics/commerce-tracking'
|
|
4
|
+
|
|
5
|
+
// Ambient, not imported: a serialized handler has no module scope, so
|
|
6
|
+
// generateHandler appends the helper's source (EmailSender, teleport-shared).
|
|
7
|
+
declare function __emailSender(sender: EmailSender.EmailSenderInput): EmailSender.EmailSenderParts
|
|
2
8
|
|
|
3
9
|
async function email_postmark(config: any, context: Record<string, unknown>) {
|
|
4
10
|
const serverToken = config.serverToken
|
|
5
11
|
const from = config.from
|
|
12
|
+
const fromName = config.fromName
|
|
6
13
|
const to = config.to
|
|
7
14
|
const subject = config.subject
|
|
8
15
|
const body = config.body
|
|
@@ -21,7 +28,7 @@ async function email_postmark(config: any, context: Record<string, unknown>) {
|
|
|
21
28
|
const toField = Array.isArray(to) ? to.join(', ') : to
|
|
22
29
|
|
|
23
30
|
const emailPayload: Record<string, any> = {
|
|
24
|
-
From: from,
|
|
31
|
+
From: __emailSender({ from, name: fromName }).header,
|
|
25
32
|
To: toField,
|
|
26
33
|
Subject: subject,
|
|
27
34
|
HtmlBody: body,
|
|
@@ -58,6 +65,9 @@ export const emailPostmark: NodeHandlerGenerator = {
|
|
|
58
65
|
postmark: '^4.0.0',
|
|
59
66
|
},
|
|
60
67
|
generateHandler(): string {
|
|
61
|
-
return
|
|
68
|
+
return assertHandlerHasNoModuleRefs(
|
|
69
|
+
handlerToString(email_postmark) + '\n' + EmailSender.generateEmailSenderHelperCode(),
|
|
70
|
+
'email-postmark'
|
|
71
|
+
)
|
|
62
72
|
},
|
|
63
73
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { EmailSender } from '@teleporthq/teleport-shared'
|
|
1
2
|
import { NodeHandlerGenerator, handlerToString } from '../types'
|
|
3
|
+
import { assertHandlerHasNoModuleRefs } from '../analytics/commerce-tracking'
|
|
4
|
+
|
|
5
|
+
// Ambient, not imported: a serialized handler has no module scope, so
|
|
6
|
+
// generateHandler appends the helper's source (EmailSender, teleport-shared).
|
|
7
|
+
declare function __emailSender(sender: EmailSender.EmailSenderInput): EmailSender.EmailSenderParts
|
|
2
8
|
|
|
3
9
|
async function email_resend(config: any, context: Record<string, unknown>) {
|
|
4
10
|
const apiKey = config.apiKey
|
|
5
11
|
const from = config.from
|
|
12
|
+
const fromName = config.fromName
|
|
6
13
|
const to = config.to
|
|
7
14
|
const subject = config.subject
|
|
8
15
|
const body = config.body
|
|
@@ -17,7 +24,7 @@ async function email_resend(config: any, context: Record<string, unknown>) {
|
|
|
17
24
|
const resend = new Resend(apiKey)
|
|
18
25
|
|
|
19
26
|
const payload: Record<string, any> = {
|
|
20
|
-
from,
|
|
27
|
+
from: __emailSender({ from, name: fromName }).header,
|
|
21
28
|
to: Array.isArray(to) ? to : [to],
|
|
22
29
|
subject,
|
|
23
30
|
html: body,
|
|
@@ -53,6 +60,9 @@ export const emailResend: NodeHandlerGenerator = {
|
|
|
53
60
|
resend: '^4.0.0',
|
|
54
61
|
},
|
|
55
62
|
generateHandler(): string {
|
|
56
|
-
return
|
|
63
|
+
return assertHandlerHasNoModuleRefs(
|
|
64
|
+
handlerToString(email_resend) + '\n' + EmailSender.generateEmailSenderHelperCode(),
|
|
65
|
+
'email-resend'
|
|
66
|
+
)
|
|
57
67
|
},
|
|
58
68
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { EmailSender } from '@teleporthq/teleport-shared'
|
|
1
2
|
import { NodeHandlerGenerator, handlerToString } from '../types'
|
|
3
|
+
import { assertHandlerHasNoModuleRefs } from '../analytics/commerce-tracking'
|
|
4
|
+
|
|
5
|
+
// Ambient, not imported: a serialized handler has no module scope, so
|
|
6
|
+
// generateHandler appends the helper's source (EmailSender, teleport-shared).
|
|
7
|
+
declare function __emailSender(sender: EmailSender.EmailSenderInput): EmailSender.EmailSenderParts
|
|
2
8
|
|
|
3
9
|
async function email_sendgrid(config: any, context: Record<string, unknown>) {
|
|
4
10
|
const apiKey = config.apiKey
|
|
5
11
|
const from = config.from
|
|
12
|
+
const fromName = config.fromName
|
|
6
13
|
const to = config.to
|
|
7
14
|
const subject = config.subject
|
|
8
15
|
const body = config.body
|
|
@@ -17,9 +24,12 @@ async function email_sendgrid(config: any, context: Record<string, unknown>) {
|
|
|
17
24
|
const sgMail = new MailService()
|
|
18
25
|
sgMail.setApiKey(apiKey)
|
|
19
26
|
|
|
27
|
+
// SendGrid reads a "Name <email>" string's name verbatim, quotes included,
|
|
28
|
+
// so a named sender goes as its two parts.
|
|
29
|
+
const sender = __emailSender({ from, name: fromName })
|
|
20
30
|
const msg: Record<string, any> = {
|
|
21
31
|
to: Array.isArray(to) ? to : [to],
|
|
22
|
-
from,
|
|
32
|
+
from: sender.name ? { email: sender.email, name: sender.name } : sender.email,
|
|
23
33
|
subject,
|
|
24
34
|
html: body,
|
|
25
35
|
}
|
|
@@ -62,6 +72,9 @@ export const emailSendgrid: NodeHandlerGenerator = {
|
|
|
62
72
|
'@sendgrid/mail': '^8.0.0',
|
|
63
73
|
},
|
|
64
74
|
generateHandler(): string {
|
|
65
|
-
return
|
|
75
|
+
return assertHandlerHasNoModuleRefs(
|
|
76
|
+
handlerToString(email_sendgrid) + '\n' + EmailSender.generateEmailSenderHelperCode(),
|
|
77
|
+
'email-sendgrid'
|
|
78
|
+
)
|
|
66
79
|
},
|
|
67
80
|
}
|
|
@@ -194,6 +194,16 @@ async function general_custom_js(config: any, context: Record<string, unknown>)
|
|
|
194
194
|
Object.keys(resolvedNamedParams).length > 0
|
|
195
195
|
) {
|
|
196
196
|
list.push(resolvedNamedParams)
|
|
197
|
+
// The named inputs are also readable as `params.<name>`, the way the
|
|
198
|
+
// custom-node path overlays `__customParams`: generated functions
|
|
199
|
+
// reach for `params.activeStep` as often as `params.slice(-1)[0]`, and
|
|
200
|
+
// an undefined there silently saved `{}` to storage.
|
|
201
|
+
const namedKeys = Object.keys(resolvedNamedParams)
|
|
202
|
+
for (let nk = 0; nk < namedKeys.length; nk++) {
|
|
203
|
+
if (!(namedKeys[nk] in list)) {
|
|
204
|
+
;(list as any)[namedKeys[nk]] = resolvedNamedParams[namedKeys[nk]]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
197
207
|
}
|
|
198
208
|
params = list
|
|
199
209
|
}
|