@teleporthq/teleport-plugin-next-workflows 0.44.8 → 0.44.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/_helpers/load-server-runtime.ts +6 -2
- package/__tests__/_helpers/run-account-delete-route.ts +140 -0
- package/__tests__/account-delete-current-password.test.ts +73 -0
- package/__tests__/account-delete-password-check.test.ts +113 -0
- package/__tests__/account-delete-visitor-details.test.ts +206 -0
- package/__tests__/auth-password-change-ends-sessions.test.ts +178 -0
- package/__tests__/data-api-invalid-body.test.ts +110 -0
- package/__tests__/data-node-not-awaited.test.ts +7 -6
- package/__tests__/invoice-payment-line.test.ts +68 -0
- package/__tests__/invoice-tender.test.ts +116 -0
- package/__tests__/pending-work-after-reply.test.ts +294 -0
- package/__tests__/runtime-condition-operands.test.ts +86 -0
- package/__tests__/webhook-delivery-lease.test.ts +68 -6
- package/dist/cjs/account-delete-route-generator.d.ts +7 -2
- package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
- package/dist/cjs/account-delete-route-generator.js +90 -43
- 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 +12 -13
- package/dist/cjs/api-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +34 -1
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/await-result.d.ts +13 -5
- package/dist/cjs/await-result.d.ts.map +1 -1
- package/dist/cjs/await-result.js +19 -8
- package/dist/cjs/await-result.js.map +1 -1
- package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
- package/dist/cjs/data-api-route-generator.js +9 -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 +18 -6
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.js +96 -5
- package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
- package/dist/cjs/nodes/account/account-delete-current.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-delete-current.js +4 -1
- package/dist/cjs/nodes/account/account-delete-current.js.map +1 -1
- package/dist/cjs/server-runtime-code.d.ts.map +1 -1
- package/dist/cjs/server-runtime-code.js +21 -0
- package/dist/cjs/server-runtime-code.js.map +1 -1
- package/dist/cjs/transactional-email-code.d.ts +7 -0
- package/dist/cjs/transactional-email-code.d.ts.map +1 -1
- package/dist/cjs/transactional-email-code.js +5 -5
- package/dist/cjs/transactional-email-code.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/vercel-functions.d.ts +34 -0
- package/dist/cjs/vercel-functions.d.ts.map +1 -0
- package/dist/cjs/vercel-functions.js +62 -0
- package/dist/cjs/vercel-functions.js.map +1 -0
- package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.d.ts +6 -0
- package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.d.ts.map +1 -1
- package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.js +26 -11
- package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.js.map +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +3 -0
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/esm/account-delete-route-generator.d.ts +7 -2
- package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
- package/dist/esm/account-delete-route-generator.js +90 -43
- 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 +12 -13
- package/dist/esm/api-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +34 -1
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/await-result.d.ts +13 -5
- package/dist/esm/await-result.d.ts.map +1 -1
- package/dist/esm/await-result.js +18 -7
- package/dist/esm/await-result.js.map +1 -1
- package/dist/esm/data-api-route-generator.d.ts.map +1 -1
- package/dist/esm/data-api-route-generator.js +9 -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 +18 -6
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-html-code.js +96 -5
- package/dist/esm/invoice/invoice-html-code.js.map +1 -1
- package/dist/esm/nodes/account/account-delete-current.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-delete-current.js +4 -1
- package/dist/esm/nodes/account/account-delete-current.js.map +1 -1
- package/dist/esm/server-runtime-code.d.ts.map +1 -1
- package/dist/esm/server-runtime-code.js +21 -0
- package/dist/esm/server-runtime-code.js.map +1 -1
- package/dist/esm/transactional-email-code.d.ts +7 -0
- package/dist/esm/transactional-email-code.d.ts.map +1 -1
- package/dist/esm/transactional-email-code.js +5 -5
- package/dist/esm/transactional-email-code.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/vercel-functions.d.ts +34 -0
- package/dist/esm/vercel-functions.d.ts.map +1 -0
- package/dist/esm/vercel-functions.js +57 -0
- package/dist/esm/vercel-functions.js.map +1 -0
- package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.d.ts +6 -0
- package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.d.ts.map +1 -1
- package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.js +26 -11
- package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.js.map +1 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +3 -0
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/account-delete-route-generator.ts +97 -45
- package/src/api-route-generator.ts +12 -13
- package/src/auth-generator.ts +34 -1
- package/src/await-result.ts +19 -7
- package/src/data-api-route-generator.ts +9 -1
- package/src/executor-generator.ts +18 -6
- package/src/invoice/invoice-html-code.ts +96 -5
- package/src/nodes/account/account-delete-current.ts +4 -1
- package/src/server-runtime-code.ts +22 -0
- package/src/transactional-email-code.ts +12 -5
- package/src/vercel-functions.ts +67 -0
- package/src/webhook-delivery-lease/webhook-delivery-lease-code.ts +26 -11
- package/src/workflow-project-plugin.ts +3 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { generateVercelFunctionsLoaderCode } from './vercel-functions'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* `utils/workflows/server-runtime.js`: what every server route loads. It is the
|
|
3
5
|
* shared runtime utilities plus the parts only a server may run — the signed
|
|
@@ -42,6 +44,8 @@ export const generateServerRuntimeCode = (): string => `'use strict';
|
|
|
42
44
|
var crypto = require('crypto');
|
|
43
45
|
var utils = require('./runtime-utils');
|
|
44
46
|
|
|
47
|
+
${generateVercelFunctionsLoaderCode()}
|
|
48
|
+
|
|
45
49
|
var __stepKeyCache = { secret: null, key: null };
|
|
46
50
|
|
|
47
51
|
function stepKey() {
|
|
@@ -394,7 +398,25 @@ function trustedBaseUrl(req) {
|
|
|
394
398
|
return origin;
|
|
395
399
|
}
|
|
396
400
|
|
|
401
|
+
// The work a segment's not-awaited steps left running (an invoice being
|
|
402
|
+
// rendered and mailed) must still finish, but the visitor need not wait for
|
|
403
|
+
// it: on Vercel it is handed to waitUntil, which keeps the function running
|
|
404
|
+
// after the reply. Anywhere else the route awaits it before replying, since a
|
|
405
|
+
// function frozen after its reply would drop it.
|
|
406
|
+
function handOffPendingNodePromises(context) {
|
|
407
|
+
var queue = context && context.__pendingNodePromises;
|
|
408
|
+
if (!queue || queue.length === 0) return Promise.resolve();
|
|
409
|
+
// Drained through the queue itself: the route deletes it from the context
|
|
410
|
+
// before replying, and a parallel branch still running pushes onto it.
|
|
411
|
+
var drained = utils.settlePendingNodePromises({ __pendingNodePromises: queue });
|
|
412
|
+
var waitUntil = __vercelWaitUntil();
|
|
413
|
+
if (!waitUntil) return drained;
|
|
414
|
+
waitUntil(drained);
|
|
415
|
+
return Promise.resolve();
|
|
416
|
+
}
|
|
417
|
+
|
|
397
418
|
module.exports = Object.assign({}, utils, {
|
|
419
|
+
handOffPendingNodePromises: handOffPendingNodePromises,
|
|
398
420
|
claimSegmentContext: claimSegmentContext,
|
|
399
421
|
segmentReply: segmentReply,
|
|
400
422
|
internalRequestHeaders: internalRequestHeaders,
|
|
@@ -38,10 +38,17 @@ export interface TransactionalEmailLedger {
|
|
|
38
38
|
source: string
|
|
39
39
|
sourceRef: string
|
|
40
40
|
relativePrefix: string
|
|
41
|
+
/**
|
|
42
|
+
* Records the send without the recipient's details: `msg.recordedTo` in
|
|
43
|
+
* place of the address, and neither the body nor the values it was filled
|
|
44
|
+
* with. For an email to someone whose details the route is removing (the
|
|
45
|
+
* farewell after an account deletion).
|
|
46
|
+
*/
|
|
47
|
+
withoutRecipientDetails?: boolean
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
// Provider-specific `__sendProviderEmail({ from, fromName?, to,
|
|
44
|
-
// apiKey, tokenValues?, userId? })`, preceded by the `__emailSender` helper that
|
|
50
|
+
// Provider-specific `__sendProviderEmail({ from, fromName?, to, recordedTo?,
|
|
51
|
+
// subject, html, apiKey, tokenValues?, userId? })`, preceded by the `__emailSender` helper that
|
|
45
52
|
// names the sender. No attachment (unlike the invoice sender). When no provider
|
|
46
53
|
// is configured the function is a no-op so the route stays self-contained and
|
|
47
54
|
// never throws. With `ledger`, the provider function is emitted as
|
|
@@ -77,12 +84,12 @@ async function __sendProviderEmail(msg) {
|
|
|
77
84
|
__sentEmailLog.recordSentEmail({
|
|
78
85
|
emailType: ${JSON.stringify(ledger.emailType)},
|
|
79
86
|
audience: 'customer',
|
|
80
|
-
to: msg.to,
|
|
87
|
+
to: ${ledger.withoutRecipientDetails ? 'msg.recordedTo' : 'msg.to'},
|
|
81
88
|
from: sender.email,
|
|
82
89
|
fromName: sender.name,
|
|
83
90
|
subject: msg.subject,
|
|
84
|
-
html: msg.html,
|
|
85
|
-
payload: msg.tokenValues,
|
|
91
|
+
html: ${ledger.withoutRecipientDetails ? "''" : 'msg.html'},
|
|
92
|
+
payload: ${ledger.withoutRecipientDetails ? 'null' : 'msg.tokenValues'},
|
|
86
93
|
provider: ${JSON.stringify(provider)},
|
|
87
94
|
status: failure ? 'failed' : 'sent',
|
|
88
95
|
error: failure ? (failure.message || String(failure)) : null,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@vercel/functions` in a generated project: `waitUntil`, which keeps a
|
|
3
|
+
* Vercel function running after its reply, and `attachDatabasePool`, which
|
|
4
|
+
* closes a pool's idle connections before the function is suspended.
|
|
5
|
+
*
|
|
6
|
+
* The generated code loads it inside a try, so a project that does not have
|
|
7
|
+
* it installed (or a bundler that cannot find it) keeps working without
|
|
8
|
+
* either. A project whose emitted files require it declares it (see
|
|
9
|
+
* `declareVercelFunctionsWhereRequired`).
|
|
10
|
+
*/
|
|
11
|
+
export const VERCEL_FUNCTIONS_PACKAGE = '@vercel/functions'
|
|
12
|
+
|
|
13
|
+
// The 2.x line still supports Node 18, which the Next project template allows;
|
|
14
|
+
// 3.x requires Node 20. attachDatabasePool is stable from 2.2.8.
|
|
15
|
+
export const VERCEL_FUNCTIONS_VERSION = '^2.2.13'
|
|
16
|
+
|
|
17
|
+
const VERCEL_FUNCTIONS_REQUIRE = `require('${VERCEL_FUNCTIONS_PACKAGE}')`
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `__vercelFunctions()` (the module, or null) and `__vercelWaitUntil()` (the
|
|
21
|
+
* module's waitUntil while this code runs inside a Vercel request, else null).
|
|
22
|
+
*
|
|
23
|
+
* waitUntil does nothing outside a Vercel request (a local `next dev`, another
|
|
24
|
+
* host): it reads the request context Vercel installs under
|
|
25
|
+
* `Symbol.for('@vercel/request-context')` and silently drops the promise when
|
|
26
|
+
* there is none. The same check here lets a caller await the work instead.
|
|
27
|
+
*/
|
|
28
|
+
export const generateVercelFunctionsLoaderCode = (): string => `var __vercelFunctionsModule;
|
|
29
|
+
function __vercelFunctions() {
|
|
30
|
+
if (__vercelFunctionsModule === undefined) {
|
|
31
|
+
try { __vercelFunctionsModule = ${VERCEL_FUNCTIONS_REQUIRE}; } catch (_e) { __vercelFunctionsModule = null; }
|
|
32
|
+
}
|
|
33
|
+
return __vercelFunctionsModule;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function __vercelWaitUntil() {
|
|
37
|
+
var store = globalThis[Symbol.for('@vercel/request-context')];
|
|
38
|
+
var requestContext = store && typeof store.get === 'function' ? store.get() : null;
|
|
39
|
+
if (!requestContext || typeof requestContext.waitUntil !== 'function') return null;
|
|
40
|
+
var vercel = __vercelFunctions();
|
|
41
|
+
return vercel && typeof vercel.waitUntil === 'function' ? vercel.waitUntil : null;
|
|
42
|
+
}`
|
|
43
|
+
|
|
44
|
+
interface GeneratedFileRecord {
|
|
45
|
+
files?: Array<{ content?: unknown }>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Declares `@vercel/functions` in the project's dependencies when any emitted
|
|
50
|
+
* file requires it, keeping a version the project already declares.
|
|
51
|
+
*/
|
|
52
|
+
export const declareVercelFunctionsWhereRequired = (
|
|
53
|
+
files: Map<string, GeneratedFileRecord>,
|
|
54
|
+
dependencies: Record<string, string>
|
|
55
|
+
): void => {
|
|
56
|
+
if (dependencies[VERCEL_FUNCTIONS_PACKAGE]) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
for (const record of files.values()) {
|
|
60
|
+
for (const file of record.files || []) {
|
|
61
|
+
if (typeof file.content === 'string' && file.content.includes(VERCEL_FUNCTIONS_REQUIRE)) {
|
|
62
|
+
dependencies[VERCEL_FUNCTIONS_PACKAGE] = VERCEL_FUNCTIONS_VERSION
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -22,6 +22,12 @@ import {
|
|
|
22
22
|
* released before the route replies; one left by a run that died expires
|
|
23
23
|
* after a lease longer than any route may run.
|
|
24
24
|
*
|
|
25
|
+
* The table is used when it exists (the editor creates it with the payment
|
|
26
|
+
* tables) and created only when it does not: a site's database role may read
|
|
27
|
+
* and write its tables without being allowed to create one, and
|
|
28
|
+
* CREATE TABLE IF NOT EXISTS asks for that permission even when the table is
|
|
29
|
+
* there.
|
|
30
|
+
*
|
|
25
31
|
* Contract: `claimWebhookDelivery` never throws. Without Postgres, a driver,
|
|
26
32
|
* the table or the privilege to create it, it claims nothing and lets the
|
|
27
33
|
* delivery run — as every delivery ran before the lease existed.
|
|
@@ -48,6 +54,7 @@ ${generateLazyPgClientCode()}
|
|
|
48
54
|
var TABLE_NAME = '${WEBHOOK_DELIVERY_LEASE_TABLE}';
|
|
49
55
|
var LEASE_SECONDS = ${WEBHOOK_DELIVERY_LEASE_SECONDS};
|
|
50
56
|
var QUERY_TIMEOUT_MS = 5000;
|
|
57
|
+
var TABLE_EXISTS_SQL = 'SELECT to_regclass($1) IS NOT NULL AS present';
|
|
51
58
|
var CREATE_SQL = 'CREATE TABLE IF NOT EXISTS "' + TABLE_NAME + '" (' +
|
|
52
59
|
'delivery_key TEXT PRIMARY KEY, claim_token TEXT NOT NULL, ' +
|
|
53
60
|
'claimed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), attempts INTEGER NOT NULL DEFAULT 1)';
|
|
@@ -80,20 +87,28 @@ function __withTimeout(promise, ms) {
|
|
|
80
87
|
return Promise.race([promise, timeout]).then(function (v) { clearTimeout(timer); return v; }, function (err) { clearTimeout(timer); throw err; });
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
// Runs \`work(query)\` on one connection, closed afterwards.
|
|
91
|
+
async function __run(work) {
|
|
84
92
|
var client = getClient();
|
|
85
93
|
await __withTimeout(client.connect(), QUERY_TIMEOUT_MS);
|
|
86
94
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
return result;
|
|
95
|
+
return await work(function (sql, values) {
|
|
96
|
+
return __withTimeout(client.query(sql, values || []), QUERY_TIMEOUT_MS);
|
|
97
|
+
});
|
|
92
98
|
} finally {
|
|
93
99
|
try { await client.end(); } catch (_e) {}
|
|
94
100
|
}
|
|
95
101
|
}
|
|
96
102
|
|
|
103
|
+
async function __ensureTable(query) {
|
|
104
|
+
if (__tableReady) return;
|
|
105
|
+
var found = await query(TABLE_EXISTS_SQL, [TABLE_NAME]);
|
|
106
|
+
if (!found || !Array.isArray(found.rows) || !found.rows[0] || !found.rows[0].present) {
|
|
107
|
+
await query(CREATE_SQL);
|
|
108
|
+
}
|
|
109
|
+
__tableReady = true;
|
|
110
|
+
}
|
|
111
|
+
|
|
97
112
|
function __stableJson(value) {
|
|
98
113
|
try { return JSON.stringify(value === undefined ? null : value) || ''; } catch (_e) { return ''; }
|
|
99
114
|
}
|
|
@@ -120,12 +135,12 @@ async function claimWebhookDelivery(scope, rawBody, verifiedBody) {
|
|
|
120
135
|
.update(__stableJson(verifiedBody))
|
|
121
136
|
.digest('hex');
|
|
122
137
|
var token = crypto.randomBytes(16).toString('hex');
|
|
123
|
-
var statements = __tableReady ? [] : [{ sql: CREATE_SQL, values: [] }];
|
|
124
|
-
statements.push({ sql: CLAIM_SQL, values: [key, token, LEASE_SECONDS] });
|
|
125
138
|
var result;
|
|
126
139
|
try {
|
|
127
|
-
result = await __run(
|
|
128
|
-
|
|
140
|
+
result = await __run(async function (query) {
|
|
141
|
+
await __ensureTable(query);
|
|
142
|
+
return query(CLAIM_SQL, [key, token, LEASE_SECONDS]);
|
|
143
|
+
});
|
|
129
144
|
} catch (err) {
|
|
130
145
|
var code = err && err.code;
|
|
131
146
|
if (code === '42501') { __disable('no privilege to create or write table ' + TABLE_NAME); }
|
|
@@ -138,7 +153,7 @@ async function claimWebhookDelivery(scope, rawBody, verifiedBody) {
|
|
|
138
153
|
return {
|
|
139
154
|
claimed: true,
|
|
140
155
|
release: function () {
|
|
141
|
-
return __run(
|
|
156
|
+
return __run(function (query) { return query(RELEASE_SQL, [key, token]); }).then(
|
|
142
157
|
function () {},
|
|
143
158
|
function (err) { console.error('[webhook-delivery-lease] release failed: ' + (err && err.message ? err.message : String(err))); }
|
|
144
159
|
);
|
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
import { generateInvoiceFiles, resolveInvoiceDataSource } from './invoice'
|
|
73
73
|
import { ensureSentEmailLogModule, hasEmailSendingNodeType } from './sent-email-log'
|
|
74
74
|
import { ensureWebhookDeliveryLeaseModule } from './webhook-delivery-lease'
|
|
75
|
+
import { declareVercelFunctionsWhereRequired } from './vercel-functions'
|
|
75
76
|
import { ensureEmailLocaleModule, resolveEmailLocaleConfig } from './email-locale'
|
|
76
77
|
import { workflowUtilsImportLine, workflowUtilsRequireLine } from './workflow-utils-alias'
|
|
77
78
|
import { generateWebhookFiles } from './webhook-generator'
|
|
@@ -385,6 +386,7 @@ export class NextWorkflowProjectPlugin implements ProjectPlugin {
|
|
|
385
386
|
if (hasAuthentication) {
|
|
386
387
|
this.injectSessionProviderIntoApp(structure)
|
|
387
388
|
}
|
|
389
|
+
declareVercelFunctionsWhereRequired(files, dependencies)
|
|
388
390
|
return structure
|
|
389
391
|
}
|
|
390
392
|
|
|
@@ -974,6 +976,7 @@ export class NextWorkflowProjectPlugin implements ProjectPlugin {
|
|
|
974
976
|
this.injectSessionProviderIntoApp(structure)
|
|
975
977
|
}
|
|
976
978
|
|
|
979
|
+
declareVercelFunctionsWhereRequired(files, dependencies)
|
|
977
980
|
return structure
|
|
978
981
|
}
|
|
979
982
|
|