@open-mercato/core 0.6.6-develop.6551.1.1511bfa890 → 0.6.7-develop.6552.1.5208a19369

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -1
  3. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  4. package/dist/modules/workflows/lib/activity-executor.js +1 -1
  5. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  6. package/dist/modules/workflows/lib/find-definition.js +18 -2
  7. package/dist/modules/workflows/lib/find-definition.js.map +2 -2
  8. package/dist/modules/workflows/lib/signal-handler.js +3 -2
  9. package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
  10. package/dist/modules/workflows/lib/step-handler.js +4 -8
  11. package/dist/modules/workflows/lib/step-handler.js.map +2 -2
  12. package/dist/modules/workflows/lib/task-handler.js +3 -5
  13. package/dist/modules/workflows/lib/task-handler.js.map +2 -2
  14. package/dist/modules/workflows/lib/timer-handler.js +2 -1
  15. package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
  16. package/dist/modules/workflows/lib/transition-handler.js +5 -13
  17. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  18. package/dist/modules/workflows/lib/workflow-executor.js +11 -9
  19. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  20. package/dist/modules/workflows/migrations/Migration20260715120000.js +68 -0
  21. package/dist/modules/workflows/migrations/Migration20260715120000.js.map +7 -0
  22. package/dist/modules/workflows/migrations/Migration20260716120000.js +24 -0
  23. package/dist/modules/workflows/migrations/Migration20260716120000.js.map +7 -0
  24. package/dist/modules/workflows/workflows.js +2 -0
  25. package/dist/modules/workflows/workflows.js.map +2 -2
  26. package/package.json +8 -8
  27. package/src/modules/workflows/frontend/checkout-demo/page.tsx +12 -1
  28. package/src/modules/workflows/lib/activity-executor.ts +22 -2
  29. package/src/modules/workflows/lib/find-definition.ts +53 -1
  30. package/src/modules/workflows/lib/signal-handler.ts +5 -4
  31. package/src/modules/workflows/lib/step-handler.ts +4 -8
  32. package/src/modules/workflows/lib/task-handler.ts +2 -4
  33. package/src/modules/workflows/lib/timer-handler.ts +3 -2
  34. package/src/modules/workflows/lib/transition-handler.ts +5 -13
  35. package/src/modules/workflows/lib/workflow-executor.ts +11 -8
  36. package/src/modules/workflows/migrations/Migration20260715120000.ts +114 -0
  37. package/src/modules/workflows/migrations/Migration20260716120000.ts +57 -0
  38. package/src/modules/workflows/workflows.ts +2 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/workflows/migrations/Migration20260716120000.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations'\n\nconst CODE_WORKFLOW_ID = 'workflows.checkout-demo'\n\n/**\n * Retires the persisted checkout-demo seed rows so runtime resolves the\n * maintained CODE definition instead (issue #4211).\n *\n * Background: `workflows.checkout-demo` is now code-defined\n * (`packages/core/src/modules/workflows/workflows.ts`), and only the code\n * definition forwards the cart's line items + shipping/tax adjustments to\n * `POST /api/sales/orders`. But existing tenants still carry a persisted\n * `workflow_definitions` row from the old seed \u2014 originally seeded under ids\n * like `checkout_simple_v1` / names like `Simple Checkout Flow` and later\n * `Checkout with Payment Webhook`, then renamed to `workflows.checkout-demo`\n * by Migration20260428102318. Its `create_order` body never sent `lines`, and\n * because `findWorkflowDefinition` resolves the DB row first, that stale row\n * SHADOWS the code definition \u2014 so orders come out with zero line items and\n * $0.00 totals. Patching the persisted body is unreliable: the seed's name and\n * body shape vary across historical versions, so a fingerprint on either misses\n * whole cohorts of tenants (the defect QA hit).\n *\n * Instead, soft-delete the seeded rows. This is body/name-agnostic, so it fixes\n * every historical seed variant:\n * - New instances: `findWorkflowDefinition` filters `deleted_at IS NULL`, so\n * the retired row is skipped and the code definition is used (correct body).\n * - In-flight instances: `findDefinitionForInstance` loads the definition by\n * `id` with no soft-delete filter (WorkflowDefinition has no global filter),\n * so instances that reference the row keep resolving and advancing.\n *\n * Scope is limited to `code_workflow_id IS NULL` rows \u2014 user customizations of\n * the code definition set `code_workflow_id` and MUST NOT be retired. The\n * `deleted_at IS NULL` guard makes the migration idempotent.\n */\nexport function buildRetireSeededCheckoutDemoSql(): string {\n return `\n update \"workflow_definitions\" as \"wf\"\n set \"deleted_at\" = current_timestamp,\n \"updated_at\" = current_timestamp\n where \"wf\".\"workflow_id\" = '${CODE_WORKFLOW_ID}'\n and \"wf\".\"code_workflow_id\" is null\n and \"wf\".\"deleted_at\" is null;\n `.trim()\n}\n\nexport class Migration20260716120000 extends Migration {\n override async up(): Promise<void> {\n this.addSql(buildRetireSeededCheckoutDemoSql())\n }\n\n override async down(): Promise<void> {\n // Forward-only. Restoring `deleted_at = null` would re-shadow the maintained\n // code definition with the stale seed body and re-introduce zero-line orders\n // (#4211). The code definition supersedes the seed, so there is nothing to\n // restore.\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAE1B,MAAM,mBAAmB;AAgClB,SAAS,mCAA2C;AACzD,SAAO;AAAA;AAAA;AAAA;AAAA,kCAIyB,gBAAgB;AAAA;AAAA;AAAA,IAG9C,KAAK;AACT;AAEO,MAAM,gCAAgC,UAAU;AAAA,EACrD,MAAe,KAAoB;AACjC,SAAK,OAAO,iCAAiC,CAAC;AAAA,EAChD;AAAA,EAEA,MAAe,OAAsB;AAAA,EAKrC;AACF;",
