@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
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import type { UIDLWorkflow, UIDLWorkflowEdge, UIDLWorkflowNode } from '@teleporthq/teleport-types'
|
|
2
|
+
import { splitIntoSegments } from '../src/segment-splitter'
|
|
3
|
+
import type { WorkflowSegment } from '../src/types'
|
|
4
|
+
|
|
5
|
+
// Every server segment the browser reaches is one awaited round trip. A
|
|
6
|
+
// checkout is one long chain of server steps with a refusal branch (a toast, a
|
|
7
|
+
// reset) at almost every gate, all at the same depth as the chain's next step.
|
|
8
|
+
// Ordered by depth alone, each refusal step sat between two server steps of the
|
|
9
|
+
// chain and cut it into one more round trip; the loop over the cart lines held
|
|
10
|
+
// everything after it in a depth-only order. Built here the way the editor's
|
|
11
|
+
// checkout builds Place Order, with synthetic ids and labels.
|
|
12
|
+
|
|
13
|
+
type Kind = 'client' | 'server' | 'gate' | 'loop' | 'custom-node' | 'navigate'
|
|
14
|
+
|
|
15
|
+
const TYPE: Record<Kind, string> = {
|
|
16
|
+
client: 'state-update-local-state',
|
|
17
|
+
server: 'data-raw-query',
|
|
18
|
+
gate: 'general-if-statement',
|
|
19
|
+
loop: 'general-loop',
|
|
20
|
+
'custom-node': 'general-custom-node',
|
|
21
|
+
navigate: 'navigation-go-to-page',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ENV: Record<Kind, UIDLWorkflowNode['executionEnv']> = {
|
|
25
|
+
client: 'client',
|
|
26
|
+
server: 'server',
|
|
27
|
+
gate: 'universal',
|
|
28
|
+
loop: 'universal',
|
|
29
|
+
'custom-node': 'universal',
|
|
30
|
+
navigate: 'client',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const buildWorkflow = (
|
|
34
|
+
steps: Array<[string, Kind]>,
|
|
35
|
+
links: Array<[string, string, string?, string?]>
|
|
36
|
+
): UIDLWorkflow => {
|
|
37
|
+
const edges: UIDLWorkflowEdge[] = links.map(([source, target, sourceHandle, targetHandle]) => ({
|
|
38
|
+
id: `${source}->${target}`,
|
|
39
|
+
source,
|
|
40
|
+
target,
|
|
41
|
+
...(sourceHandle ? { sourceHandle } : {}),
|
|
42
|
+
...(targetHandle ? { targetHandle } : {}),
|
|
43
|
+
}))
|
|
44
|
+
// The editor's step numbers: breadth-first depth from the trigger.
|
|
45
|
+
const depth = new Map<string, number>()
|
|
46
|
+
const queue: Array<[string, number]> = [['trigger', 0]]
|
|
47
|
+
while (queue.length > 0) {
|
|
48
|
+
const [id, d] = queue.shift() as [string, number]
|
|
49
|
+
if (depth.has(id)) {
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
depth.set(id, d)
|
|
53
|
+
edges.filter((e) => e.source === id).forEach((e) => queue.push([e.target, d + 1]))
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
id: 'place-order',
|
|
57
|
+
name: 'Place Order',
|
|
58
|
+
trigger: { type: 'event-form-submitted', nodeId: 'trigger' },
|
|
59
|
+
nodes: steps.map(([id, kind]) => ({
|
|
60
|
+
id,
|
|
61
|
+
type: TYPE[kind],
|
|
62
|
+
label: id,
|
|
63
|
+
config: {},
|
|
64
|
+
executionEnv: ENV[kind],
|
|
65
|
+
stepNumber: depth.get(id) || 0,
|
|
66
|
+
})),
|
|
67
|
+
edges,
|
|
68
|
+
} as unknown as UIDLWorkflow
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// A gate whose condition reads a server step, its refusal branch three or four
|
|
72
|
+
// browser steps long, its accepted branch the rest of the chain.
|
|
73
|
+
const placeOrder = buildWorkflow(
|
|
74
|
+
[
|
|
75
|
+
['setBusy', 'client'],
|
|
76
|
+
['formValid', 'gate'],
|
|
77
|
+
['formToast', 'client'],
|
|
78
|
+
['fetchStock', 'server'],
|
|
79
|
+
['checkStock', 'server'],
|
|
80
|
+
['inStock', 'gate'],
|
|
81
|
+
['stockToast', 'client'],
|
|
82
|
+
['stockReset', 'client'],
|
|
83
|
+
['resolveUser', 'custom-node'],
|
|
84
|
+
['loadDiscounts', 'server'],
|
|
85
|
+
['countOrders', 'server'],
|
|
86
|
+
['recheckVoucher', 'server'],
|
|
87
|
+
['voucherValid', 'gate'],
|
|
88
|
+
['forgetVoucher', 'client'],
|
|
89
|
+
['voucherToast', 'client'],
|
|
90
|
+
['voucherReset', 'client'],
|
|
91
|
+
['voucherClear', 'client'],
|
|
92
|
+
['priceOrder', 'server'],
|
|
93
|
+
['assemble', 'server'],
|
|
94
|
+
['checkAddress', 'server'],
|
|
95
|
+
['canBill', 'gate'],
|
|
96
|
+
['billToast', 'client'],
|
|
97
|
+
['billReset', 'client'],
|
|
98
|
+
['createOrder', 'server'],
|
|
99
|
+
['redeem', 'server'],
|
|
100
|
+
['redeemed', 'gate'],
|
|
101
|
+
['cancelOrder', 'server'],
|
|
102
|
+
['redeemToast', 'client'],
|
|
103
|
+
['orderNumber', 'server'],
|
|
104
|
+
['eachLine', 'loop'],
|
|
105
|
+
['buildLine', 'server'],
|
|
106
|
+
['saveLine', 'server'],
|
|
107
|
+
['decrementStock', 'server'],
|
|
108
|
+
['recordPlaced', 'custom-node'],
|
|
109
|
+
['saveDetails', 'server'],
|
|
110
|
+
['settled', 'gate'],
|
|
111
|
+
['markSettled', 'server'],
|
|
112
|
+
['clearCart', 'client'],
|
|
113
|
+
['emailPayload', 'server'],
|
|
114
|
+
['sendEmail', 'server'],
|
|
115
|
+
['goToOrder', 'navigate'],
|
|
116
|
+
['redirectUrls', 'server'],
|
|
117
|
+
['charge', 'server'],
|
|
118
|
+
['opened', 'gate'],
|
|
119
|
+
['cancelRefused', 'server'],
|
|
120
|
+
['refusedToast', 'client'],
|
|
121
|
+
['recordCheckout', 'server'],
|
|
122
|
+
['sendToCheckout', 'navigate'],
|
|
123
|
+
],
|
|
124
|
+
[
|
|
125
|
+
['trigger', 'setBusy'],
|
|
126
|
+
['setBusy', 'formValid'],
|
|
127
|
+
['formValid', 'formToast', 'false'],
|
|
128
|
+
['formValid', 'fetchStock', 'true'],
|
|
129
|
+
['fetchStock', 'checkStock'],
|
|
130
|
+
['checkStock', 'inStock'],
|
|
131
|
+
['inStock', 'stockToast', 'false'],
|
|
132
|
+
['stockToast', 'stockReset'],
|
|
133
|
+
['inStock', 'resolveUser', 'true'],
|
|
134
|
+
['resolveUser', 'loadDiscounts'],
|
|
135
|
+
['loadDiscounts', 'countOrders'],
|
|
136
|
+
['countOrders', 'recheckVoucher'],
|
|
137
|
+
['recheckVoucher', 'voucherValid'],
|
|
138
|
+
['voucherValid', 'forgetVoucher', 'false'],
|
|
139
|
+
['forgetVoucher', 'voucherToast'],
|
|
140
|
+
['voucherToast', 'voucherReset'],
|
|
141
|
+
['voucherReset', 'voucherClear'],
|
|
142
|
+
['voucherValid', 'priceOrder', 'true'],
|
|
143
|
+
['priceOrder', 'assemble'],
|
|
144
|
+
['assemble', 'checkAddress'],
|
|
145
|
+
['checkAddress', 'canBill'],
|
|
146
|
+
['canBill', 'billToast', 'false'],
|
|
147
|
+
['billToast', 'billReset'],
|
|
148
|
+
['canBill', 'createOrder', 'true'],
|
|
149
|
+
['createOrder', 'redeem'],
|
|
150
|
+
['redeem', 'redeemed'],
|
|
151
|
+
['redeemed', 'cancelOrder', 'false'],
|
|
152
|
+
['cancelOrder', 'redeemToast'],
|
|
153
|
+
['redeemed', 'orderNumber', 'true'],
|
|
154
|
+
['orderNumber', 'eachLine'],
|
|
155
|
+
['eachLine', 'buildLine', 'loop', 'loop-body-in'],
|
|
156
|
+
['buildLine', 'saveLine'],
|
|
157
|
+
['saveLine', 'eachLine', 'loop-body-out', 'loop-back'],
|
|
158
|
+
['eachLine', 'decrementStock', 'exit'],
|
|
159
|
+
['decrementStock', 'recordPlaced'],
|
|
160
|
+
['recordPlaced', 'saveDetails'],
|
|
161
|
+
['saveDetails', 'settled'],
|
|
162
|
+
['settled', 'markSettled', 'true'],
|
|
163
|
+
['markSettled', 'clearCart'],
|
|
164
|
+
['clearCart', 'emailPayload'],
|
|
165
|
+
['emailPayload', 'sendEmail'],
|
|
166
|
+
['sendEmail', 'goToOrder'],
|
|
167
|
+
['settled', 'redirectUrls', 'false'],
|
|
168
|
+
['redirectUrls', 'charge'],
|
|
169
|
+
['charge', 'opened'],
|
|
170
|
+
['opened', 'cancelRefused', 'false'],
|
|
171
|
+
['cancelRefused', 'refusedToast'],
|
|
172
|
+
['opened', 'recordCheckout', 'true'],
|
|
173
|
+
['recordCheckout', 'sendToCheckout'],
|
|
174
|
+
]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
const REFUSALS = [
|
|
178
|
+
'formToast',
|
|
179
|
+
'stockToast',
|
|
180
|
+
'stockReset',
|
|
181
|
+
'forgetVoucher',
|
|
182
|
+
'voucherToast',
|
|
183
|
+
'voucherReset',
|
|
184
|
+
'voucherClear',
|
|
185
|
+
'billToast',
|
|
186
|
+
'billReset',
|
|
187
|
+
'cancelOrder',
|
|
188
|
+
'redeemToast',
|
|
189
|
+
'cancelRefused',
|
|
190
|
+
'refusedToast',
|
|
191
|
+
]
|
|
192
|
+
const CASH_ONLY = ['markSettled', 'clearCart', 'emailPayload', 'sendEmail', 'goToOrder']
|
|
193
|
+
const ONLINE_ONLY = ['redirectUrls', 'charge', 'opened', 'recordCheckout', 'sendToCheckout']
|
|
194
|
+
|
|
195
|
+
// The server segments an order that every gate accepts calls, in order.
|
|
196
|
+
const roundTrips = (segments: WorkflowSegment[], skipped: string[]): string[][] =>
|
|
197
|
+
segments
|
|
198
|
+
.filter((s) => s.env === 'server')
|
|
199
|
+
.map((s) => s.nodes.map((n) => n.id).filter((id) => !skipped.includes(id)))
|
|
200
|
+
.filter((ids) => ids.length > 0)
|
|
201
|
+
|
|
202
|
+
const segmentOf = (segments: WorkflowSegment[], id: string): WorkflowSegment =>
|
|
203
|
+
segments.find((s) => s.nodes.some((n) => n.id === id)) as WorkflowSegment
|
|
204
|
+
|
|
205
|
+
describe('splitIntoSegments — a checkout waits on as few server round trips as it can', () => {
|
|
206
|
+
const segments = splitIntoSegments(placeOrder)
|
|
207
|
+
|
|
208
|
+
it('calls the server once between each pair of steps that need the browser', () => {
|
|
209
|
+
// Browser steps on the accepted path: resolveUser (custom node) and
|
|
210
|
+
// recordPlaced (custom node) — plus clearCart for a cash order.
|
|
211
|
+
expect(roundTrips(segments, [...REFUSALS, ...ONLINE_ONLY])).toEqual([
|
|
212
|
+
['fetchStock', 'checkStock', 'inStock'],
|
|
213
|
+
[
|
|
214
|
+
'loadDiscounts',
|
|
215
|
+
'countOrders',
|
|
216
|
+
'recheckVoucher',
|
|
217
|
+
'voucherValid',
|
|
218
|
+
'priceOrder',
|
|
219
|
+
'assemble',
|
|
220
|
+
'checkAddress',
|
|
221
|
+
'canBill',
|
|
222
|
+
'createOrder',
|
|
223
|
+
'redeem',
|
|
224
|
+
'redeemed',
|
|
225
|
+
'orderNumber',
|
|
226
|
+
'eachLine',
|
|
227
|
+
'buildLine',
|
|
228
|
+
'saveLine',
|
|
229
|
+
'decrementStock',
|
|
230
|
+
],
|
|
231
|
+
['saveDetails', 'settled', 'markSettled'],
|
|
232
|
+
['emailPayload', 'sendEmail'],
|
|
233
|
+
])
|
|
234
|
+
expect(roundTrips(segments, [...REFUSALS, ...CASH_ONLY])).toHaveLength(3)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('decides every gate that reads a server step inside the server route', () => {
|
|
238
|
+
// A gate the browser decides is one a crafted request can answer: the
|
|
239
|
+
// route then takes the browser's word for which branch was skipped.
|
|
240
|
+
for (const gate of ['inStock', 'voucherValid', 'canBill', 'redeemed', 'settled', 'opened']) {
|
|
241
|
+
expect(segmentOf(segments, gate).env).toBe('server')
|
|
242
|
+
}
|
|
243
|
+
// A refusal step on the server shares its gate's route, which skips it itself.
|
|
244
|
+
expect(segmentOf(segments, 'cancelOrder')).toBe(segmentOf(segments, 'redeemed'))
|
|
245
|
+
expect(segmentOf(segments, 'cancelRefused')).toBe(segmentOf(segments, 'opened'))
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('keeps the loop and its body in one segment, in order', () => {
|
|
249
|
+
const loopSegment = segmentOf(segments, 'eachLine')
|
|
250
|
+
const ids = loopSegment.nodes.map((n) => n.id)
|
|
251
|
+
expect(ids.slice(ids.indexOf('eachLine'), ids.indexOf('eachLine') + 3)).toEqual([
|
|
252
|
+
'eachLine',
|
|
253
|
+
'buildLine',
|
|
254
|
+
'saveLine',
|
|
255
|
+
])
|
|
256
|
+
expect(ids.indexOf('decrementStock')).toBeGreaterThan(ids.indexOf('saveLine'))
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('runs every step after everything it depends on', () => {
|
|
260
|
+
const order = segments.flatMap((s) => s.nodes.map((n) => n.id))
|
|
261
|
+
for (const e of placeOrder.edges) {
|
|
262
|
+
if (e.targetHandle === 'loop-back' || e.source === 'trigger') {
|
|
263
|
+
continue
|
|
264
|
+
}
|
|
265
|
+
expect([e.source, order.indexOf(e.source) < order.indexOf(e.target)]).toEqual([
|
|
266
|
+
e.source,
|
|
267
|
+
true,
|
|
268
|
+
])
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
describe('splitIntoSegments — a server route runs its steps by step number', () => {
|
|
274
|
+
it('never puts a step in the segment of an input with a later step number', () => {
|
|
275
|
+
// `total` hangs off the trigger (step 1) but reads `line3` (step 3): the
|
|
276
|
+
// route, which sorts its segment by step, would run it before that value.
|
|
277
|
+
const workflow = {
|
|
278
|
+
id: 'w',
|
|
279
|
+
name: 'w',
|
|
280
|
+
trigger: { type: 'event-element-clicked', nodeId: 'trigger' },
|
|
281
|
+
nodes: [
|
|
282
|
+
{ id: 'line1', type: 'data-select', stepNumber: 1, executionEnv: 'server', config: {} },
|
|
283
|
+
{ id: 'line2', type: 'data-select', stepNumber: 2, executionEnv: 'server', config: {} },
|
|
284
|
+
{ id: 'line3', type: 'data-select', stepNumber: 3, executionEnv: 'server', config: {} },
|
|
285
|
+
{
|
|
286
|
+
id: 'total',
|
|
287
|
+
type: 'data-create-item',
|
|
288
|
+
stepNumber: 1,
|
|
289
|
+
executionEnv: 'server',
|
|
290
|
+
config: { columnMappings: [{ value: { type: 'workflowContext', nodeId: 'line3' } }] },
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
edges: [
|
|
294
|
+
{ id: 'e0', source: 'trigger', target: 'line1' },
|
|
295
|
+
{ id: 'e1', source: 'line1', target: 'line2' },
|
|
296
|
+
{ id: 'e2', source: 'line2', target: 'line3' },
|
|
297
|
+
{ id: 'e3', source: 'trigger', target: 'total' },
|
|
298
|
+
],
|
|
299
|
+
} as unknown as UIDLWorkflow
|
|
300
|
+
const segments = splitIntoSegments(workflow)
|
|
301
|
+
expect(segments.map((s) => [s.env, s.nodes.map((n) => n.id)])).toEqual([
|
|
302
|
+
['server', ['line1', 'line2', 'line3']],
|
|
303
|
+
['server', ['total']],
|
|
304
|
+
])
|
|
305
|
+
})
|
|
306
|
+
})
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
// reproduced live against a published chat bundle.
|
|
16
16
|
//
|
|
17
17
|
// The fix: emitted nodes carry `executionEnv`, and the client runtime filters
|
|
18
|
-
// on-stream
|
|
19
|
-
//
|
|
18
|
+
// on-stream branch execution down to client-executable nodes. Server branch
|
|
19
|
+
// nodes stay server-side where they already run with full configs. The on-end
|
|
20
|
+
// branch is no longer run by the 'done' handler at all: its steps run in their
|
|
21
|
+
// own segments, in edge order (see streaming-on-end-order.test.ts).
|
|
20
22
|
|
|
21
23
|
import {
|
|
22
24
|
generateSharedRuntimeUtilsCode,
|
|
@@ -167,7 +169,7 @@ describe('callStreamingServerSegment — on-stream/on-end env filter', () => {
|
|
|
167
169
|
global.fetch = originalFetch
|
|
168
170
|
})
|
|
169
171
|
|
|
170
|
-
it('
|
|
172
|
+
it('runs the on-stream client nodes per chunk and leaves the whole on-end branch to its segments', async () => {
|
|
171
173
|
const { runtime } = loadRuntimeModules()
|
|
172
174
|
const nodes = clientBundleNodes()
|
|
173
175
|
const edges = workflowEdges()
|
|
@@ -211,20 +213,15 @@ describe('callStreamingServerSegment — on-stream/on-end env filter', () => {
|
|
|
211
213
|
'exec-1'
|
|
212
214
|
)
|
|
213
215
|
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
expect(calls).
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
expect(
|
|
220
|
-
// All on-end branch nodes stay marked handled so later client segments
|
|
221
|
-
// do not re-run them (unchanged bookkeeping semantics).
|
|
222
|
-
expect(handled[ON_END_SERVER_JS_ID]).toBe(true)
|
|
223
|
-
expect(handled[ON_END_SERVER_SQL_ID]).toBe(true)
|
|
224
|
-
expect(handled[ON_END_CLIENT_ID]).toBe(true)
|
|
216
|
+
// Only the on-stream state update ran; server nodes never ran with client
|
|
217
|
+
// handlers, and the on-end client node waits for the server steps before it.
|
|
218
|
+
expect(calls).toEqual(['state:answer'])
|
|
219
|
+
expect(handled[ON_STREAM_CLIENT_ID]).toBe(true)
|
|
220
|
+
// Not marked handled, so its own client segment still runs it.
|
|
221
|
+
expect(handled[ON_END_CLIENT_ID]).toBeUndefined()
|
|
225
222
|
})
|
|
226
223
|
|
|
227
|
-
it('keeps executing
|
|
224
|
+
it('keeps executing on-stream nodes WITHOUT an executionEnv marker (older bundles)', async () => {
|
|
228
225
|
const { runtime } = loadRuntimeModules()
|
|
229
226
|
const nodes = clientBundleNodes().map((n) => {
|
|
230
227
|
const { executionEnv, ...rest } = n
|
|
@@ -268,9 +265,12 @@ describe('callStreamingServerSegment — on-stream/on-end env filter', () => {
|
|
|
268
265
|
'exec-2'
|
|
269
266
|
)
|
|
270
267
|
|
|
271
|
-
// Fail-open:
|
|
272
|
-
expect(calls).toContain('
|
|
273
|
-
|
|
268
|
+
// Fail-open: an unmarked on-stream node still runs per chunk.
|
|
269
|
+
expect(calls).toContain('state:answer')
|
|
270
|
+
// The on-end branch runs in its own segments, marker or not.
|
|
271
|
+
expect(calls).not.toContain('general-custom-js')
|
|
272
|
+
expect(calls).not.toContain('data-raw-query')
|
|
273
|
+
expect(calls).not.toContain('state:done')
|
|
274
274
|
})
|
|
275
275
|
})
|
|
276
276
|
|