@teleporthq/teleport-plugin-next-workflows 0.43.65 → 0.43.67
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/bind-workflow-utils.ts +30 -0
- package/__tests__/_helpers/run-generated-middleware.ts +11 -2
- package/__tests__/admin-form-row-hydration.test.ts +55 -0
- package/__tests__/cart-clear-db-mirror.test.ts +12 -0
- package/__tests__/cart-get-total-regional-pricing.test.ts +166 -0
- package/__tests__/client-config-redaction.test.ts +53 -0
- package/__tests__/continue-on-error.test.ts +119 -0
- package/__tests__/email-locale-module.test.ts +323 -0
- package/__tests__/email-locale-senders.test.ts +268 -0
- package/__tests__/invoice-delivery-fee.test.ts +104 -0
- package/__tests__/invoice-regional-tax.test.ts +126 -0
- package/__tests__/locale-aware-redirects.test.ts +355 -0
- package/__tests__/navigation-go-to-page.test.ts +43 -0
- package/__tests__/node-handler-file-inline-map.test.ts +29 -3
- package/__tests__/payment-redirect-and-order-notification.test.ts +6 -0
- package/__tests__/paypal-webhook-order-notification.test.ts +41 -0
- package/__tests__/resolve-config-localized-templates.test.ts +262 -0
- package/__tests__/sent-email-log-module.test.ts +381 -0
- package/__tests__/sent-email-log-wiring.test.ts +267 -0
- package/dist/cjs/account-delete-route-generator.d.ts +20 -0
- package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
- package/dist/cjs/account-delete-route-generator.js +29 -26
- 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 +57 -11
- package/dist/cjs/api-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts +2 -1
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +55 -18
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
- package/dist/cjs/data-api-route-generator.js +19 -0
- package/dist/cjs/data-api-route-generator.js.map +1 -1
- package/dist/cjs/email-locale/email-locale-code.d.ts +25 -0
- package/dist/cjs/email-locale/email-locale-code.d.ts.map +1 -0
- package/dist/cjs/email-locale/email-locale-code.js +228 -0
- package/dist/cjs/email-locale/email-locale-code.js.map +1 -0
- package/dist/cjs/email-locale/email-locale-scope.d.ts +46 -0
- package/dist/cjs/email-locale/email-locale-scope.d.ts.map +1 -0
- package/dist/cjs/email-locale/email-locale-scope.js +51 -0
- package/dist/cjs/email-locale/email-locale-scope.js.map +1 -0
- package/dist/cjs/email-locale/index.d.ts +11 -0
- package/dist/cjs/email-locale/index.d.ts.map +1 -0
- package/dist/cjs/email-locale/index.js +40 -0
- package/dist/cjs/email-locale/index.js.map +1 -0
- package/dist/cjs/executor-generator.d.ts +11 -1
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +49 -7
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +9 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/cjs/invoice/api-routes-code.js +55 -6
- package/dist/cjs/invoice/api-routes-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 +72 -31
- package/dist/cjs/invoice/email-sender-code.js.map +1 -1
- package/dist/cjs/invoice/index.d.ts +1 -4
- package/dist/cjs/invoice/index.d.ts.map +1 -1
- package/dist/cjs/invoice/index.js +8 -19
- package/dist/cjs/invoice/index.js.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.js +31 -8
- package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
- package/dist/cjs/invoice/regional-invoice-tax-code.d.ts +25 -0
- package/dist/cjs/invoice/regional-invoice-tax-code.d.ts.map +1 -0
- package/dist/cjs/invoice/regional-invoice-tax-code.js +116 -0
- package/dist/cjs/invoice/regional-invoice-tax-code.js.map +1 -0
- package/dist/cjs/invoice/resolve-data-source.d.ts +6 -0
- package/dist/cjs/invoice/resolve-data-source.d.ts.map +1 -0
- package/dist/cjs/invoice/resolve-data-source.js +23 -0
- package/dist/cjs/invoice/resolve-data-source.js.map +1 -0
- package/dist/cjs/nodes/account/account-delete-current.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-delete-current.js +10 -3
- package/dist/cjs/nodes/account/account-delete-current.js.map +1 -1
- package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-login.js +3 -1
- package/dist/cjs/nodes/account/account-login.js.map +1 -1
- package/dist/cjs/nodes/account/account-logout.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-logout.js +4 -2
- package/dist/cjs/nodes/account/account-logout.js.map +1 -1
- package/dist/cjs/nodes/account/account-signup.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-signup.js +12 -2
- package/dist/cjs/nodes/account/account-signup.js.map +1 -1
- package/dist/cjs/nodes/account/account-social-login.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-social-login.js +4 -2
- package/dist/cjs/nodes/account/account-social-login.js.map +1 -1
- package/dist/cjs/nodes/cart/cart-clear.d.ts.map +1 -1
- package/dist/cjs/nodes/cart/cart-clear.js +6 -0
- package/dist/cjs/nodes/cart/cart-clear.js.map +1 -1
- package/dist/cjs/nodes/cart/cart-get-total.d.ts.map +1 -1
- package/dist/cjs/nodes/cart/cart-get-total.js +81 -5
- package/dist/cjs/nodes/cart/cart-get-total.js.map +1 -1
- package/dist/cjs/nodes/data/data-create-item.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-create-item.js +16 -0
- package/dist/cjs/nodes/data/data-create-item.js.map +1 -1
- package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.d.ts.map +1 -1
- package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.js +6 -0
- package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.js.map +1 -1
- package/dist/cjs/nodes/navigation/navigation-go-to-page.d.ts.map +1 -1
- package/dist/cjs/nodes/navigation/navigation-go-to-page.js +4 -1
- package/dist/cjs/nodes/navigation/navigation-go-to-page.js.map +1 -1
- package/dist/cjs/nodes/navigation/navigation-navigate-to-url.d.ts.map +1 -1
- package/dist/cjs/nodes/navigation/navigation-navigate-to-url.js +5 -2
- package/dist/cjs/nodes/navigation/navigation-navigate-to-url.js.map +1 -1
- package/dist/cjs/nodes/payment/payment-charge-user.d.ts.map +1 -1
- package/dist/cjs/nodes/payment/payment-charge-user.js +7 -2
- package/dist/cjs/nodes/payment/payment-charge-user.js.map +1 -1
- package/dist/cjs/segment-splitter.d.ts +1 -1
- package/dist/cjs/segment-splitter.d.ts.map +1 -1
- package/dist/cjs/segment-splitter.js +29 -2
- package/dist/cjs/segment-splitter.js.map +1 -1
- package/dist/cjs/sent-email-log/index.d.ts +16 -0
- package/dist/cjs/sent-email-log/index.d.ts.map +1 -0
- package/dist/cjs/sent-email-log/index.js +53 -0
- package/dist/cjs/sent-email-log/index.js.map +1 -0
- package/dist/cjs/sent-email-log/sent-email-log-code.d.ts +4 -0
- package/dist/cjs/sent-email-log/sent-email-log-code.d.ts.map +1 -0
- package/dist/cjs/sent-email-log/sent-email-log-code.js +415 -0
- package/dist/cjs/sent-email-log/sent-email-log-code.js.map +1 -0
- package/dist/cjs/sent-email-log/sent-email-log-scope.d.ts +21 -0
- package/dist/cjs/sent-email-log/sent-email-log-scope.d.ts.map +1 -0
- package/dist/cjs/sent-email-log/sent-email-log-scope.js +36 -0
- package/dist/cjs/sent-email-log/sent-email-log-scope.js.map +1 -0
- package/dist/cjs/transactional-email-code.d.ts +39 -1
- package/dist/cjs/transactional-email-code.d.ts.map +1 -1
- package/dist/cjs/transactional-email-code.js +86 -12
- package/dist/cjs/transactional-email-code.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/webhook-generator.d.ts.map +1 -1
- package/dist/cjs/webhook-generator.js +9 -2
- package/dist/cjs/webhook-generator.js.map +1 -1
- package/dist/cjs/workflow-component-plugin.js +4 -3
- 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 +31 -3
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/cjs/workflow-utils-alias.d.ts +21 -0
- package/dist/cjs/workflow-utils-alias.d.ts.map +1 -0
- package/dist/cjs/workflow-utils-alias.js +27 -0
- package/dist/cjs/workflow-utils-alias.js.map +1 -0
- package/dist/esm/account-delete-route-generator.d.ts +20 -0
- package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
- package/dist/esm/account-delete-route-generator.js +30 -27
- 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 +57 -11
- package/dist/esm/api-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts +2 -1
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +56 -19
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/data-api-route-generator.d.ts.map +1 -1
- package/dist/esm/data-api-route-generator.js +19 -0
- package/dist/esm/data-api-route-generator.js.map +1 -1
- package/dist/esm/email-locale/email-locale-code.d.ts +25 -0
- package/dist/esm/email-locale/email-locale-code.d.ts.map +1 -0
- package/dist/esm/email-locale/email-locale-code.js +222 -0
- package/dist/esm/email-locale/email-locale-code.js.map +1 -0
- package/dist/esm/email-locale/email-locale-scope.d.ts +46 -0
- package/dist/esm/email-locale/email-locale-scope.d.ts.map +1 -0
- package/dist/esm/email-locale/email-locale-scope.js +47 -0
- package/dist/esm/email-locale/email-locale-scope.js.map +1 -0
- package/dist/esm/email-locale/index.d.ts +11 -0
- package/dist/esm/email-locale/index.d.ts.map +1 -0
- package/dist/esm/email-locale/index.js +28 -0
- package/dist/esm/email-locale/index.js.map +1 -0
- package/dist/esm/executor-generator.d.ts +11 -1
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +49 -7
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/esm/invoice/api-routes-code.js +55 -6
- package/dist/esm/invoice/api-routes-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 +72 -31
- package/dist/esm/invoice/email-sender-code.js.map +1 -1
- package/dist/esm/invoice/index.d.ts +1 -4
- package/dist/esm/invoice/index.d.ts.map +1 -1
- package/dist/esm/invoice/index.js +7 -18
- package/dist/esm/invoice/index.js.map +1 -1
- package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-html-code.js +31 -8
- package/dist/esm/invoice/invoice-html-code.js.map +1 -1
- package/dist/esm/invoice/regional-invoice-tax-code.d.ts +25 -0
- package/dist/esm/invoice/regional-invoice-tax-code.d.ts.map +1 -0
- package/dist/esm/invoice/regional-invoice-tax-code.js +113 -0
- package/dist/esm/invoice/regional-invoice-tax-code.js.map +1 -0
- package/dist/esm/invoice/resolve-data-source.d.ts +6 -0
- package/dist/esm/invoice/resolve-data-source.d.ts.map +1 -0
- package/dist/esm/invoice/resolve-data-source.js +19 -0
- package/dist/esm/invoice/resolve-data-source.js.map +1 -0
- package/dist/esm/nodes/account/account-delete-current.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-delete-current.js +10 -3
- package/dist/esm/nodes/account/account-delete-current.js.map +1 -1
- package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-login.js +3 -1
- package/dist/esm/nodes/account/account-login.js.map +1 -1
- package/dist/esm/nodes/account/account-logout.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-logout.js +4 -2
- package/dist/esm/nodes/account/account-logout.js.map +1 -1
- package/dist/esm/nodes/account/account-signup.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-signup.js +12 -2
- package/dist/esm/nodes/account/account-signup.js.map +1 -1
- package/dist/esm/nodes/account/account-social-login.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-social-login.js +4 -2
- package/dist/esm/nodes/account/account-social-login.js.map +1 -1
- package/dist/esm/nodes/cart/cart-clear.d.ts.map +1 -1
- package/dist/esm/nodes/cart/cart-clear.js +6 -0
- package/dist/esm/nodes/cart/cart-clear.js.map +1 -1
- package/dist/esm/nodes/cart/cart-get-total.d.ts.map +1 -1
- package/dist/esm/nodes/cart/cart-get-total.js +81 -5
- package/dist/esm/nodes/cart/cart-get-total.js.map +1 -1
- package/dist/esm/nodes/data/data-create-item.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-create-item.js +16 -0
- package/dist/esm/nodes/data/data-create-item.js.map +1 -1
- package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.d.ts.map +1 -1
- package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.js +6 -0
- package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.js.map +1 -1
- package/dist/esm/nodes/navigation/navigation-go-to-page.d.ts.map +1 -1
- package/dist/esm/nodes/navigation/navigation-go-to-page.js +4 -1
- package/dist/esm/nodes/navigation/navigation-go-to-page.js.map +1 -1
- package/dist/esm/nodes/navigation/navigation-navigate-to-url.d.ts.map +1 -1
- package/dist/esm/nodes/navigation/navigation-navigate-to-url.js +5 -2
- package/dist/esm/nodes/navigation/navigation-navigate-to-url.js.map +1 -1
- package/dist/esm/nodes/payment/payment-charge-user.d.ts.map +1 -1
- package/dist/esm/nodes/payment/payment-charge-user.js +7 -2
- package/dist/esm/nodes/payment/payment-charge-user.js.map +1 -1
- package/dist/esm/segment-splitter.d.ts +1 -1
- package/dist/esm/segment-splitter.d.ts.map +1 -1
- package/dist/esm/segment-splitter.js +29 -2
- package/dist/esm/segment-splitter.js.map +1 -1
- package/dist/esm/sent-email-log/index.d.ts +16 -0
- package/dist/esm/sent-email-log/index.d.ts.map +1 -0
- package/dist/esm/sent-email-log/index.js +45 -0
- package/dist/esm/sent-email-log/index.js.map +1 -0
- package/dist/esm/sent-email-log/sent-email-log-code.d.ts +4 -0
- package/dist/esm/sent-email-log/sent-email-log-code.d.ts.map +1 -0
- package/dist/esm/sent-email-log/sent-email-log-code.js +411 -0
- package/dist/esm/sent-email-log/sent-email-log-code.js.map +1 -0
- package/dist/esm/sent-email-log/sent-email-log-scope.d.ts +21 -0
- package/dist/esm/sent-email-log/sent-email-log-scope.d.ts.map +1 -0
- package/dist/esm/sent-email-log/sent-email-log-scope.js +31 -0
- package/dist/esm/sent-email-log/sent-email-log-scope.js.map +1 -0
- package/dist/esm/transactional-email-code.d.ts +39 -1
- package/dist/esm/transactional-email-code.d.ts.map +1 -1
- package/dist/esm/transactional-email-code.js +81 -10
- package/dist/esm/transactional-email-code.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/webhook-generator.d.ts.map +1 -1
- package/dist/esm/webhook-generator.js +9 -2
- package/dist/esm/webhook-generator.js.map +1 -1
- package/dist/esm/workflow-component-plugin.js +4 -3
- 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 +32 -4
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/dist/esm/workflow-utils-alias.d.ts +21 -0
- package/dist/esm/workflow-utils-alias.d.ts.map +1 -0
- package/dist/esm/workflow-utils-alias.js +21 -0
- package/dist/esm/workflow-utils-alias.js.map +1 -0
- package/package.json +4 -4
- package/src/account-delete-route-generator.ts +36 -7
- package/src/api-route-generator.ts +64 -11
- package/src/auth-generator.ts +63 -18
- package/src/data-api-route-generator.ts +19 -0
- package/src/email-locale/email-locale-code.ts +239 -0
- package/src/email-locale/email-locale-scope.ts +65 -0
- package/src/email-locale/index.ts +46 -0
- package/src/executor-generator.ts +65 -7
- package/src/index.ts +8 -0
- package/src/invoice/api-routes-code.ts +65 -6
- package/src/invoice/email-sender-code.ts +72 -31
- package/src/invoice/index.ts +7 -23
- package/src/invoice/invoice-html-code.ts +31 -8
- package/src/invoice/regional-invoice-tax-code.ts +112 -0
- package/src/invoice/resolve-data-source.ts +25 -0
- package/src/nodes/account/account-delete-current.ts +10 -3
- package/src/nodes/account/account-login.ts +3 -1
- package/src/nodes/account/account-logout.ts +4 -2
- package/src/nodes/account/account-signup.ts +12 -2
- package/src/nodes/account/account-social-login.ts +7 -2
- package/src/nodes/cart/cart-clear.ts +6 -0
- package/src/nodes/cart/cart-get-total.ts +94 -5
- package/src/nodes/data/data-create-item.ts +16 -0
- package/src/nodes/ecommerce/ecommerce-generate-invoice.ts +6 -0
- package/src/nodes/navigation/navigation-go-to-page.ts +5 -1
- package/src/nodes/navigation/navigation-navigate-to-url.ts +6 -2
- package/src/nodes/payment/payment-charge-user.ts +13 -2
- package/src/nodes/workflow-utils-global.d.ts +12 -0
- package/src/segment-splitter.ts +33 -2
- package/src/sent-email-log/index.ts +57 -0
- package/src/sent-email-log/sent-email-log-code.ts +419 -0
- package/src/sent-email-log/sent-email-log-scope.ts +36 -0
- package/src/transactional-email-code.ts +112 -4
- package/src/webhook-generator.ts +11 -2
- package/src/workflow-component-plugin.ts +4 -3
- package/src/workflow-project-plugin.ts +36 -4
- package/src/workflow-utils-alias.ts +26 -0
package/src/segment-splitter.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { WorkflowSegment, WorkflowExecutionEnv } from './types'
|
|
|
3
3
|
import { getLoopBodyNodes, getNodeById, getTopologicalOrder } from './graph-utils'
|
|
4
4
|
import { nodeRegistry } from './nodes'
|
|
5
5
|
import { AWAIT_RESULT_CONFIG_KEY } from './await-result'
|
|
6
|
+
import { WELCOME_EMAIL_CONFIG_KEYS } from './transactional-email-code'
|
|
6
7
|
|
|
7
8
|
const CLIENT_ONLY_NODE_TYPES = new Set([
|
|
8
9
|
'account-login',
|
|
@@ -322,11 +323,17 @@ export const CLIENT_SAFE_SERVER_CONFIG_KEYS: ReadonlyArray<string> = [
|
|
|
322
323
|
*/
|
|
323
324
|
export const redactServerNodeConfig = (
|
|
324
325
|
config: Record<string, unknown>,
|
|
325
|
-
env: WorkflowExecutionEnv
|
|
326
|
+
env: WorkflowExecutionEnv,
|
|
327
|
+
nodeType?: string
|
|
326
328
|
): Record<string, unknown> => {
|
|
327
|
-
if (
|
|
329
|
+
if (!config || typeof config !== 'object') {
|
|
328
330
|
return config
|
|
329
331
|
}
|
|
332
|
+
if (env !== 'server') {
|
|
333
|
+
return nodeType && ROUTE_BACKED_ACCOUNT_NODE_TYPES.has(nodeType)
|
|
334
|
+
? redactRouteOnlyAccountConfig(config)
|
|
335
|
+
: config
|
|
336
|
+
}
|
|
330
337
|
const safe: Record<string, unknown> = {}
|
|
331
338
|
for (const key of CLIENT_SAFE_SERVER_CONFIG_KEYS) {
|
|
332
339
|
if (config[key] !== undefined) {
|
|
@@ -336,6 +343,30 @@ export const redactServerNodeConfig = (
|
|
|
336
343
|
return safe
|
|
337
344
|
}
|
|
338
345
|
|
|
346
|
+
// The two CLIENT account nodes carry the config of the transactional email
|
|
347
|
+
// their generated ROUTE sends (provider, credential reference, sender, the
|
|
348
|
+
// subject and body in every language). The route bakes all of it from the full
|
|
349
|
+
// UIDL config at generation time, and the client handlers never read a key of
|
|
350
|
+
// it (the signup handler even skips them so they are not forwarded as user
|
|
351
|
+
// columns) — so none of it belongs in a page bundle.
|
|
352
|
+
const ROUTE_ONLY_ACCOUNT_CONFIG_KEYS = new Set<string>([
|
|
353
|
+
...WELCOME_EMAIL_CONFIG_KEYS,
|
|
354
|
+
'domain',
|
|
355
|
+
'deletedEmailPattern',
|
|
356
|
+
])
|
|
357
|
+
|
|
358
|
+
const ROUTE_BACKED_ACCOUNT_NODE_TYPES = new Set(['account-signup', 'account-delete-current'])
|
|
359
|
+
|
|
360
|
+
const redactRouteOnlyAccountConfig = (config: Record<string, unknown>): Record<string, unknown> => {
|
|
361
|
+
const safe: Record<string, unknown> = {}
|
|
362
|
+
for (const key of Object.keys(config)) {
|
|
363
|
+
if (!ROUTE_ONLY_ACCOUNT_CONFIG_KEYS.has(key)) {
|
|
364
|
+
safe[key] = config[key]
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return safe
|
|
368
|
+
}
|
|
369
|
+
|
|
339
370
|
export const getServerSegments = (segments: WorkflowSegment[]): WorkflowSegment[] => {
|
|
340
371
|
return segments.filter((s) => s.env === 'server')
|
|
341
372
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { FileType, ProjectPluginStructure } from '@teleporthq/teleport-types'
|
|
2
|
+
import { getDatabaseDriverDependencies } from '../auth-generator'
|
|
3
|
+
import { resolveInvoiceDataSource } from '../invoice/resolve-data-source'
|
|
4
|
+
import { generateSentEmailLogCode } from './sent-email-log-code'
|
|
5
|
+
import {
|
|
6
|
+
SENT_EMAIL_LOG_FILE_KEY,
|
|
7
|
+
SENT_EMAIL_LOG_FILE_NAME,
|
|
8
|
+
SENT_EMAIL_LOG_PATH,
|
|
9
|
+
} from './sent-email-log-scope'
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
EMAIL_CAPABLE_INTEGRATION_NODE_TYPES,
|
|
13
|
+
hasEmailSendingNodeType,
|
|
14
|
+
isEmailSendingNodeType,
|
|
15
|
+
} from './sent-email-log-scope'
|
|
16
|
+
export { generateSentEmailLogCode } from './sent-email-log-code'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Writes `utils/email/sent-email-log.js` into the project, once. Every
|
|
20
|
+
* emitter of a send path calls this right where it emits the code that
|
|
21
|
+
* `require`s the module (workflow routes, the invoice sender, the account
|
|
22
|
+
* routes, the e-commerce notification sender), so the file exists exactly
|
|
23
|
+
* when something needs it, whichever plugin ran first.
|
|
24
|
+
*
|
|
25
|
+
* The ledger is Postgres-only: on another data source the module is a no-op
|
|
26
|
+
* with the same exports. The `pg` dependency is added only when the project's
|
|
27
|
+
* database is Postgres, through the same driver map auth and invoices use.
|
|
28
|
+
*/
|
|
29
|
+
export const ensureSentEmailLogModule = (structure: ProjectPluginStructure): void => {
|
|
30
|
+
const { files, dependencies } = structure
|
|
31
|
+
if (files.has(SENT_EMAIL_LOG_FILE_KEY)) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { dataSourceType } = resolveInvoiceDataSource(structure)
|
|
36
|
+
const driverDeps = getDatabaseDriverDependencies(dataSourceType)
|
|
37
|
+
const pgSupported = 'pg' in driverDeps
|
|
38
|
+
|
|
39
|
+
files.set(SENT_EMAIL_LOG_FILE_KEY, {
|
|
40
|
+
path: SENT_EMAIL_LOG_PATH,
|
|
41
|
+
files: [
|
|
42
|
+
{
|
|
43
|
+
name: SENT_EMAIL_LOG_FILE_NAME,
|
|
44
|
+
fileType: FileType.JS,
|
|
45
|
+
content: generateSentEmailLogCode({ pgSupported }),
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
if (pgSupported) {
|
|
51
|
+
for (const [pkg, version] of Object.entries(driverDeps)) {
|
|
52
|
+
if (!dependencies[pkg]) {
|
|
53
|
+
dependencies[pkg] = version
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { generatePgClientCode } from '../pg-client-code'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Emits `utils/email/sent-email-log.js` — the ONE place every email the
|
|
5
|
+
* generated app sends is recorded into `teleport_sent_emails`.
|
|
6
|
+
*
|
|
7
|
+
* Callers (in this order of coverage):
|
|
8
|
+
* - workflow `email-*` / Gmail / Outlook nodes: wrapped per server route by
|
|
9
|
+
* `wrapEmailNodeHandler` (see `generateNodeHandlersForSegment`);
|
|
10
|
+
* - the invoice sender (`utils/invoices/email-sender.js`);
|
|
11
|
+
* - the welcome / farewell routes (`transactional-email-code.ts`);
|
|
12
|
+
* - the order-notification / low-stock routes (`utils/ecommerce/email-sender.js`).
|
|
13
|
+
*
|
|
14
|
+
* Contract: `recordSentEmail` never throws and never rejects, the send is
|
|
15
|
+
* never delayed by it, and a route drains it before replying (a serverless
|
|
16
|
+
* function may be frozen the instant it responds). Only an explicit allow-list
|
|
17
|
+
* of fields is stored — a node config carries credentials.
|
|
18
|
+
*
|
|
19
|
+
* `pgSupported=false` (a MySQL / Mongo / Firestore project) emits a module with
|
|
20
|
+
* the same exports that records nothing, so consumers need no branching.
|
|
21
|
+
*/
|
|
22
|
+
const PG_REQUIRE_LINE = "const { Client } = require('pg');"
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The shared `getClient()` boilerplate with its eager `require('pg')` swapped
|
|
26
|
+
* for the lazy loader above: a project can carry an email node and no
|
|
27
|
+
* Postgres driver, and a top-level require would fail the build of every
|
|
28
|
+
* workflow route ("Collecting page data"). `new Client(opts)` keeps working —
|
|
29
|
+
* a constructor that returns an object yields that object.
|
|
30
|
+
*/
|
|
31
|
+
const lazyPgClientCode = (): string => {
|
|
32
|
+
const code = generatePgClientCode()
|
|
33
|
+
if (!code.startsWith(PG_REQUIRE_LINE)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
'sent-email-log: generatePgClientCode() no longer starts with the pg require line'
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
return code.replace(
|
|
39
|
+
PG_REQUIRE_LINE,
|
|
40
|
+
'function Client(opts) { var pg = __loadPg(); return new pg.Client(opts); }'
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const generateSentEmailLogCode = (options: { pgSupported: boolean }): string => {
|
|
45
|
+
if (!options.pgSupported) {
|
|
46
|
+
return `/**
|
|
47
|
+
* Sent-email ledger — disabled: the project's data source is not Postgres.
|
|
48
|
+
*/
|
|
49
|
+
function recordSentEmail() { return Promise.resolve(false); }
|
|
50
|
+
function settleSentEmailLog() { return Promise.resolve(); }
|
|
51
|
+
function wrapEmailNodeHandler(_nodeType, handler) { return handler; }
|
|
52
|
+
|
|
53
|
+
module.exports = { recordSentEmail, settleSentEmailLog, wrapEmailNodeHandler };
|
|
54
|
+
`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return `/**
|
|
58
|
+
* Sent-email ledger.
|
|
59
|
+
*
|
|
60
|
+
* Every email the app sends — workflow email nodes, the invoice sender, the
|
|
61
|
+
* welcome/farewell routes, order and stock alerts — lands here as one row of
|
|
62
|
+
* \`teleport_sent_emails\`: who it went to, what it said, the values the
|
|
63
|
+
* template was filled with, and whether the provider accepted it.
|
|
64
|
+
*
|
|
65
|
+
* Never awaited by the send itself; never throws; drained before a route
|
|
66
|
+
* replies (see settleSentEmailLog).
|
|
67
|
+
*/
|
|
68
|
+
var __pg = null;
|
|
69
|
+
var __pgLoadFailed = false;
|
|
70
|
+
function __loadPg() {
|
|
71
|
+
if (__pg || __pgLoadFailed) return __pg;
|
|
72
|
+
try { __pg = require('pg'); } catch (_e) { __pgLoadFailed = true; __pg = null; }
|
|
73
|
+
return __pg;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
${lazyPgClientCode()}
|
|
77
|
+
|
|
78
|
+
var TABLE_NAME = 'teleport_sent_emails';
|
|
79
|
+
var BODY_MAX_CHARS = 1000000;
|
|
80
|
+
var PAYLOAD_MAX_CHARS = 200000;
|
|
81
|
+
var SUBJECT_MAX_CHARS = 2000;
|
|
82
|
+
var ADDRESS_MAX_CHARS = 320;
|
|
83
|
+
var TRUNCATION_MARKER = '\\n<!-- truncated by sent-email-log -->';
|
|
84
|
+
var INSERT_TIMEOUT_MS = 15000;
|
|
85
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
86
|
+
// Template parameters whose VALUE must not be persisted: a reset link carries
|
|
87
|
+
// a live token, and the ledger is readable from the admin panel.
|
|
88
|
+
var SENSITIVE_PARAM_KEY_RE = /token|password|secret|otp|reset|verif|magic|passcode/i;
|
|
89
|
+
var REDACTED = '[redacted]';
|
|
90
|
+
|
|
91
|
+
var __pending = [];
|
|
92
|
+
var __disabledReason = '';
|
|
93
|
+
var __consecutiveFailures = 0;
|
|
94
|
+
var MAX_CONSECUTIVE_FAILURES = 3;
|
|
95
|
+
|
|
96
|
+
function __disable(reason) {
|
|
97
|
+
if (__disabledReason) return;
|
|
98
|
+
__disabledReason = reason;
|
|
99
|
+
console.warn('[sent-email-log] disabled for this process: ' + reason);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function __hasDatabaseEnv() {
|
|
103
|
+
return !!(process.env.TELEPORT_DB_CONNECTION_STRING || process.env.TELEPORT_DB_HOST);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function __toArray(value) {
|
|
107
|
+
if (value == null || value === '') return [];
|
|
108
|
+
if (Array.isArray(value)) {
|
|
109
|
+
var out = [];
|
|
110
|
+
for (var i = 0; i < value.length; i++) { out = out.concat(__toArray(value[i])); }
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
if (typeof value === 'object') {
|
|
114
|
+
// Provider SDK shapes: { email, name } / { address }.
|
|
115
|
+
var addr = value.email || value.address || value.emailAddress;
|
|
116
|
+
return addr ? [String(addr)] : [];
|
|
117
|
+
}
|
|
118
|
+
return String(value).split(',').map(function (s) { return s.trim(); }).filter(Boolean);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function __truncate(text, max) {
|
|
122
|
+
if (text == null) return null;
|
|
123
|
+
var str = String(text);
|
|
124
|
+
if (str.length <= max) return str;
|
|
125
|
+
return str.slice(0, max) + TRUNCATION_MARKER;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function __safeStringify(value, max) {
|
|
129
|
+
if (value == null) return null;
|
|
130
|
+
var json;
|
|
131
|
+
try {
|
|
132
|
+
json = JSON.stringify(value, function (_k, v) {
|
|
133
|
+
if (typeof v === 'bigint') return String(v);
|
|
134
|
+
if (v && typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) return '[buffer ' + v.data.length + ' bytes]';
|
|
135
|
+
return v;
|
|
136
|
+
});
|
|
137
|
+
} catch (_e) {
|
|
138
|
+
return '"[unserializable]"';
|
|
139
|
+
}
|
|
140
|
+
if (json == null) return null;
|
|
141
|
+
return __truncate(json, max);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// "Acme Billing <billing@acme.com>" → { name, email }; "billing@acme.com" → { name: '', email }.
|
|
145
|
+
function __parseAddress(from) {
|
|
146
|
+
var str = String(from || '').trim();
|
|
147
|
+
if (!str) return { name: '', email: '' };
|
|
148
|
+
var m = /^(.*)<([^<>]+)>\\s*$/.exec(str);
|
|
149
|
+
if (m) return { name: m[1].trim().replace(/^"|"$/g, ''), email: m[2].trim() };
|
|
150
|
+
return { name: '', email: str };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function __uuidOrNull(value) {
|
|
154
|
+
if (typeof value !== 'string' || !UUID_RE.test(value)) return null;
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// templateParams arrive as [{ key, value }] (workflow nodes) or as a plain
|
|
159
|
+
// object (routes). Returns { payload, redactedValues } where redactedValues
|
|
160
|
+
// are the string values of sensitive keys, to be scrubbed from the body too.
|
|
161
|
+
function __normalizePayload(params) {
|
|
162
|
+
var payload = {};
|
|
163
|
+
var redactedValues = [];
|
|
164
|
+
var entries = [];
|
|
165
|
+
if (Array.isArray(params)) {
|
|
166
|
+
for (var i = 0; i < params.length; i++) {
|
|
167
|
+
var p = params[i];
|
|
168
|
+
if (p && typeof p === 'object' && typeof p.key === 'string') entries.push([p.key, p.value]);
|
|
169
|
+
}
|
|
170
|
+
} else if (params && typeof params === 'object') {
|
|
171
|
+
var keys = Object.keys(params);
|
|
172
|
+
for (var k = 0; k < keys.length; k++) entries.push([keys[k], params[keys[k]]]);
|
|
173
|
+
}
|
|
174
|
+
for (var e = 0; e < entries.length; e++) {
|
|
175
|
+
var key = entries[e][0];
|
|
176
|
+
var value = entries[e][1];
|
|
177
|
+
if (SENSITIVE_PARAM_KEY_RE.test(key)) {
|
|
178
|
+
if (typeof value === 'string' && value.length >= 8) redactedValues.push(value);
|
|
179
|
+
payload[key] = REDACTED;
|
|
180
|
+
} else {
|
|
181
|
+
payload[key] = value;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return { payload: entries.length ? payload : null, redactedValues: redactedValues };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function __scrub(text, redactedValues) {
|
|
188
|
+
if (!text) return text;
|
|
189
|
+
var out = String(text);
|
|
190
|
+
for (var i = 0; i < redactedValues.length; i++) {
|
|
191
|
+
out = out.split(redactedValues[i]).join(REDACTED);
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function __normalizeAttachments(attachments) {
|
|
197
|
+
if (!Array.isArray(attachments) || attachments.length === 0) return null;
|
|
198
|
+
var out = [];
|
|
199
|
+
for (var i = 0; i < attachments.length; i++) {
|
|
200
|
+
var a = attachments[i] || {};
|
|
201
|
+
out.push({
|
|
202
|
+
filename: a.filename || a.name || a.Name || 'attachment',
|
|
203
|
+
contentType: a.contentType || a.type || a.ContentType || null,
|
|
204
|
+
sizeBytes: typeof a.sizeBytes === 'number' ? a.sizeBytes : null,
|
|
205
|
+
url: a.url || null,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return __safeStringify(out, PAYLOAD_MAX_CHARS);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Maps a loose entry onto the table's columns. Returns null when there is
|
|
213
|
+
* nothing to record (no recipient at all).
|
|
214
|
+
*
|
|
215
|
+
* entry: { emailType, audience, to, cc, bcc, from, fromName, replyTo, subject,
|
|
216
|
+
* html, payload, attachments, provider, providerMessageId, status,
|
|
217
|
+
* error, source, sourceRef, orderId, userId, referenceType, referenceId }
|
|
218
|
+
*/
|
|
219
|
+
function buildSentEmailRow(entry) {
|
|
220
|
+
var e = entry || {};
|
|
221
|
+
var recipients = __toArray(e.to);
|
|
222
|
+
if (recipients.length === 0) return null;
|
|
223
|
+
var from = __parseAddress(e.from);
|
|
224
|
+
var fromName = e.fromName ? String(e.fromName) : from.name;
|
|
225
|
+
var normalized = __normalizePayload(e.payload);
|
|
226
|
+
var cc = __toArray(e.cc);
|
|
227
|
+
var bcc = __toArray(e.bcc);
|
|
228
|
+
var status = e.status === 'failed' ? 'failed' : 'sent';
|
|
229
|
+
return {
|
|
230
|
+
email_type: __truncate(e.emailType || 'custom', 100),
|
|
231
|
+
audience: __truncate(e.audience || 'other', 20),
|
|
232
|
+
recipient_email: __truncate(recipients[0], ADDRESS_MAX_CHARS),
|
|
233
|
+
recipients: JSON.stringify(recipients),
|
|
234
|
+
cc: cc.length ? JSON.stringify(cc) : null,
|
|
235
|
+
bcc: bcc.length ? JSON.stringify(bcc) : null,
|
|
236
|
+
reply_to: e.replyTo ? __truncate(__toArray(e.replyTo)[0] || '', ADDRESS_MAX_CHARS) : null,
|
|
237
|
+
from_email: from.email ? __truncate(from.email, ADDRESS_MAX_CHARS) : null,
|
|
238
|
+
from_name: fromName ? __truncate(fromName, 255) : null,
|
|
239
|
+
subject: __truncate(__scrub(e.subject, normalized.redactedValues), SUBJECT_MAX_CHARS),
|
|
240
|
+
body_html: __truncate(__scrub(e.html, normalized.redactedValues), BODY_MAX_CHARS) || '',
|
|
241
|
+
payload: __safeStringify(normalized.payload, PAYLOAD_MAX_CHARS),
|
|
242
|
+
attachments: __normalizeAttachments(e.attachments),
|
|
243
|
+
provider: e.provider ? __truncate(e.provider, 50) : null,
|
|
244
|
+
provider_message_id: e.providerMessageId ? __truncate(String(e.providerMessageId), 255) : null,
|
|
245
|
+
status: status,
|
|
246
|
+
error_message: e.error ? __truncate(String(e.error), 4000) : null,
|
|
247
|
+
source: __truncate(e.source || 'app', 50),
|
|
248
|
+
source_ref: e.sourceRef ? __truncate(String(e.sourceRef), 255) : null,
|
|
249
|
+
order_id: __uuidOrNull(e.orderId),
|
|
250
|
+
user_id: __uuidOrNull(e.userId),
|
|
251
|
+
reference_type: e.referenceType ? __truncate(String(e.referenceType), 50) : null,
|
|
252
|
+
reference_id: e.referenceId ? __truncate(String(e.referenceId), 255) : null,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function __newId() {
|
|
257
|
+
try {
|
|
258
|
+
var crypto = require('crypto');
|
|
259
|
+
if (typeof crypto.randomUUID === 'function') return crypto.randomUUID();
|
|
260
|
+
var b = crypto.randomBytes(16);
|
|
261
|
+
b[6] = (b[6] & 0x0f) | 0x40;
|
|
262
|
+
b[8] = (b[8] & 0x3f) | 0x80;
|
|
263
|
+
var h = b.toString('hex');
|
|
264
|
+
return h.slice(0, 8) + '-' + h.slice(8, 12) + '-' + h.slice(12, 16) + '-' + h.slice(16, 20) + '-' + h.slice(20);
|
|
265
|
+
} catch (_e) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function __withTimeout(promise, ms) {
|
|
271
|
+
var timer;
|
|
272
|
+
var timeout = new Promise(function (_resolve, reject) {
|
|
273
|
+
timer = setTimeout(function () { reject(new Error('sent-email-log insert timed out after ' + ms + 'ms')); }, ms);
|
|
274
|
+
});
|
|
275
|
+
return Promise.race([promise, timeout]).then(function (v) { clearTimeout(timer); return v; }, function (err) { clearTimeout(timer); throw err; });
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function __insert(row) {
|
|
279
|
+
var columns = Object.keys(row);
|
|
280
|
+
var values = columns.map(function (c) { return row[c]; });
|
|
281
|
+
var id = __newId();
|
|
282
|
+
if (id) { columns.unshift('id'); values.unshift(id); }
|
|
283
|
+
var placeholders = values.map(function (_v, i) { return '$' + (i + 1); });
|
|
284
|
+
var sql = 'INSERT INTO "' + TABLE_NAME + '" (' + columns.map(function (c) { return '"' + c + '"'; }).join(', ') + ') VALUES (' + placeholders.join(', ') + ')';
|
|
285
|
+
var client = getClient();
|
|
286
|
+
await client.connect();
|
|
287
|
+
try {
|
|
288
|
+
await __withTimeout(client.query(sql, values), INSERT_TIMEOUT_MS);
|
|
289
|
+
} finally {
|
|
290
|
+
try { await client.end(); } catch (_e) {}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Records one send attempt. Resolves to true when the row landed, false
|
|
296
|
+
* otherwise. NEVER rejects.
|
|
297
|
+
*/
|
|
298
|
+
function recordSentEmail(entry) {
|
|
299
|
+
var task = (async function () {
|
|
300
|
+
if (__disabledReason) return false;
|
|
301
|
+
if (!__hasDatabaseEnv()) { __disable('no database connection configured'); return false; }
|
|
302
|
+
if (!__loadPg()) { __disable('the pg driver is not installed'); return false; }
|
|
303
|
+
var row;
|
|
304
|
+
try { row = buildSentEmailRow(entry); } catch (buildErr) {
|
|
305
|
+
console.error('[sent-email-log] could not build the row:', buildErr && buildErr.message ? buildErr.message : buildErr);
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
if (!row) return false;
|
|
309
|
+
try {
|
|
310
|
+
await __insert(row);
|
|
311
|
+
__consecutiveFailures = 0;
|
|
312
|
+
return true;
|
|
313
|
+
} catch (err) {
|
|
314
|
+
var code = err && err.code;
|
|
315
|
+
if (code === '42P01') { __disable('table ' + TABLE_NAME + ' does not exist — re-run the feature activation in the editor'); return false; }
|
|
316
|
+
if (code === '42703') { __disable('table ' + TABLE_NAME + ' is missing a column — re-run the feature activation in the editor'); return false; }
|
|
317
|
+
__consecutiveFailures += 1;
|
|
318
|
+
console.error('[sent-email-log] insert failed: ' + (err && err.message ? err.message : String(err)));
|
|
319
|
+
if (__consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) __disable('repeated insert failures');
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
})();
|
|
323
|
+
__pending.push(task);
|
|
324
|
+
task.then(function () { __forget(task); }, function () { __forget(task); });
|
|
325
|
+
return task;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function __forget(task) {
|
|
329
|
+
var idx = __pending.indexOf(task);
|
|
330
|
+
if (idx >= 0) __pending.splice(idx, 1);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Awaits every in-flight record. Never rejects. */
|
|
334
|
+
async function settleSentEmailLog() {
|
|
335
|
+
for (var pass = 0; pass < 5 && __pending.length > 0; pass++) {
|
|
336
|
+
await Promise.all(__pending.slice());
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Provider name from a node type: 'email-resend' → 'resend', 'integration-gmail' → 'gmail'.
|
|
341
|
+
function __providerOf(nodeType) {
|
|
342
|
+
var t = String(nodeType || '');
|
|
343
|
+
if (t.indexOf('email-') === 0) return t.slice(6);
|
|
344
|
+
if (t.indexOf('integration-') === 0) return t.slice(12);
|
|
345
|
+
return t || null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function __shouldRecordNode(nodeType, config) {
|
|
349
|
+
if (String(nodeType).indexOf('email-') === 0) return true;
|
|
350
|
+
return !!config && config.action === 'send-email';
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function __entryFromNode(nodeType, config, result, error) {
|
|
354
|
+
var c = config || {};
|
|
355
|
+
var r = result || {};
|
|
356
|
+
var failed = !!error || r.success === false || (typeof r.error === 'string' && r.error) || r.error === true;
|
|
357
|
+
var message = r.message && typeof r.message === 'object' ? r.message : null;
|
|
358
|
+
var providerMessageId = r.messageId || r.id || (message && message.id) || null;
|
|
359
|
+
var errorText = error ? (error.message || String(error)) : (typeof r.error === 'string' ? r.error : (r.error === true && typeof r.message === 'string' ? r.message : null));
|
|
360
|
+
return {
|
|
361
|
+
emailType: c.emailPurpose || 'custom',
|
|
362
|
+
audience: c.emailAudience || 'other',
|
|
363
|
+
to: c.to,
|
|
364
|
+
cc: c.cc,
|
|
365
|
+
bcc: c.bcc,
|
|
366
|
+
from: c.from,
|
|
367
|
+
fromName: c.fromName,
|
|
368
|
+
replyTo: c.replyTo,
|
|
369
|
+
subject: c.subject,
|
|
370
|
+
html: c.body != null ? c.body : (c.html != null ? c.html : c.text),
|
|
371
|
+
payload: c.templateParams,
|
|
372
|
+
provider: __providerOf(nodeType),
|
|
373
|
+
providerMessageId: providerMessageId,
|
|
374
|
+
status: failed ? 'failed' : 'sent',
|
|
375
|
+
error: errorText,
|
|
376
|
+
source: 'workflow',
|
|
377
|
+
sourceRef: nodeType,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Wraps a server node handler so every send is recorded. The record is
|
|
383
|
+
* registered on the workflow context's fire-and-forget queue — the same one
|
|
384
|
+
* \`settlePendingNodePromises\` drains before the route replies — and pushed
|
|
385
|
+
* BEFORE the handler's result is returned, so the drain always sees it.
|
|
386
|
+
* Extra arguments (a streaming callback) are forwarded untouched.
|
|
387
|
+
*/
|
|
388
|
+
function wrapEmailNodeHandler(nodeType, handler) {
|
|
389
|
+
if (typeof handler !== 'function') return handler;
|
|
390
|
+
return async function (config, context) {
|
|
391
|
+
if (!__shouldRecordNode(nodeType, config)) {
|
|
392
|
+
return handler.apply(this, arguments);
|
|
393
|
+
}
|
|
394
|
+
var result;
|
|
395
|
+
try {
|
|
396
|
+
result = await handler.apply(this, arguments);
|
|
397
|
+
} catch (err) {
|
|
398
|
+
__register(context, recordSentEmail(__entryFromNode(nodeType, config, null, err)));
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
__register(context, recordSentEmail(__entryFromNode(nodeType, config, result, null)));
|
|
402
|
+
return result;
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function __register(context, promise) {
|
|
407
|
+
if (!context || typeof context !== 'object') return;
|
|
408
|
+
if (!Array.isArray(context.__pendingNodePromises)) context.__pendingNodePromises = [];
|
|
409
|
+
context.__pendingNodePromises.push(promise);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
module.exports = {
|
|
413
|
+
recordSentEmail: recordSentEmail,
|
|
414
|
+
settleSentEmailLog: settleSentEmailLog,
|
|
415
|
+
wrapEmailNodeHandler: wrapEmailNodeHandler,
|
|
416
|
+
buildSentEmailRow: buildSentEmailRow,
|
|
417
|
+
};
|
|
418
|
+
`
|
|
419
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which generated code sends email, and therefore which projects get the
|
|
3
|
+
* sent-email ledger module (`utils/email/sent-email-log.js`).
|
|
4
|
+
*
|
|
5
|
+
* Every emitter of a send path calls `ensureSentEmailLogModule` itself, so the
|
|
6
|
+
* module exists exactly when something `require`s it. This file only holds the
|
|
7
|
+
* node-type vocabulary the route generators share.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const SENT_EMAIL_LOG_FILE_KEY = 'sent-email-log'
|
|
11
|
+
export const SENT_EMAIL_LOG_PATH = ['utils', 'email']
|
|
12
|
+
export const SENT_EMAIL_LOG_FILE_NAME = 'sent-email-log'
|
|
13
|
+
|
|
14
|
+
/** Provider send-email nodes: `email-resend`, `email-sendgrid`, … */
|
|
15
|
+
export const EMAIL_NODE_TYPE_PREFIX = 'email-'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Integration nodes that can send mail among other actions. Only their
|
|
19
|
+
* `send-email` action is recorded; the wrapper checks the resolved config.
|
|
20
|
+
*/
|
|
21
|
+
export const EMAIL_CAPABLE_INTEGRATION_NODE_TYPES = new Set([
|
|
22
|
+
'integration-gmail',
|
|
23
|
+
'integration-outlook',
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
export const isEmailSendingNodeType = (nodeType: string): boolean =>
|
|
27
|
+
nodeType.startsWith(EMAIL_NODE_TYPE_PREFIX) || EMAIL_CAPABLE_INTEGRATION_NODE_TYPES.has(nodeType)
|
|
28
|
+
|
|
29
|
+
export const hasEmailSendingNodeType = (nodeTypes: Iterable<string>): boolean => {
|
|
30
|
+
for (const nodeType of nodeTypes) {
|
|
31
|
+
if (isEmailSendingNodeType(nodeType)) {
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return false
|
|
36
|
+
}
|