6
+ "names": []
7
+ }
@@ -222,6 +222,8 @@ const checkoutDemo = defineWorkflow({
222
222
  customerEntityId: "{{context.customer.id}}",
223
223
  currencyCode: "{{context.cart.currency}}",
224
224
  placedAt: "{{now}}",
225
+ lines: "{{context.cart.orderLines}}",
226
+ adjustments: "{{context.cart.orderAdjustments}}",
225
227
  grandTotalGrossAmount: "{{context.cart.total}}"
226
228
  },
227
229
  validateTenantMatch: true
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/workflows/workflows.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module \u2014 Code-Based Workflow Definitions\n *\n * Demo workflows shipped with the workflows module.\n * These are auto-discovered by the generator and loaded into the in-memory registry.\n */\n\nimport { defineWorkflow, createWorkflowsModuleConfig } from '@open-mercato/shared/modules/workflows'\n\n// ============================================================================\n// Simple Approval Workflow\n// ============================================================================\n\nconst simpleApproval = defineWorkflow({\n workflowId: 'workflows.simple-approval',\n workflowName: 'Simple Approval Workflow',\n description: 'Basic three-step approval workflow: Start \u2192 Approval \u2192 End',\n metadata: { category: 'Testing', tags: ['test', 'approval', 'simple'], icon: 'check-circle' },\n steps: [\n { stepId: 'start', stepName: 'Start', stepType: 'START', description: 'Initialize workflow' },\n {\n stepId: 'approval',\n stepName: 'Pending Approval',\n stepType: 'USER_TASK',\n description: 'Approve or reject request',\n userTaskConfig: { assignedTo: 'approver', slaDuration: 'PT1H' },\n },\n { stepId: 'end', stepName: 'Complete', stepType: 'END', description: 'Workflow complete' },\n ] as const,\n transitions: [\n {\n transitionId: 'start_to_approval',\n transitionName: 'Submit for Approval',\n fromStepId: 'start',\n toStepId: 'approval',\n trigger: 'auto',\n priority: 100,\n activities: [\n {\n activityId: 'notify_approver',\n activityName: 'Notify Approver',\n activityType: 'SEND_EMAIL',\n config: {\n to: '{{context.approver.email}}',\n subject: 'Approval Required: {{context.request.title}}',\n template: 'approval_request',\n data: {\n requestId: '{{context.request.id}}',\n title: '{{context.request.title}}',\n requester: '{{context.requester.name}}',\n },\n },\n timeout: 'PT10S',\n async: true,\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 2000, backoffCoefficient: 2, maxIntervalMs: 20000 },\n },\n {\n activityId: 'emit_approval_requested',\n activityName: 'Emit Approval Requested Event',\n activityType: 'EMIT_EVENT',\n config: {\n eventType: 'approval.requested',\n payload: { requestId: '{{context.request.id}}', workflowInstanceId: '{{workflow.instanceId}}' },\n },\n async: true,\n },\n ],\n },\n {\n transitionId: 'approval_to_end',\n transitionName: 'Approval Decision',\n fromStepId: 'approval',\n toStepId: 'end',\n trigger: 'manual',\n priority: 100,\n activities: [\n {\n activityId: 'notify_requester',\n activityName: 'Notify Requester of Decision',\n activityType: 'SEND_EMAIL',\n config: {\n to: '{{context.requester.email}}',\n subject: 'Approval Decision: {{context.request.title}}',\n template: 'approval_decision',\n data: {\n requestId: '{{context.request.id}}',\n title: '{{context.request.title}}',\n decision: '{{task.result.approved}}',\n comments: '{{task.result.comments}}',\n approver: '{{task.completedBy}}',\n },\n },\n timeout: 'PT10S',\n async: true,\n },\n {\n activityId: 'emit_approval_completed',\n activityName: 'Emit Approval Completed Event',\n activityType: 'EMIT_EVENT',\n config: {\n eventType: 'approval.completed',\n payload: {\n requestId: '{{context.request.id}}',\n approved: '{{task.result.approved}}',\n approvedBy: '{{task.completedBy}}',\n timestamp: '{{now}}',\n },\n },\n async: true,\n },\n ],\n },\n ],\n})\n\n// ============================================================================\n// Checkout Demo Workflow\n// ============================================================================\n\nconst checkoutDemo = defineWorkflow({\n workflowId: 'workflows.checkout-demo',\n workflowName: 'Checkout with Payment Webhook',\n description: 'Realistic checkout workflow with signal-based payment confirmation',\n metadata: { category: 'E-commerce', tags: ['checkout', 'demo', 'payments', 'signals'], icon: 'ShoppingCart' },\n steps: [\n {\n stepId: 'start',\n stepName: 'Start',\n stepType: 'START',\n description: 'Checkout process initiated',\n preConditions: [{\n ruleId: 'workflow_checkout_cart_not_empty',\n required: true,\n validationMessage: {\n en: 'Your shopping cart is empty. Please add items before starting checkout.',\n pl: 'Tw\u00F3j koszyk jest pusty. Dodaj produkty przed rozpocz\u0119ciem zakupu.',\n },\n }],\n },\n { stepId: 'cart_validation', stepName: 'Cart Validation', stepType: 'AUTOMATED', description: 'Validate cart has items and inventory is available', timeout: 'PT10S' },\n {\n stepId: 'customer_info',\n stepName: 'Customer Information',\n stepType: 'USER_TASK',\n description: 'Collect customer shipping and contact information',\n userTaskConfig: {\n formSchema: {\n type: 'object',\n properties: {\n fullName: { type: 'string', title: 'Full Name', description: \"Customer's full legal name\" },\n email: { type: 'string', format: 'email', title: 'Email Address', description: 'Email for order confirmation' },\n phone: { type: 'string', title: 'Phone Number', description: 'Contact number for delivery' },\n comment: { type: 'string', title: 'Order Comment', maxLength: 500, description: 'Special instructions or notes' },\n },\n required: ['fullName', 'email'],\n },\n slaDuration: 'PT24H',\n },\n },\n { stepId: 'payment_initiation', stepName: 'Initiate Payment', stepType: 'AUTOMATED', description: 'Send payment request to payment provider', timeout: 'PT10S' },\n {\n stepId: 'wait_payment_confirmation',\n stepName: 'Wait for Payment Confirmation',\n stepType: 'WAIT_FOR_SIGNAL',\n description: 'Waiting for payment provider webhook confirmation',\n signalConfig: { signalName: 'payment_confirmed', timeout: 'PT5M' },\n },\n { stepId: 'order_confirmation', stepName: 'Order Confirmation', stepType: 'AUTOMATED', description: 'Create order record and send confirmation', timeout: 'PT15S' },\n { stepId: 'end', stepName: 'Complete', stepType: 'END', description: 'Checkout completed successfully' },\n ] as const,\n transitions: [\n {\n transitionId: 'start_to_cart',\n transitionName: 'Initialize Checkout',\n fromStepId: 'start',\n toStepId: 'cart_validation',\n trigger: 'auto',\n priority: 100,\n activities: [{\n activityId: 'log_checkout_start',\n activityName: 'Log Checkout Start',\n activityType: 'EMIT_EVENT',\n config: {\n eventName: 'checkout.started',\n payload: { customerId: '{{context.customerId}}', cartId: '{{context.cartId}}', currency: '{{context.currency}}', timestamp: '{{now}}' },\n },\n async: false,\n }],\n },\n {\n transitionId: 'cart_to_customer_info',\n transitionName: 'Collect Customer Information',\n fromStepId: 'cart_validation',\n toStepId: 'customer_info',\n trigger: 'auto',\n priority: 100,\n preConditions: [{ ruleId: 'workflow_checkout_cart_not_empty', required: true }],\n },\n {\n transitionId: 'customer_info_to_payment',\n transitionName: 'Initiate Payment',\n fromStepId: 'customer_info',\n toStepId: 'payment_initiation',\n trigger: 'auto',\n priority: 100,\n },\n {\n transitionId: 'payment_to_wait_confirmation',\n transitionName: 'Wait for Confirmation',\n fromStepId: 'payment_initiation',\n toStepId: 'wait_payment_confirmation',\n trigger: 'auto',\n priority: 100,\n },\n {\n transitionId: 'confirmation_to_order',\n transitionName: 'Payment Confirmed',\n fromStepId: 'wait_payment_confirmation',\n toStepId: 'order_confirmation',\n trigger: 'auto',\n priority: 100,\n },\n {\n transitionId: 'confirmation_to_end',\n transitionName: 'Finalize Order',\n fromStepId: 'order_confirmation',\n toStepId: 'end',\n trigger: 'auto',\n priority: 100,\n activities: [\n {\n activityId: 'create_order',\n activityName: 'Create Order Record',\n activityType: 'CALL_API',\n config: {\n endpoint: '/api/sales/orders',\n method: 'POST',\n body: {\n customerEntityId: '{{context.customer.id}}',\n currencyCode: '{{context.cart.currency}}',\n placedAt: '{{now}}',\n grandTotalGrossAmount: '{{context.cart.total}}',\n },\n validateTenantMatch: true,\n },\n timeout: 'PT10S',\n async: false,\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 2000, backoffCoefficient: 2, maxIntervalMs: 10000 },\n },\n {\n activityId: 'send_confirmation_email',\n activityName: 'Send Order Confirmation Email',\n activityType: 'SEND_EMAIL',\n config: {\n to: '{{context.customer.email}}',\n subject: 'Order Confirmation',\n template: 'order_confirmation',\n data: { customerName: '{{context.customer.name}}', total: '{{context.cart.total}}' },\n },\n timeout: 'PT15S',\n async: true,\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 2000, backoffCoefficient: 2, maxIntervalMs: 20000 },\n },\n ],\n },\n ],\n})\n\n// ============================================================================\n// Module Export\n// ============================================================================\n\nexport const workflowsConfig = createWorkflowsModuleConfig({\n moduleId: 'workflows',\n workflows: [simpleApproval, checkoutDemo],\n})\n\nexport default workflowsConfig\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module \u2014 Code-Based Workflow Definitions\n *\n * Demo workflows shipped with the workflows module.\n * These are auto-discovered by the generator and loaded into the in-memory registry.\n */\n\nimport { defineWorkflow, createWorkflowsModuleConfig } from '@open-mercato/shared/modules/workflows'\n\n// ============================================================================\n// Simple Approval Workflow\n// ============================================================================\n\nconst simpleApproval = defineWorkflow({\n workflowId: 'workflows.simple-approval',\n workflowName: 'Simple Approval Workflow',\n description: 'Basic three-step approval workflow: Start \u2192 Approval \u2192 End',\n metadata: { category: 'Testing', tags: ['test', 'approval', 'simple'], icon: 'check-circle' },\n steps: [\n { stepId: 'start', stepName: 'Start', stepType: 'START', description: 'Initialize workflow' },\n {\n stepId: 'approval',\n stepName: 'Pending Approval',\n stepType: 'USER_TASK',\n description: 'Approve or reject request',\n userTaskConfig: { assignedTo: 'approver', slaDuration: 'PT1H' },\n },\n { stepId: 'end', stepName: 'Complete', stepType: 'END', description: 'Workflow complete' },\n ] as const,\n transitions: [\n {\n transitionId: 'start_to_approval',\n transitionName: 'Submit for Approval',\n fromStepId: 'start',\n toStepId: 'approval',\n trigger: 'auto',\n priority: 100,\n activities: [\n {\n activityId: 'notify_approver',\n activityName: 'Notify Approver',\n activityType: 'SEND_EMAIL',\n config: {\n to: '{{context.approver.email}}',\n subject: 'Approval Required: {{context.request.title}}',\n template: 'approval_request',\n data: {\n requestId: '{{context.request.id}}',\n title: '{{context.request.title}}',\n requester: '{{context.requester.name}}',\n },\n },\n timeout: 'PT10S',\n async: true,\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 2000, backoffCoefficient: 2, maxIntervalMs: 20000 },\n },\n {\n activityId: 'emit_approval_requested',\n activityName: 'Emit Approval Requested Event',\n activityType: 'EMIT_EVENT',\n config: {\n eventType: 'approval.requested',\n payload: { requestId: '{{context.request.id}}', workflowInstanceId: '{{workflow.instanceId}}' },\n },\n async: true,\n },\n ],\n },\n {\n transitionId: 'approval_to_end',\n transitionName: 'Approval Decision',\n fromStepId: 'approval',\n toStepId: 'end',\n trigger: 'manual',\n priority: 100,\n activities: [\n {\n activityId: 'notify_requester',\n activityName: 'Notify Requester of Decision',\n activityType: 'SEND_EMAIL',\n config: {\n to: '{{context.requester.email}}',\n subject: 'Approval Decision: {{context.request.title}}',\n template: 'approval_decision',\n data: {\n requestId: '{{context.request.id}}',\n title: '{{context.request.title}}',\n decision: '{{task.result.approved}}',\n comments: '{{task.result.comments}}',\n approver: '{{task.completedBy}}',\n },\n },\n timeout: 'PT10S',\n async: true,\n },\n {\n activityId: 'emit_approval_completed',\n activityName: 'Emit Approval Completed Event',\n activityType: 'EMIT_EVENT',\n config: {\n eventType: 'approval.completed',\n payload: {\n requestId: '{{context.request.id}}',\n approved: '{{task.result.approved}}',\n approvedBy: '{{task.completedBy}}',\n timestamp: '{{now}}',\n },\n },\n async: true,\n },\n ],\n },\n ],\n})\n\n// ============================================================================\n// Checkout Demo Workflow\n// ============================================================================\n\nconst checkoutDemo = defineWorkflow({\n workflowId: 'workflows.checkout-demo',\n workflowName: 'Checkout with Payment Webhook',\n description: 'Realistic checkout workflow with signal-based payment confirmation',\n metadata: { category: 'E-commerce', tags: ['checkout', 'demo', 'payments', 'signals'], icon: 'ShoppingCart' },\n steps: [\n {\n stepId: 'start',\n stepName: 'Start',\n stepType: 'START',\n description: 'Checkout process initiated',\n preConditions: [{\n ruleId: 'workflow_checkout_cart_not_empty',\n required: true,\n validationMessage: {\n en: 'Your shopping cart is empty. Please add items before starting checkout.',\n pl: 'Tw\u00F3j koszyk jest pusty. Dodaj produkty przed rozpocz\u0119ciem zakupu.',\n },\n }],\n },\n { stepId: 'cart_validation', stepName: 'Cart Validation', stepType: 'AUTOMATED', description: 'Validate cart has items and inventory is available', timeout: 'PT10S' },\n {\n stepId: 'customer_info',\n stepName: 'Customer Information',\n stepType: 'USER_TASK',\n description: 'Collect customer shipping and contact information',\n userTaskConfig: {\n formSchema: {\n type: 'object',\n properties: {\n fullName: { type: 'string', title: 'Full Name', description: \"Customer's full legal name\" },\n email: { type: 'string', format: 'email', title: 'Email Address', description: 'Email for order confirmation' },\n phone: { type: 'string', title: 'Phone Number', description: 'Contact number for delivery' },\n comment: { type: 'string', title: 'Order Comment', maxLength: 500, description: 'Special instructions or notes' },\n },\n required: ['fullName', 'email'],\n },\n slaDuration: 'PT24H',\n },\n },\n { stepId: 'payment_initiation', stepName: 'Initiate Payment', stepType: 'AUTOMATED', description: 'Send payment request to payment provider', timeout: 'PT10S' },\n {\n stepId: 'wait_payment_confirmation',\n stepName: 'Wait for Payment Confirmation',\n stepType: 'WAIT_FOR_SIGNAL',\n description: 'Waiting for payment provider webhook confirmation',\n signalConfig: { signalName: 'payment_confirmed', timeout: 'PT5M' },\n },\n { stepId: 'order_confirmation', stepName: 'Order Confirmation', stepType: 'AUTOMATED', description: 'Create order record and send confirmation', timeout: 'PT15S' },\n { stepId: 'end', stepName: 'Complete', stepType: 'END', description: 'Checkout completed successfully' },\n ] as const,\n transitions: [\n {\n transitionId: 'start_to_cart',\n transitionName: 'Initialize Checkout',\n fromStepId: 'start',\n toStepId: 'cart_validation',\n trigger: 'auto',\n priority: 100,\n activities: [{\n activityId: 'log_checkout_start',\n activityName: 'Log Checkout Start',\n activityType: 'EMIT_EVENT',\n config: {\n eventName: 'checkout.started',\n payload: { customerId: '{{context.customerId}}', cartId: '{{context.cartId}}', currency: '{{context.currency}}', timestamp: '{{now}}' },\n },\n async: false,\n }],\n },\n {\n transitionId: 'cart_to_customer_info',\n transitionName: 'Collect Customer Information',\n fromStepId: 'cart_validation',\n toStepId: 'customer_info',\n trigger: 'auto',\n priority: 100,\n preConditions: [{ ruleId: 'workflow_checkout_cart_not_empty', required: true }],\n },\n {\n transitionId: 'customer_info_to_payment',\n transitionName: 'Initiate Payment',\n fromStepId: 'customer_info',\n toStepId: 'payment_initiation',\n trigger: 'auto',\n priority: 100,\n },\n {\n transitionId: 'payment_to_wait_confirmation',\n transitionName: 'Wait for Confirmation',\n fromStepId: 'payment_initiation',\n toStepId: 'wait_payment_confirmation',\n trigger: 'auto',\n priority: 100,\n },\n {\n transitionId: 'confirmation_to_order',\n transitionName: 'Payment Confirmed',\n fromStepId: 'wait_payment_confirmation',\n toStepId: 'order_confirmation',\n trigger: 'auto',\n priority: 100,\n },\n {\n transitionId: 'confirmation_to_end',\n transitionName: 'Finalize Order',\n fromStepId: 'order_confirmation',\n toStepId: 'end',\n trigger: 'auto',\n priority: 100,\n activities: [\n {\n activityId: 'create_order',\n activityName: 'Create Order Record',\n activityType: 'CALL_API',\n config: {\n endpoint: '/api/sales/orders',\n method: 'POST',\n body: {\n customerEntityId: '{{context.customer.id}}',\n currencyCode: '{{context.cart.currency}}',\n placedAt: '{{now}}',\n lines: '{{context.cart.orderLines}}',\n adjustments: '{{context.cart.orderAdjustments}}',\n grandTotalGrossAmount: '{{context.cart.total}}',\n },\n validateTenantMatch: true,\n },\n timeout: 'PT10S',\n async: false,\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 2000, backoffCoefficient: 2, maxIntervalMs: 10000 },\n },\n {\n activityId: 'send_confirmation_email',\n activityName: 'Send Order Confirmation Email',\n activityType: 'SEND_EMAIL',\n config: {\n to: '{{context.customer.email}}',\n subject: 'Order Confirmation',\n template: 'order_confirmation',\n data: { customerName: '{{context.customer.name}}', total: '{{context.cart.total}}' },\n },\n timeout: 'PT15S',\n async: true,\n retryPolicy: { maxAttempts: 3, initialIntervalMs: 2000, backoffCoefficient: 2, maxIntervalMs: 20000 },\n },\n ],\n },\n ],\n})\n\n// ============================================================================\n// Module Export\n// ============================================================================\n\nexport const workflowsConfig = createWorkflowsModuleConfig({\n moduleId: 'workflows',\n workflows: [simpleApproval, checkoutDemo],\n})\n\nexport default workflowsConfig\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6551.1.1511bfa890",
3
+ "version": "0.6.7-develop.6552.1.5208a19369",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -253,16 +253,16 @@
253
253
  "zod": "^4.4.3"
254
254
  },
255
255
  "peerDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.6-develop.6551.1.1511bfa890",
257
- "@open-mercato/shared": "0.6.6-develop.6551.1.1511bfa890",
258
- "@open-mercato/ui": "0.6.6-develop.6551.1.1511bfa890",
256
+ "@open-mercato/ai-assistant": "0.6.7-develop.6552.1.5208a19369",
257
+ "@open-mercato/shared": "0.6.7-develop.6552.1.5208a19369",
258
+ "@open-mercato/ui": "0.6.7-develop.6552.1.5208a19369",
259
259
  "react": "^19.0.0",
260
260
  "react-dom": "^19.0.0"
261
261
  },
262
262
  "devDependencies": {
263
- "@open-mercato/ai-assistant": "0.6.6-develop.6551.1.1511bfa890",
264
- "@open-mercato/shared": "0.6.6-develop.6551.1.1511bfa890",
265
- "@open-mercato/ui": "0.6.6-develop.6551.1.1511bfa890",
263
+ "@open-mercato/ai-assistant": "0.6.7-develop.6552.1.5208a19369",
264
+ "@open-mercato/shared": "0.6.7-develop.6552.1.5208a19369",
265
+ "@open-mercato/ui": "0.6.7-develop.6552.1.5208a19369",
266
266
  "@testing-library/dom": "^10.4.1",
267
267
  "@testing-library/jest-dom": "^6.9.1",
268
268
  "@testing-library/react": "^16.3.1",
@@ -286,5 +286,5 @@
286
286
  "url": "https://github.com/open-mercato/open-mercato",
287
287
  "directory": "packages/core"
288
288
  },
289
- "stableVersion": "0.6.5"
289
+ "stableVersion": "0.6.6"
290
290
  }
@@ -389,9 +389,20 @@ export default function CheckoutDemoPage() {
389
389
  currencyCode: selectedCurrency || 'USD', // Ensure currency is always set
390
390
  kind: 'product' as const,
391
391
  productId: item.id,
392
- lineDescription: item.name,
392
+ name: item.name,
393
393
  unitPriceGross: item.price,
394
394
  })),
395
+ // Fold the demo's shipping and tax into order-level adjustments so the
396
+ // created order's grand total matches the cart total shown to the user
397
+ // (line items alone only cover the product subtotal).
398
+ orderAdjustments: [
399
+ ...(shipping > 0
400
+ ? [{ kind: 'shipping' as const, label: 'Shipping', currencyCode: selectedCurrency || 'USD', amountGross: shipping }]
401
+ : []),
402
+ ...(tax > 0
403
+ ? [{ kind: 'tax' as const, label: 'Tax', currencyCode: selectedCurrency || 'USD', amountGross: tax }]
404
+ : []),
405
+ ],
395
406
  itemCount: demoCart.reduce((sum, item) => sum + item.quantity, 0),
396
407
  subtotal: subtotal,
397
408
  tax: tax,
@@ -929,8 +929,28 @@ export async function executeCallApi(
929
929
  // 3. Import the one-time API key helper
930
930
  const { withOnetimeApiKey } = await import('../../api_keys/services/apiKeyService')
931
931
 
932
- // 4. Get EntityManager from container (for correct type)
933
- const apiKeyEm = container.resolve<PostgreSqlEntityManager>('em')
932
+ // 4. Create the one-time API key on an EntityManager that is fully detached
933
+ // from the surrounding request/transaction context.
934
+ //
935
+ // CALL_API runs inside `workflowExecutor.executeWorkflow()`, which wraps
936
+ // the whole execution in `em.transactional(...)`. The request EM is forked
937
+ // with `useContext: true`, so while that transaction is open, EVERY
938
+ // operation on the container's `em` — including this API key's
939
+ // persist/flush — is transparently redirected to the uncommitted
940
+ // transaction fork (MikroORM `getContext()` → `TransactionContext`). The
941
+ // key would therefore stay invisible until the transaction commits, but
942
+ // the commit cannot happen until this activity returns. The outbound
943
+ // self-authenticated `fetch` below opens a SEPARATE DB connection that
944
+ // cannot see the uncommitted row, so the internal API responds `401` and
945
+ // the activity fails (issue #4202).
946
+ //
947
+ // Forking with `useContext: false` (matching the query_index/webhooks
948
+ // isolated-EM convention) gives the key its own pooled connection with
949
+ // autocommit, so it is committed and visible to the internal request
950
+ // immediately.
951
+ const apiKeyEm = container
952
+ .resolve<PostgreSqlEntityManager>('em')
953
+ .fork({ clear: true, freshEventManager: true, useContext: false }) as PostgreSqlEntityManager
934
954
 
935
955
  // 5. Resolve the roles that the one-time API key will inherit.
936
956
  //
@@ -80,9 +80,17 @@ export async function findWorkflowDefinition(
80
80
  // so disabled code workflows aren't silently executable.
81
81
  if (version === undefined && !codeDef.enabled) return null
82
82
 
83
+ return buildVirtualCodeDefinition(codeDef, tenantId, organizationId)
84
+ }
85
+
86
+ function buildVirtualCodeDefinition(
87
+ codeDef: NonNullable<ReturnType<typeof getCodeWorkflow>>,
88
+ tenantId: string,
89
+ organizationId: string,
90
+ ): WorkflowDefinition {
83
91
  // Construct a virtual WorkflowDefinition object (not persisted)
84
92
  const virtual = new WorkflowDefinition()
85
- virtual.id = codeWorkflowUuid(workflowId)
93
+ virtual.id = codeWorkflowUuid(codeDef.workflowId)
86
94
  virtual.workflowId = codeDef.workflowId
87
95
  virtual.workflowName = codeDef.workflowName
88
96
  virtual.description = codeDef.description ?? null
@@ -98,3 +106,47 @@ export async function findWorkflowDefinition(
98
106
 
99
107
  return virtual
100
108
  }
109
+
110
+ /**
111
+ * Resolve a virtual code definition for an already-started instance whose
112
+ * `definitionId` does not exist in the database.
113
+ *
114
+ * Instances started from a virtual code definition persist the deterministic
115
+ * `codeWorkflowUuid(workflowId)` as their `definitionId`. Runtime handlers
116
+ * (step/transition/signal/timer/task) load definitions by that id, so without
117
+ * this fallback an unpersisted code workflow starts but can never advance.
118
+ *
119
+ * The UUID equality gate ensures the fallback never substitutes the code
120
+ * definition for a hard-deleted persisted row: those rows have their own
121
+ * random UUIDs that can never match the deterministic code UUID.
122
+ */
123
+ export function resolveCodeDefinitionForInstance(instance: {
124
+ definitionId: string
125
+ workflowId: string
126
+ tenantId: string
127
+ organizationId: string
128
+ }): WorkflowDefinition | null {
129
+ const codeDef = getCodeWorkflow(instance.workflowId)
130
+ if (!codeDef) return null
131
+ if (codeWorkflowUuid(instance.workflowId) !== instance.definitionId) return null
132
+ return buildVirtualCodeDefinition(codeDef, instance.tenantId, instance.organizationId)
133
+ }
134
+
135
+ /**
136
+ * Find the definition backing a workflow instance: database row by id first,
137
+ * falling back to the in-memory code registry for instances started from an
138
+ * unpersisted code definition.
139
+ */
140
+ export async function findDefinitionForInstance(
141
+ em: EntityManager,
142
+ instance: {
143
+ definitionId: string
144
+ workflowId: string
145
+ tenantId: string
146
+ organizationId: string
147
+ },
148
+ ): Promise<WorkflowDefinition | null> {
149
+ const dbDef = await em.findOne(WorkflowDefinition, { id: instance.definitionId })
150
+ if (dbDef) return dbDef
151
+ return resolveCodeDefinitionForInstance(instance)
152
+ }
@@ -13,6 +13,7 @@ import type * as eventLoggerModule from './event-logger'
13
13
  import type * as stepHandlerModule from './step-handler'
14
14
  import type * as transitionHandlerModule from './transition-handler'
15
15
  import type * as workflowExecutorModule from './workflow-executor'
16
+ import { resolveCodeDefinitionForInstance } from './find-definition'
16
17
  import { createLogger } from '@open-mercato/shared/lib/logger'
17
18
 
18
19
  const logger = createLogger('workflows')
@@ -95,13 +96,13 @@ export async function sendSignal(
95
96
  // Branch-scoped signal: a FORKED instance routes the signal to the branch
96
97
  // paused at a matching WAIT_FOR_SIGNAL step.
97
98
  if (instance.status === 'FORKED') {
98
- const branchDefinition = await findOneWithDecryption(
99
+ const branchDefinition = (await findOneWithDecryption(
99
100
  em as PostgreSqlEntityManager,
100
101
  WorkflowDefinition,
101
102
  { id: instance.definitionId, tenantId: instance.tenantId, organizationId: instance.organizationId, deletedAt: null },
102
103
  undefined,
103
104
  { tenantId: instance.tenantId, organizationId: instance.organizationId },
104
- )
105
+ )) ?? resolveCodeDefinitionForInstance(instance)
105
106
  if (!branchDefinition) {
106
107
  throw new SignalError('Workflow definition not found', 'DEFINITION_NOT_FOUND', { definitionId: instance.definitionId })
107
108
  }
@@ -173,7 +174,7 @@ export async function sendSignal(
173
174
  }
174
175
 
175
176
  // Load workflow definition with tenant/org scope to check current step
176
- const definition = await findOneWithDecryption(
177
+ const definition = (await findOneWithDecryption(
177
178
  em as PostgreSqlEntityManager,
178
179
  WorkflowDefinition,
179
180
  {
@@ -184,7 +185,7 @@ export async function sendSignal(
184
185
  },
185
186
  undefined,
186
187
  { tenantId: instance.tenantId, organizationId: instance.organizationId },
187
- )
188
+ )) ?? resolveCodeDefinitionForInstance(instance)
188
189
  if (!definition) {
189
190
  throw new SignalError(
190
191
  'Workflow definition not found',
@@ -13,7 +13,6 @@ import { EntityManager } from '@mikro-orm/core'
13
13
  import {
14
14
  WorkflowInstance,
15
15
  WorkflowBranchInstance,
16
- WorkflowDefinition,
17
16
  StepInstance,
18
17
  UserTask,
19
18
  WorkflowEvent,
@@ -22,6 +21,7 @@ import {
22
21
  } from '../data/entities'
23
22
  import { parseDuration } from './duration'
24
23
  import { logWorkflowEvent } from './event-logger'
24
+ import { findDefinitionForInstance } from './find-definition'
25
25
  import { createLogger } from '@open-mercato/shared/lib/logger'
26
26
 
27
27
  const logger = createLogger('workflows')
@@ -76,9 +76,7 @@ export async function enterStep(
76
76
  branch?: WorkflowBranchInstance | null
77
77
  ): Promise<StepInstance> {
78
78
  // Load workflow definition to get step details
79
- const definition = await em.findOne(WorkflowDefinition, {
80
- id: instance.definitionId,
81
- })
79
+ const definition = await findDefinitionForInstance(em, instance)
82
80
 
83
81
  if (!definition) {
84
82
  throw new StepExecutionError(
@@ -213,9 +211,7 @@ export async function executeStep(
213
211
  const stepInstance = await enterStep(em, instance, stepId, context, branch)
214
212
 
215
213
  // Load workflow definition to get step configuration
216
- const definition = await em.findOne(WorkflowDefinition, {
217
- id: instance.definitionId,
218
- })
214
+ const definition = await findDefinitionForInstance(em, instance)
219
215
 
220
216
  if (!definition) {
221
217
  throw new StepExecutionError(
@@ -359,7 +355,7 @@ async function executeStepByType(
359
355
  { stepType, stepId: stepDef.stepId }
360
356
  )
361
357
  }
362
- const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })
358
+ const definition = await findDefinitionForInstance(em, instance)
363
359
  if (!definition) {
364
360
  throw new StepExecutionError(
365
361
  `Workflow definition not found: ${instance.definitionId}`,
@@ -17,9 +17,9 @@ import {
17
17
  WorkflowInstance,
18
18
  WorkflowEvent,
19
19
  StepInstance,
20
- WorkflowDefinition,
21
20
  } from '../data/entities'
22
21
  import { executeWorkflow } from './workflow-executor'
22
+ import { findDefinitionForInstance } from './find-definition'
23
23
  import * as stepHandler from './step-handler'
24
24
  import * as transitionHandler from './transition-handler'
25
25
  import { createLogger } from '@open-mercato/shared/lib/logger'
@@ -191,9 +191,7 @@ export async function completeUserTask(
191
191
  const currentStepId = instance.currentStepId
192
192
 
193
193
  // Load workflow definition to find transitions
194
- const definition = await em.findOne(WorkflowDefinition, {
195
- id: instance.definitionId,
196
- })
194
+ const definition = await findDefinitionForInstance(em, instance)
197
195
 
198
196
  if (!definition) {
199
197
  throw new UserTaskError(
@@ -14,6 +14,7 @@ import type * as eventLoggerModule from './event-logger'
14
14
  import type * as stepHandlerModule from './step-handler'
15
15
  import type * as transitionHandlerModule from './transition-handler'
16
16
  import type * as workflowExecutorModule from './workflow-executor'
17
+ import { resolveCodeDefinitionForInstance } from './find-definition'
17
18
 
18
19
  export interface FireTimerOptions {
19
20
  instanceId: string
@@ -110,7 +111,7 @@ export async function fireTimer(
110
111
  )
111
112
  }
112
113
 
113
- const definition = await findOneWithDecryption(
114
+ const definition = (await findOneWithDecryption(
114
115
  em as PostgreSqlEntityManager,
115
116
  WorkflowDefinition,
116
117
  {
@@ -121,7 +122,7 @@ export async function fireTimer(
121
122
  },
122
123
  undefined,
123
124
  { tenantId: instance.tenantId, organizationId: instance.organizationId },
124
- )
125
+ )) ?? resolveCodeDefinitionForInstance(instance)
125
126
  if (!definition) {
126
127
  throw new TimerError(
127
128
  'Workflow definition not found',
@@ -15,7 +15,6 @@ import type { AwilixContainer } from 'awilix'
15
15
  import type { EventBus } from '@open-mercato/events'
16
16
  import {
17
17
  WorkflowInstance,
18
- WorkflowDefinition,
19
18
  WorkflowEvent,
20
19
  } from '../data/entities'
21
20
  import * as ruleEvaluator from '../../business_rules/lib/rule-evaluator'
@@ -23,6 +22,7 @@ import * as ruleEngine from '../../business_rules/lib/rule-engine'
23
22
  import * as activityExecutor from './activity-executor'
24
23
  import type { ActivityDefinition } from './activity-executor'
25
24
  import * as stepHandler from './step-handler'
25
+ import { findDefinitionForInstance } from './find-definition'
26
26
  import {
27
27
  type ExecutionToken,
28
28
  rootToken,
@@ -116,9 +116,7 @@ export async function evaluateTransition(
116
116
 
117
117
  try {
118
118
  // Load workflow definition
119
- const definition = await em.findOne(WorkflowDefinition, {
120
- id: instance.definitionId,
121
- })
119
+ const definition = await findDefinitionForInstance(em, instance)
122
120
 
123
121
  if (!definition) {
124
122
  return {
@@ -227,9 +225,7 @@ export async function findValidTransitions(
227
225
  ): Promise<TransitionEvaluationResult[]> {
228
226
  try {
229
227
  // Load workflow definition
230
- const definition = await em.findOne(WorkflowDefinition, {
231
- id: instance.definitionId,
232
- })
228
+ const definition = await findDefinitionForInstance(em, instance)
233
229
 
234
230
  if (!definition) {
235
231
  return []
@@ -752,9 +748,7 @@ async function evaluatePreConditions(
752
748
  ): Promise<ruleEngine.RuleEngineResult> {
753
749
  try {
754
750
  // Load workflow definition to get workflow ID
755
- const definition = await em.findOne(WorkflowDefinition, {
756
- id: instance.definitionId,
757
- })
751
+ const definition = await findDefinitionForInstance(em, instance)
758
752
 
759
753
  if (!definition) {
760
754
  return {
@@ -881,9 +875,7 @@ async function evaluatePostConditions(
881
875
  ): Promise<ruleEngine.RuleEngineResult> {
882
876
  try {
883
877
  // Load workflow definition to get workflow ID
884
- const definition = await em.findOne(WorkflowDefinition, {
885
- id: instance.definitionId,
886
- })
878
+ const definition = await findDefinitionForInstance(em, instance)
887
879
 
888
880
  if (!definition) {
889
881
  return {
@@ -19,7 +19,7 @@ import {
19
19
  type WorkflowInstanceStatus,
20
20
  } from '../data/entities'
21
21
  import { compensateWorkflow } from './compensation-handler'
22
- import { findWorkflowDefinition } from './find-definition'
22
+ import { findWorkflowDefinition, findDefinitionForInstance } from './find-definition'
23
23
  import { createLogger } from '@open-mercato/shared/lib/logger'
24
24
 
25
25
  const logger = createLogger('workflows')
@@ -278,9 +278,7 @@ export async function executeWorkflow(
278
278
  )
279
279
  }
280
280
 
281
- const definition = await trx.findOne(WorkflowDefinition, {
282
- id: instance.definitionId,
283
- })
281
+ const definition = await findDefinitionForInstance(trx, instance)
284
282
 
285
283
  if (!definition) {
286
284
  throw new WorkflowExecutionError(
@@ -614,7 +612,7 @@ export async function completeWorkflow(
614
612
 
615
613
  // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)
616
614
  if (status === 'FAILED') {
617
- const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })
615
+ const definition = await findDefinitionForInstance(em, instance)
618
616
 
619
617
  if (definition && checkIfCompensationNeeded(definition)) {
620
618
  try {
@@ -836,9 +834,14 @@ export async function resumeWorkflowAfterActivities(
836
834
  fromStepId: instance.currentStepId,
837
835
  })
838
836
 
839
- const definition = await trx.findOneOrFail(WorkflowDefinition, {
840
- id: instance.definitionId,
841
- })
837
+ const definition = await findDefinitionForInstance(trx, instance)
838
+ if (!definition) {
839
+ throw new WorkflowExecutionError(
840
+ `Workflow definition not found: ${instance.definitionId}`,
841
+ 'DEFINITION_NOT_FOUND',
842
+ { definitionId: instance.definitionId }
843
+ )
844
+ }
842
845
 
843
846
  const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)
844
847
 
@@ -0,0 +1,114 @@
1
+ import { Migration } from '@mikro-orm/migrations'
2
+
3
+ const LEGACY_WORKFLOW_ID = 'workflows.checkout-demo'
4
+ const LEGACY_WORKFLOW_NAME = 'Checkout with Payment Webhook'
5
+ const LEGACY_ACTIVITY_ID = 'reserve_inventory'
6
+ const LEGACY_ACTIVITY_URL = '{{env.INVENTORY_SERVICE_URL}}/api/inventory/reserve'
7
+ const TRANSITIONS_REPLACED_BY_CODE_DEFINITION = [
8
+ 'cart_to_customer_info',
9
+ 'customer_info_to_payment',
10
+ 'confirmation_to_order',
11
+ ] as const
12
+
13
+ /**
14
+ * SQL fragment (for the UPDATE `where` clause) that matches ONLY the exact
15
+ * legacy checkout seed: workflow id, name, version, and the presence of the
16
+ * obsolete `reserve_inventory` `CALL_WEBHOOK` activity with its exact env-based
17
+ * URL. The match is intentionally strict so the repair never touches a row that
18
+ * is not the known-broken seed. A tenant whose persisted row diverges from this
19
+ * fingerprint (renamed, re-versioned, or a different webhook URL) is left
20
+ * untouched — the trade-off is safety over coverage for an unknown variant.
21
+ */
22
+ export function legacyCheckoutPredicate(): string {
23
+ return `
24
+ "wf"."workflow_id" = '${LEGACY_WORKFLOW_ID}'
25
+ and "wf"."workflow_name" = '${LEGACY_WORKFLOW_NAME}'
26
+ and "wf"."version" = 1
27
+ and exists (
28
+ select 1
29
+ from jsonb_array_elements(coalesce("wf"."definition"->'transitions', '[]'::jsonb)) as "transition"("value")
30
+ cross join lateral jsonb_array_elements(coalesce("transition"."value"->'activities', '[]'::jsonb)) as "activity"("value")
31
+ where "activity"."value"->>'activityId' = '${LEGACY_ACTIVITY_ID}'
32
+ and "activity"."value"->>'activityType' = 'CALL_WEBHOOK'
33
+ and "activity"."value"#>>'{config,url}' = '${LEGACY_ACTIVITY_URL}'
34
+ )
35
+ `.trim()
36
+ }
37
+
38
+ /**
39
+ * The exact UPDATE the migration runs. Exported so the DB-level regression test
40
+ * (`__integration__/TC-WF-031`) executes the identical SQL against Postgres,
41
+ * making the jsonb transformation itself — not just its rendered string —
42
+ * the thing under test.
43
+ *
44
+ * It rebuilds the `transitions` array in original order, dropping the
45
+ * `activities` key from exactly the three transitions the maintained code
46
+ * definition made side-effect-free. All other keys (e.g. `preConditions`) and
47
+ * all other transitions — including `confirmation_to_end`, whose remaining
48
+ * activities are internal (`CALL_API`/`SEND_EMAIL`/`EMIT_EVENT`) and never trip
49
+ * the outbound URL guard — are preserved verbatim.
50
+ */
51
+ export function buildLegacyCheckoutRepairSql(): string {
52
+ const strippedTransitionList = TRANSITIONS_REPLACED_BY_CODE_DEFINITION
53
+ .map((id) => `'${id}'`)
54
+ .join(', ')
55
+ return `
56
+ update "workflow_definitions" as "wf"
57
+ set "definition" = jsonb_set(
58
+ "wf"."definition",
59
+ '{transitions}',
60
+ coalesce(
61
+ (
62
+ select jsonb_agg(
63
+ case
64
+ when "transition"."value"->>'transitionId' in (${strippedTransitionList})
65
+ then "transition"."value" - 'activities'
66
+ else "transition"."value"
67
+ end
68
+ order by "transition"."ordinality"
69
+ )
70
+ from jsonb_array_elements(
71
+ coalesce("wf"."definition"->'transitions', '[]'::jsonb)
72
+ ) with ordinality as "transition"("value", "ordinality")
73
+ ),
74
+ '[]'::jsonb
75
+ )
76
+ ),
77
+ "updated_at" = current_timestamp
78
+ where "wf"."code_workflow_id" is null
79
+ and "wf"."deleted_at" is null
80
+ and ${legacyCheckoutPredicate()};
81
+ `.trim()
82
+ }
83
+
84
+ /**
85
+ * Repairs the former seeded checkout demo after it was renamed to the same ID
86
+ * as the code-defined workflow. The DB-first lookup shadows the current code
87
+ * definition, including its obsolete external inventory webhook.
88
+ *
89
+ * The persisted row must remain active because historical and in-flight
90
+ * workflow instances reference it by definition_id — a random UUID the
91
+ * code-registry fallback in find-definition.ts deliberately never substitutes.
92
+ * The migration removes the activity arrays from the three transitions that
93
+ * the maintained code definition intentionally made side-effect-free,
94
+ * preserving the row and all instance references while keeping the demo
95
+ * self-contained. (Fresh installs never had this row; they execute the virtual
96
+ * code definition directly via findDefinitionForInstance.)
97
+ *
98
+ * `confirmation_to_end` is deliberately NOT rebuilt: unlike the three stripped
99
+ * transitions it still holds activities in the maintained code definition, and
100
+ * its legacy-only extra (`emit_order_completed`, an internal `EMIT_EVENT`) is
101
+ * harmless — it emits no external request, so leaving it costs nothing and
102
+ * avoids fragile per-activity surgery that could re-introduce a failure.
103
+ */
104
+ export class Migration20260715120000 extends Migration {
105
+ override async up(): Promise<void> {
106
+ this.addSql(buildLegacyCheckoutRepairSql())
107
+ }
108
+
109
+ override async down(): Promise<void> {
110
+ // Forward-only data repair. The removed demo-only activity payloads cannot
111
+ // be reconstructed safely, and restoring obsolete external webhooks would
112
+ // re-open issue #4179.
113
+ }
114
+ }