@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.56

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 (476) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +11 -0
  3. package/dist/cjs/clients/fluent-client.js +13 -6
  4. package/dist/cjs/utils/pagination-helpers.js +38 -2
  5. package/dist/cjs/versori/fluent-versori-client.js +11 -5
  6. package/dist/esm/clients/fluent-client.js +13 -6
  7. package/dist/esm/utils/pagination-helpers.js +38 -2
  8. package/dist/esm/versori/fluent-versori-client.js +11 -5
  9. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  10. package/dist/tsconfig.tsbuildinfo +1 -1
  11. package/dist/tsconfig.types.tsbuildinfo +1 -1
  12. package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
  13. package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
  14. package/docs/00-START-HERE/cli-documentation-index.md +202 -202
  15. package/docs/00-START-HERE/cli-quick-reference.md +252 -252
  16. package/docs/00-START-HERE/decision-tree.md +552 -552
  17. package/docs/00-START-HERE/getting-started.md +1070 -1070
  18. package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
  19. package/docs/00-START-HERE/readme.md +237 -237
  20. package/docs/00-START-HERE/retailerid-configuration.md +404 -404
  21. package/docs/00-START-HERE/sdk-philosophy.md +794 -794
  22. package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
  23. package/docs/01-TEMPLATES/faq.md +686 -686
  24. package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
  25. package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
  26. package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
  27. package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
  28. package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
  29. package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
  30. package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
  31. package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
  32. package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
  33. package/docs/01-TEMPLATES/readme.md +957 -957
  34. package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
  35. package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
  36. package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
  37. package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
  38. package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
  39. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
  40. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
  41. package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
  42. package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
  43. package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
  44. package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
  45. package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
  46. package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
  47. package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
  48. package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
  49. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
  50. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
  51. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
  52. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
  53. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
  54. package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
  55. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
  56. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
  57. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
  58. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
  59. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
  60. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
  61. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
  62. package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
  63. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
  64. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
  65. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
  66. package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
  67. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
  68. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
  69. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
  70. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
  71. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
  72. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
  73. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
  74. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
  75. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
  76. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
  77. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
  78. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
  79. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
  80. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
  81. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
  82. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
  83. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
  84. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
  85. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
  86. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
  87. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
  88. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
  89. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
  90. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
  91. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
  92. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
  93. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
  94. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
  95. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
  96. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
  97. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
  98. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
  99. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
  100. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
  101. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
  102. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
  103. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
  104. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
  105. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
  106. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
  107. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
  108. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
  109. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
  110. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
  111. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
  112. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
  113. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
  114. package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
  115. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
  116. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
  117. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
  118. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
  119. package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
  120. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
  121. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
  122. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
  123. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
  124. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
  125. package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
  126. package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
  127. package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
  128. package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
  129. package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
  130. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
  131. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
  132. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
  133. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
  134. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
  135. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
  136. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
  137. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
  138. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
  139. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
  140. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
  141. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
  142. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
  143. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
  144. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
  145. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
  146. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
  147. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
  148. package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
  149. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
  150. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
  151. package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
  152. package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
  153. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
  154. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
  155. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
  156. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
  157. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
  158. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
  159. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
  160. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
  161. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
  162. package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
  163. package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
  164. package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
  165. package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
  166. package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
  167. package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
  168. package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
  169. package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
  170. package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
  171. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
  172. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
  173. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
  174. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
  175. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
  176. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
  177. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
  178. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
  179. package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
  180. package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
  181. package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
  182. package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
  183. package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
  184. package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
  185. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
  186. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
  187. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
  188. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
  189. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
  190. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
  191. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
  192. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
  193. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
  194. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
  195. package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
  196. package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
  197. package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
  198. package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
  199. package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
  200. package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
  201. package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
  202. package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
  203. package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
  204. package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
  205. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
  206. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
  207. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
  208. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
  209. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
  210. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
  211. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
  212. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
  213. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
  214. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
  215. package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
  216. package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
  217. package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
  218. package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
  219. package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
  220. package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
  221. package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
  222. package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
  223. package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
  224. package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
  225. package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
  226. package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
  227. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
  228. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
  229. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
  230. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
  231. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
  232. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
  233. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
  234. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
  235. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
  236. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
  237. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
  238. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
  239. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
  240. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
  241. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
  242. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
  243. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
  244. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
  245. package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
  246. package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
  247. package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
  248. package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
  249. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
  250. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
  251. package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
  252. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
  253. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
  254. package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
  255. package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
  256. package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
  257. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
  258. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
  259. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
  260. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
  261. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
  262. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
  263. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
  264. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
  265. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
  266. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
  267. package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
  268. package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
  269. package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
  270. package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
  271. package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
  272. package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
  273. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
  274. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
  275. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
  276. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
  277. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
  278. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
  279. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
  280. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
  281. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
  282. package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
  283. package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
  284. package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
  285. package/docs/02-CORE-GUIDES/readme.md +194 -194
  286. package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
  287. package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
  288. package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
  289. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
  290. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
  291. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
  292. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
  293. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
  294. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
  295. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
  296. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
  297. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
  298. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
  299. package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
  300. package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
  301. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
  302. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
  303. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
  304. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
  305. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
  306. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
  307. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
  308. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
  309. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
  310. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
  311. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
  312. package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
  313. package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
  314. package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
  315. package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
  316. package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
  317. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
  318. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
  319. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
  320. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
  321. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
  322. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
  323. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
  324. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
  325. package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
  326. package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
  327. package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
  328. package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
  329. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
  330. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
  331. package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
  332. package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
  333. package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
  334. package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
  335. package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
  336. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
  337. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
  338. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
  339. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
  340. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
  341. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
  342. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
  343. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
  344. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
  345. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
  346. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
  347. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
  348. package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
  349. package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
  350. package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
  351. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
  352. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
  353. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
  354. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
  355. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
  356. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
  357. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
  358. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
  359. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
  360. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
  361. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
  362. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
  363. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
  364. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
  365. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
  366. package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
  367. package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
  368. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
  369. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
  370. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
  371. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
  372. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
  373. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
  374. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
  375. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
  376. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
  377. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
  378. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
  379. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
  380. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
  381. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
  382. package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
  383. package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
  384. package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
  385. package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
  386. package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
  387. package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
  388. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
  389. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
  390. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
  391. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
  392. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
  393. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
  394. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
  395. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
  396. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
  397. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
  398. package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
  399. package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
  400. package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
  401. package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
  402. package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
  403. package/docs/03-PATTERN-GUIDES/readme.md +159 -159
  404. package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
  405. package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
  406. package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
  407. package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
  408. package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
  409. package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
  410. package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
  411. package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
  412. package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
  413. package/docs/04-REFERENCE/architecture/readme.md +279 -279
  414. package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
  415. package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
  416. package/docs/04-REFERENCE/platforms/readme.md +135 -135
  417. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
  418. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
  419. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
  420. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
  421. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
  422. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
  423. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
  424. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
  425. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
  426. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
  427. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
  428. package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
  429. package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
  430. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
  431. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
  432. package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
  433. package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
  434. package/docs/04-REFERENCE/readme.md +148 -148
  435. package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
  436. package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
  437. package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
  438. package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
  439. package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
  440. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
  441. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
  442. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
  443. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
  444. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
  445. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
  446. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
  447. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
  448. package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
  449. package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
  450. package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
  451. package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
  452. package/docs/04-REFERENCE/schema/readme.md +141 -141
  453. package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
  454. package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
  455. package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
  456. package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
  457. package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
  458. package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
  459. package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
  460. package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
  461. package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
  462. package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
  463. package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
  464. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
  465. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
  466. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
  467. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
  468. package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
  469. package/docs/04-REFERENCE/testing/readme.md +86 -86
  470. package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
  471. package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
  472. package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
  473. package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
  474. package/docs/template-loading-matrix.md +242 -242
  475. package/package.json +5 -3
  476. package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
@@ -1,1160 +1,1160 @@
1
- # Versori Webhook: XML/HTML Response Patterns
2
-
3
- **FC Connect SDK Use Case Guide**
4
-
5
- > **SDK**: [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)
6
- > **Version**: Use latest - `npm install @fluentcommerce/fc-connect-sdk@latest`
7
-
8
- **Context**: Return non-JSON content (XML, HTML, CSV) from Versori HTTP webhooks
9
-
10
- **Complexity**: Low-Medium
11
-
12
- **Runtime**: Versori Platform
13
-
14
- **Estimated Lines**: ~300 lines
15
-
16
- ## What You'll Build
17
-
18
- - Versori webhook with XML response
19
- - Custom onSuccess/onError handlers
20
- - Response object with proper Content-Type
21
- - XMLBuilder for generating XML
22
- - Error responses in XML format
23
-
24
- ## SDK Methods Used
25
-
26
- - `webhook('name', { response: { mode, onSuccess, onError } })` - Versori webhook config
27
- - `XMLBuilder(options)` - Build XML responses
28
- - `builder.build(data)` - Generate XML string
29
- - `new Response(body, { status, headers })` - Custom response objects
30
-
31
- ---
32
-
33
- ## Versori Workflows Structure
34
-
35
- **Key Concept**: Versori workflows are organized by **trigger type** at the first level, then by **specific workflow** with descriptive file names.
36
-
37
- **Trigger Types:**
38
- - **`webhook()`** → HTTP-based triggers (event-driven) - Creates HTTP endpoints
39
- - **`schedule()`** → Time-based triggers (cron expressions) - NOT exposed as HTTP endpoints
40
- - **`http()`** → External API calls (chained from webhook/schedule)
41
- - **`fn()`** → Internal processing (chained from webhook/schedule)
42
-
43
- ### Recommended Project Structure
44
-
45
- ```
46
- xml-response-patterns/
47
- ├── index.ts # Entry point - exports all workflows
48
- └── src/
49
- ├── workflows/
50
- │ └── webhook/
51
- │ └── xml-response.ts # Webhook: Return XML responses
52
-
53
- ├── services/
54
- │ └── xml-builder.service.ts # Shared XML building logic (reusable)
55
-
56
- └── config/
57
- └── xml-templates.json # XML templates
58
- ```
59
-
60
- **Benefits:**
61
- - ✅ Clear trigger separation (`webhook/` vs `scheduled/`)
62
- - ✅ Descriptive file names (easy to browse and understand)
63
- - ✅ Scalable (add new workflows without cluttering)
64
- - ✅ Reusable code in `services/` (DRY principle)
65
- - ✅ Easy to modify individual workflows without affecting others
66
-
67
- ---
68
-
69
- ## The Critical Problem
70
-
71
- By default, Versori webhooks **JSON-encode all responses**. This breaks non-JSON content types like XML, HTML, and CSV.
72
-
73
- ### The Wrong Way (Default Behavior)
74
-
75
- ```typescript
76
- import { webhook, fn } from '@versori/run';
77
-
78
- // ❌ PROBLEM: Returns JSON-encoded XML string
79
- export const badExample = webhook('xml-endpoint', async (ctx) => {
80
- return '<?xml version="1.0"?><order><id>123</id></order>';
81
- });
82
-
83
- // Response Body: "<?xml version=\"1.0\"?><order><id>123</id></order>"
84
- // Content-Type: application/json
85
- // Problem: XML is wrapped in JSON string with escaped quotes!
86
- ```
87
-
88
- **What happens:**
89
-
90
- 1. Your workflow returns an XML string
91
- 2. Versori's default handler runs `JSON.stringify()` on it
92
- 3. Client receives a JSON-encoded string instead of raw XML
93
- 4. Content-Type is set to `application/json` instead of `application/xml`
94
-
95
- ### The Right Way (Custom Response Objects)
96
-
97
- ```typescript
98
- import { webhook, fn } from '@versori/run';
99
-
100
- // ✅ SOLUTION: Returns raw XML
101
- export const goodExample = webhook('xml-endpoint', {
102
- response: {
103
- mode: 'sync',
104
- onSuccess: (ctx) => new Response(ctx.data, {
105
- status: 200,
106
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
107
- }),
108
- onError: (ctx) => new Response(ctx.data, {
109
- status: 500,
110
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
111
- })
112
- }
113
- })
114
- .then(fn('generate-xml', () => {
115
- return '<?xml version="1.0"?><order><id>123</id></order>';
116
- }));
117
-
118
- // Response Body: <?xml version="1.0"?><order><id>123</id></order>
119
- // Content-Type: application/xml; charset=utf-8
120
- // Success: Raw XML streamed directly to client!
121
- ```
122
-
123
- **Why this works:**
124
-
125
- - Custom handlers return `Response` objects
126
- - Versori's `sendResponse()` function streams Response bodies directly via Node.js `pipeline()`
127
- - No JSON encoding is applied to Response objects
128
- - Content-Type header is preserved exactly as specified
129
-
130
- ## Complete Working Examples
131
-
132
- ### Example 1: Basic JSON Response (Default Behavior)
133
-
134
- For JSON responses, no custom handlers are needed:
135
-
136
- ```typescript
137
- import { webhook, fn } from '@versori/run';
138
-
139
- /**
140
- * Default JSON response - no custom handlers needed
141
- * Versori automatically JSON-encodes and sets Content-Type: application/json
142
- */
143
- export const jsonEndpoint = webhook('json-data', async (ctx) => {
144
- return {
145
- orderId: '12345',
146
- status: 'COMPLETED',
147
- items: [
148
- { sku: 'ABC123', quantity: 2 },
149
- { sku: 'DEF456', quantity: 1 }
150
- ]
151
- };
152
- });
153
-
154
- // Response Body: {"orderId":"12345","status":"COMPLETED","items":[...]}
155
- // Content-Type: application/json
156
- // ✅ Perfect for JSON data!
157
- ```
158
-
159
- ### Example 2: XML Response with XMLBuilder
160
-
161
- Full XML response workflow with proper error handling:
162
-
163
- ```typescript
164
- import { webhook, fn, http } from '@versori/run';
165
- // FC Connect SDK
166
- // Install: npm install @fluentcommerce/fc-connect-sdk@latest
167
- // Docs: https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk
168
- // GitHub: https://github.com/fluentcommerce/fc-connect-sdk
169
- import { createClient } from '@fluentcommerce/fc-connect-sdk';
170
- import { XMLBuilder } from 'fast-xml-parser';
171
-
172
- /**
173
- * XML Response Webhook
174
- *
175
- * CRITICAL PATTERNS:
176
- * 1. Configure custom onSuccess/onError handlers
177
- * 2. Both handlers return Response objects
178
- * 3. Set Content-Type: application/xml
179
- * 4. Workflow steps return raw strings (not Response objects)
180
- * 5. Error handler also returns XML
181
- */
182
- export const orderXmlEndpoint = webhook('order-xml', {
183
- response: {
184
- mode: 'sync',
185
- // Success handler - wraps XML string in Response object
186
- onSuccess: (ctx) => new Response(ctx.data, {
187
- status: 200,
188
- headers: {
189
- 'Content-Type': 'application/xml; charset=utf-8',
190
- 'X-Execution-Id': ctx.executionId,
191
- 'Cache-Control': 'no-cache'
192
- }
193
- }),
194
- // Error handler - also returns XML format
195
- onError: (ctx) => new Response(ctx.data, {
196
- status: 500,
197
- headers: {
198
- 'Content-Type': 'application/xml; charset=utf-8',
199
- 'X-Execution-Id': ctx.executionId
200
- }
201
- })
202
- },
203
- cors: true
204
- })
205
- // Step 1: Extract order ID from request
206
- .then(fn('parse-request', ({ data }) => {
207
- // Versori auto-parses XML when Content-Type is application/xml
208
- const orderId = data?.OrderRequest?.OrderId;
209
- if (!orderId) {
210
- throw new Error('OrderId missing from request');
211
- }
212
- return { orderId };
213
- }))
214
- // Step 2: Fetch order from Fluent Commerce
215
- .then(http('fetch-order', {
216
- connection: 'fluent_commerce'
217
- }, async (ctx) => {
218
- const client = await createClient(ctx);
219
- const result = await client.graphql({
220
- query: `query GetOrder($ref: String) {
221
- order(ref: $ref) {
222
- id
223
- ref
224
- status
225
- totalPrice
226
- customer {
227
- firstName
228
- lastName
229
- username
230
- }
231
- items(first: 50) {
232
- edges {
233
- node {
234
- ref
235
- quantity
236
- price
237
- product {
238
- ref
239
- name
240
- }
241
- }
242
- }
243
- }
244
- }
245
- }`,
246
- variables: { ref: ctx.data.orderId }
247
- });
248
-
249
- if (!result.data?.order) {
250
- throw new Error(`Order not found: ${ctx.data.orderId}`);
251
- }
252
-
253
- return { order: result.data.order };
254
- }))
255
- // Step 3: Transform to XML format
256
- .then(fn('build-xml', ({ data }) => {
257
- const { order } = data;
258
-
259
- // Initialize XML Builder
260
- const builder = new XMLBuilder({
261
- ignoreAttributes: false,
262
- attributeNamePrefix: '@',
263
- format: true,
264
- indentBy: ' ',
265
- suppressEmptyNode: true
266
- });
267
-
268
- // Build XML structure
269
- const xmlObject = {
270
- '?xml': {
271
- '@version': '1.0',
272
- '@encoding': 'UTF-8'
273
- },
274
- OrderResponse: {
275
- '@xmlns': 'http://api.example.com/schema/order/1.0',
276
- Order: {
277
- OrderId: order.ref,
278
- Status: order.status,
279
- TotalPrice: {
280
- '@currency': 'USD',
281
- '#text': order.totalPrice
282
- },
283
- Customer: {
284
- FirstName: order.customer.firstName,
285
- LastName: order.customer.lastName,
286
- Email: order.customer.username
287
- },
288
- Items: {
289
- Item: order.items.edges.map(edge => ({
290
- SKU: edge.node.product.ref,
291
- ProductName: edge.node.product.name,
292
- Quantity: edge.node.quantity,
293
- Price: edge.node.price
294
- }))
295
- }
296
- }
297
- }
298
- };
299
-
300
- // Generate XML string
301
- const xmlString = builder.build(xmlObject);
302
-
303
- // Return XML string - onSuccess handler will wrap it
304
- return xmlString;
305
- }))
306
- // Error handling - return XML error format
307
- .catch(({ data }) => {
308
- const errorMessage = data instanceof Error ? data.message : String(data);
309
-
310
- // Return error XML string - onError handler will wrap it
311
- return `<?xml version="1.0" encoding="UTF-8"?>
312
- <OrderResponse xmlns="http://api.example.com/schema/order/1.0">
313
- <Error>
314
- <Code>PROCESSING_ERROR</Code>
315
- <Message>${errorMessage}</Message>
316
- <Timestamp>${new Date().toISOString()}</Timestamp>
317
- </Error>
318
- </OrderResponse>`;
319
- });
320
- ```
321
-
322
- **Testing this endpoint:**
323
-
324
- ```bash
325
- # Send XML request
326
- curl -X POST https://your-workspace.versori.run/order-xml \
327
- -H "Content-Type: application/xml" \
328
- -d '<?xml version="1.0"?>
329
- <OrderRequest>
330
- <OrderId>ORD-12345</OrderId>
331
- </OrderRequest>'
332
-
333
- # Success Response (200 OK):
334
- <?xml version="1.0" encoding="UTF-8"?>
335
- <OrderResponse xmlns="http://api.example.com/schema/order/1.0">
336
- <Order>
337
- <OrderId>ORD-12345</OrderId>
338
- <Status>COMPLETED</Status>
339
- <TotalPrice currency="USD">199.99</TotalPrice>
340
- ...
341
- </Order>
342
- </OrderResponse>
343
-
344
- # Error Response (500 Internal Server Error):
345
- <?xml version="1.0" encoding="UTF-8"?>
346
- <OrderResponse xmlns="http://api.example.com/schema/order/1.0">
347
- <Error>
348
- <Code>PROCESSING_ERROR</Code>
349
- <Message>Order not found: ORD-12345</Message>
350
- <Timestamp>2025-01-15T10:30:00Z</Timestamp>
351
- </Error>
352
- </OrderResponse>
353
- ```
354
-
355
- ### Example 3: HTML Response
356
-
357
- Return HTML pages from webhooks (useful for status pages, documentation):
358
-
359
- ```typescript
360
- import { webhook, fn } from '@versori/run';
361
-
362
- export const statusPage = webhook('status', {
363
- response: {
364
- mode: 'sync',
365
- onSuccess: (ctx) => new Response(ctx.data, {
366
- status: 200,
367
- headers: { 'Content-Type': 'text/html; charset=utf-8' }
368
- })
369
- }
370
- })
371
- .then(fn('generate-html', () => {
372
- return `<!DOCTYPE html>
373
- <html lang="en">
374
- <head>
375
- <meta charset="UTF-8">
376
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
377
- <title>Service Status</title>
378
- <style>
379
- body {
380
- font-family: Arial, sans-serif;
381
- max-width: 800px;
382
- margin: 50px auto;
383
- padding: 20px;
384
- }
385
- .status {
386
- padding: 20px;
387
- background-color: #4CAF50;
388
- color: white;
389
- border-radius: 5px;
390
- }
391
- .service {
392
- margin: 10px 0;
393
- padding: 10px;
394
- border: 1px solid #ddd;
395
- border-radius: 3px;
396
- }
397
- </style>
398
- </head>
399
- <body>
400
- <h1>Service Status Dashboard</h1>
401
- <div class="status">
402
- <h2>✓ All Systems Operational</h2>
403
- </div>
404
- <div class="service">
405
- <h3>Inventory Ingestion</h3>
406
- <p>Status: <strong>Operational</strong></p>
407
- <p>Last Run: ${new Date().toISOString()}</p>
408
- </div>
409
- <div class="service">
410
- <h3>Order Processing</h3>
411
- <p>Status: <strong>Operational</strong></p>
412
- </div>
413
- </body>
414
- </html>`;
415
- }));
416
- ```
417
-
418
- ### Example 4: CSV Response
419
-
420
- Download data as CSV files:
421
-
422
- ```typescript
423
- import { webhook, fn, http } from '@versori/run';
424
- import { createClient } from '@fluentcommerce/fc-connect-sdk';
425
-
426
- export const exportInventory = webhook('export-inventory-csv', {
427
- response: {
428
- mode: 'sync',
429
- onSuccess: (ctx) => new Response(ctx.data, {
430
- status: 200,
431
- headers: {
432
- 'Content-Type': 'text/csv; charset=utf-8',
433
- 'Content-Disposition': 'attachment; filename="inventory-export.csv"'
434
- }
435
- })
436
- }
437
- })
438
- .then(http('fetch-inventory', {
439
- connection: 'fluent_commerce'
440
- }, async (ctx) => {
441
- const client = await createClient(ctx);
442
- const result = await client.graphql({
443
- query: `query {
444
- inventoryQuantities(first: 100) {
445
- edges {
446
- node {
447
- ref
448
- quantity
449
- location { ref }
450
- product { ref name }
451
- }
452
- }
453
- }
454
- }`
455
- });
456
-
457
- return { items: result.data.inventoryQuantities.edges };
458
- }))
459
- .then(fn('build-csv', ({ data }) => {
460
- // CSV Header
461
- let csv = 'SKU,Product Name,Location,Quantity\n';
462
-
463
- // CSV Rows
464
- data.items.forEach(edge => {
465
- const item = edge.node;
466
- const sku = item.product?.ref || '';
467
- const name = (item.product?.name || '').replace(/"/g, '""'); // Escape quotes
468
- const location = item.location?.ref || '';
469
- const qty = item.quantity || 0;
470
-
471
- csv += `"${sku}","${name}","${location}",${qty}\n`;
472
- });
473
-
474
- return csv;
475
- }));
476
- ```
477
-
478
- ### Example 5: Plain Text Response
479
-
480
- Health check or simple text endpoints:
481
-
482
- ```typescript
483
- import { webhook, fn } from '@versori/run';
484
-
485
- export const healthCheck = webhook('health', {
486
- response: {
487
- mode: 'sync',
488
- onSuccess: (ctx) => new Response(ctx.data, {
489
- status: 200,
490
- headers: { 'Content-Type': 'text/plain; charset=utf-8' }
491
- })
492
- }
493
- })
494
- .then(fn('check-health', () => {
495
- const uptime = process.uptime();
496
- const timestamp = new Date().toISOString();
497
-
498
- return `Service Status: Operational
499
- Uptime: ${uptime.toFixed(0)} seconds
500
- Timestamp: ${timestamp}
501
- }));
502
- ```
503
-
504
- ## Key Patterns Explained
505
-
506
- ### Pattern 1: Why Custom Response Objects Are Needed
507
-
508
- **The Technical Details:**
509
-
510
- Versori's `sendResponse()` function (from @versori/run v0.4.4):
511
-
512
- ```typescript
513
- function sendResponse(res, response) {
514
- res.status(response.status);
515
- response.headers.forEach((value, key) => {
516
- res.setHeader(key, value);
517
- });
518
- if (response.body) {
519
- pipeline(response.body, res); // Streams directly without encoding
520
- }
521
- }
522
- ```
523
-
524
- **Key insight:** When you return a `Response` object, Versori uses Node.js `pipeline()` to stream the body directly to the HTTP response **without any JSON encoding**.
525
-
526
- **Default handlers** (when you don't provide custom ones):
527
-
528
- ```typescript
529
- // Simplified version of default behavior
530
- const defaultOnSuccess = (ctx) => {
531
- return JSON.stringify(ctx.data); // ❌ Encodes everything as JSON
532
- };
533
- ```
534
-
535
- ### Pattern 2: onSuccess Handler Pattern
536
-
537
- The `onSuccess` handler receives context and must return a `Response` object:
538
-
539
- ```typescript
540
- onSuccess: (ctx) => {
541
- // ctx.data = output from final .then() step
542
- // ctx.executionId = unique execution ID
543
- // ctx.metadata = any metadata from workflow
544
-
545
- return new Response(ctx.data, {
546
- status: 200, // HTTP status code
547
- headers: {
548
- 'Content-Type': 'application/xml; charset=utf-8',
549
- 'X-Execution-Id': ctx.executionId,
550
- 'Cache-Control': 'no-cache',
551
- // Any custom headers...
552
- }
553
- });
554
- }
555
- ```
556
-
557
- **Important:** Your workflow steps should return **raw strings**, not Response objects. The handler wraps them.
558
-
559
- ### Pattern 3: onError Handler Pattern
560
-
561
- The `onError` handler handles exceptions and should match the content type:
562
-
563
- ```typescript
564
- onError: (ctx) => {
565
- // ctx.data = error from .catch() or thrown exception
566
- // ctx.executionId = unique execution ID
567
-
568
- return new Response(ctx.data, {
569
- status: 500, // or 400, 404, etc.
570
- headers: {
571
- 'Content-Type': 'application/xml; charset=utf-8', // Match success type!
572
- 'X-Execution-Id': ctx.executionId
573
- }
574
- });
575
- }
576
- ```
577
-
578
- **Best practice:** Use the same Content-Type for errors as for success responses. If your API returns XML on success, return XML errors too.
579
-
580
- ### Pattern 4: Content-Type Headers
581
-
582
- Always include charset for text-based formats:
583
-
584
- ```typescript
585
- // ✅ CORRECT - Includes charset
586
- 'Content-Type': 'application/xml; charset=utf-8'
587
- 'Content-Type': 'text/html; charset=utf-8'
588
- 'Content-Type': 'text/csv; charset=utf-8'
589
- 'Content-Type': 'text/plain; charset=utf-8'
590
-
591
- // ❌ INCOMPLETE - Missing charset (may work but not recommended)
592
- 'Content-Type': 'application/xml'
593
-
594
- // ✅ CORRECT - Binary formats don't need charset
595
- 'Content-Type': 'application/pdf'
596
- 'Content-Type': 'image/png'
597
- ```
598
-
599
- ### Pattern 5: XMLBuilder Integration
600
-
601
- Using `fast-xml-parser` to generate clean XML:
602
-
603
- ```typescript
604
- import { XMLBuilder } from 'fast-xml-parser';
605
-
606
- // Initialize builder with options
607
- const builder = new XMLBuilder({
608
- ignoreAttributes: false, // Include XML attributes
609
- attributeNamePrefix: '@', // Prefix for attributes
610
- textNodeName: '#text', // Key for text content
611
- format: true, // Pretty-print
612
- indentBy: ' ', // Indentation
613
- suppressEmptyNode: true // Don't output <tag></tag> for nulls
614
- });
615
-
616
- // Define XML structure
617
- const xmlObject = {
618
- '?xml': { // XML declaration
619
- '@version': '1.0',
620
- '@encoding': 'UTF-8'
621
- },
622
- Root: {
623
- '@xmlns': 'http://...', // Root attributes start with @
624
- Child: 'value',
625
- Another: {
626
- '@id': '123', // Element with attribute and text
627
- '#text': 'content'
628
- },
629
- List: {
630
- Item: ['item1', 'item2'] // Arrays become multiple elements
631
- }
632
- }
633
- };
634
-
635
- // Generate XML string
636
- const xmlString = builder.build(xmlObject);
637
- ```
638
-
639
- **Generated Output:**
640
-
641
- ```xml
642
- <?xml version="1.0" encoding="UTF-8"?>
643
- <Root xmlns="http://...">
644
- <Child>value</Child>
645
- <Another id="123">content</Another>
646
- <List>
647
- <Item>item1</Item>
648
- <Item>item2</Item>
649
- </List>
650
- </Root>
651
- ```
652
-
653
- ## The JSON Encoding Problem
654
-
655
- ### Side-by-Side Comparison
656
-
657
- #### ❌ WRONG: Default Behavior (JSON-Encoded)
658
-
659
- ```typescript
660
- export const badXmlEndpoint = webhook('bad-xml', async (ctx) => {
661
- return '<?xml version="1.0"?><order><id>123</id></order>';
662
- });
663
- ```
664
-
665
- **What the client receives:**
666
-
667
- ```bash
668
- $ curl https://workspace.versori.run/bad-xml
669
-
670
- # Response:
671
- "<?xml version=\"1.0\"?><order><id>123</id></order>"
672
-
673
- # Response Headers:
674
- Content-Type: application/json
675
- Content-Length: 52
676
- ```
677
-
678
- **Problems:**
679
-
680
- 1. XML is wrapped in quotes
681
- 2. Special characters are escaped (`\n`, `\"`)
682
- 3. Content-Type is JSON, not XML
683
- 4. Cannot be parsed as XML by clients
684
- 5. Requires client-side JSON parsing then XML parsing
685
-
686
- #### ✅ RIGHT: Custom Response Objects
687
-
688
- ```typescript
689
- export const goodXmlEndpoint = webhook('good-xml', {
690
- response: {
691
- mode: 'sync',
692
- onSuccess: (ctx) => new Response(ctx.data, {
693
- status: 200,
694
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
695
- })
696
- }
697
- })
698
- .then(fn('gen', () => '<?xml version="1.0"?><order><id>123</id></order>'));
699
- ```
700
-
701
- **What the client receives:**
702
-
703
- ```bash
704
- $ curl https://workspace.versori.run/good-xml
705
-
706
- # Response:
707
- <?xml version="1.0"?><order><id>123</id></order>
708
-
709
- # Response Headers:
710
- Content-Type: application/xml; charset=utf-8
711
- Content-Length: 47
712
- ```
713
-
714
- **Benefits:**
715
-
716
- 1. Raw XML delivered to client
717
- 2. No escaping or encoding
718
- 3. Correct Content-Type header
719
- 4. Client can parse directly as XML
720
- 5. Standard HTTP semantics
721
-
722
- ### Visual Example: What Gets Sent
723
-
724
- **Bad (JSON-encoded):**
725
-
726
- ```
727
- HTTP/1.1 200 OK
728
- Content-Type: application/json
729
-
730
- "<?xml version=\"1.0\"?><order><id>123</id></order>"
731
- ```
732
-
733
- **Good (Raw XML):**
734
-
735
- ```
736
- HTTP/1.1 200 OK
737
- Content-Type: application/xml; charset=utf-8
738
-
739
- <?xml version="1.0"?><order><id>123</id></order>
740
- ```
741
-
742
- ## Common Issues and Solutions
743
-
744
- ### Issue 1: XML Still Being JSON-Encoded
745
-
746
- **Symptom:** Response is wrapped in quotes with escaped characters.
747
-
748
- **Cause:** Missing custom response handlers.
749
-
750
- **Solution:**
751
-
752
- ```typescript
753
- // ❌ Missing handlers
754
- export const endpoint = webhook('test')
755
- .then(fn('gen', () => '<xml>data</xml>'));
756
-
757
- // ✅ Add custom handlers
758
- export const endpoint = webhook('test', {
759
- response: {
760
- mode: 'sync',
761
- onSuccess: (ctx) => new Response(ctx.data, {
762
- status: 200,
763
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
764
- })
765
- }
766
- })
767
- .then(fn('gen', () => '<xml>data</xml>'));
768
- ```
769
-
770
- ### Issue 2: Wrong Content-Type in Response
771
-
772
- **Symptom:** Browser tries to download file or displays incorrectly.
773
-
774
- **Cause:** Content-Type doesn't match actual content.
775
-
776
- **Solution:**
777
-
778
- ```typescript
779
- // ❌ WRONG - XML with JSON content type
780
- headers: { 'Content-Type': 'application/json' }
781
-
782
- // ✅ RIGHT - Match content type to content
783
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
784
- ```
785
-
786
- **Content-Type Reference:**
787
-
788
- - XML: `application/xml; charset=utf-8`
789
- - HTML: `text/html; charset=utf-8`
790
- - CSV: `text/csv; charset=utf-8`
791
- - Plain text: `text/plain; charset=utf-8`
792
- - JSON: `application/json` (default, no custom handler needed)
793
-
794
- ### Issue 3: Error Responses Return JSON Instead of XML
795
-
796
- **Symptom:** Success returns XML, but errors return JSON.
797
-
798
- **Cause:** Missing `onError` handler.
799
-
800
- **Solution:**
801
-
802
- ```typescript
803
- export const endpoint = webhook('test', {
804
- response: {
805
- mode: 'sync',
806
- onSuccess: (ctx) => new Response(ctx.data, {
807
- status: 200,
808
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
809
- }),
810
- // ✅ Add error handler with same content type
811
- onError: (ctx) => new Response(ctx.data, {
812
- status: 500,
813
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
814
- })
815
- }
816
- })
817
- .then(fn('gen', () => '<success/>'))
818
- .catch(() => '<error/>'); // Make sure .catch() returns XML string
819
- ```
820
-
821
- ### Issue 4: Accidental Double-Encoding
822
-
823
- **Symptom:** Response has extra quotes or escaped characters.
824
-
825
- **Cause:** Calling `JSON.stringify()` on data before returning.
826
-
827
- **Solution:**
828
-
829
- ```typescript
830
- // ❌ WRONG - Don't stringify in handler
831
- onSuccess: (ctx) => new Response(JSON.stringify(ctx.data), {
832
- status: 200,
833
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
834
- })
835
-
836
- // ✅ RIGHT - Pass raw data
837
- onSuccess: (ctx) => new Response(ctx.data, {
838
- status: 200,
839
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
840
- })
841
- ```
842
-
843
- ## Testing Your Implementation
844
-
845
- ### Test 1: Verify Content-Type Header
846
-
847
- ```bash
848
- # Check response headers
849
- curl -v https://your-workspace.versori.run/your-endpoint
850
-
851
- # Look for:
852
- # ✅ Content-Type: application/xml; charset=utf-8
853
- # ❌ Content-Type: application/json
854
- ```
855
-
856
- ### Test 2: Verify Raw Content
857
-
858
- ```bash
859
- # Get response body
860
- curl https://your-workspace.versori.run/your-endpoint
861
-
862
- # Expected (raw XML):
863
- # <?xml version="1.0" encoding="UTF-8"?>
864
- # <order><id>123</id></order>
865
-
866
- # NOT expected (JSON-encoded):
867
- # "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<order><id>123</id></order>"
868
- ```
869
-
870
- ### Test 3: Verify Error Handling
871
-
872
- ```bash
873
- # Trigger an error (send invalid request)
874
- curl -X POST https://your-workspace.versori.run/your-endpoint \
875
- -H "Content-Type: application/xml" \
876
- -d '<?xml version="1.0"?><Invalid/>'
877
-
878
- # Should return:
879
- # - Status: 500 (or appropriate error code)
880
- # - Content-Type: application/xml (same as success)
881
- # - Body: XML error message
882
- ```
883
-
884
- ### Test 4: XML Parser Validation
885
-
886
- ```bash
887
- # Pipe response through xmllint to validate XML
888
- curl https://your-workspace.versori.run/your-endpoint | xmllint --format -
889
-
890
- # Should format successfully without errors
891
- ```
892
-
893
- ## Implementation Checklist
894
-
895
- When implementing non-JSON webhooks, verify:
896
-
897
- - [ ] Webhook configured with `response.mode: 'sync'`
898
- - [ ] `onSuccess` handler defined and returns `Response` object
899
- - [ ] `onError` handler defined and returns `Response` object
900
- - [ ] Both handlers set correct `Content-Type` header
901
- - [ ] Content-Type includes `charset=utf-8` for text formats
902
- - [ ] Workflow `.then()` steps return raw strings (not Response objects)
903
- - [ ] Workflow `.catch()` returns error string in correct format
904
- - [ ] Status codes are appropriate (200, 400, 500, etc.)
905
- - [ ] Error handler uses same Content-Type as success handler
906
- - [ ] Tested with curl to verify raw output (no JSON encoding)
907
- - [ ] Tested error scenarios return proper format
908
- - [ ] No `JSON.stringify()` calls in custom handlers
909
- - [ ] XML validated with parser (if XML response)
910
-
911
-
912
- ## Versori Syntax Validation
913
-
914
- ### Critical: Buffer Import Required
915
-
916
- **For Deno/Versori runtime, ALWAYS import Buffer explicitly:**
917
-
918
- ```typescript
919
- // ✅ CORRECT - Explicit import required
920
- import { Buffer } from 'node:buffer';
921
-
922
- // Use Buffer for encoding operations
923
- await sftp.uploadFile('utf8', Buffer.from(xmlContent), '/path/file.xml');
924
- const decoded = Buffer.from(base64String, 'base64').toString('utf-8');
925
- ```
926
-
927
- **Why:** Deno runtime doesn't have `Buffer` as a global (unlike Node.js). Missing this import will cause runtime errors.
928
-
929
- ### Validated Syntax Patterns for SDK ^0.1.27
930
-
931
- #### 1. Webhook Response Configuration
932
-
933
- ```typescript
934
- // ✅ CORRECT - Webhook with custom response handlers
935
- export const endpoint = webhook('name', {
936
- response: {
937
- mode: 'sync', // Required for custom handlers
938
- onSuccess: (ctx) => new Response(ctx.data, {
939
- status: 200,
940
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
941
- }),
942
- onError: (ctx) => new Response(ctx.data, {
943
- status: 500,
944
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
945
- })
946
- },
947
- cors: true // Optional CORS configuration
948
- })
949
- .then(fn('step', () => '<xml/>'));
950
-
951
- // ❌ WRONG - Missing response configuration
952
- export const endpoint = webhook('name', async (ctx) => {
953
- return '<xml/>'; // Will be JSON-encoded!
954
- });
955
- ```
956
-
957
- #### 2. Client Factory Usage
958
-
959
- ```typescript
960
- // ✅ CORRECT - Use createClient() factory
961
- import { createClient } from '@fluentcommerce/fc-connect-sdk';
962
-
963
- export const endpoint = webhook('name', {
964
- connection: 'fluent_commerce'
965
- }, async (ctx) => {
966
- const client = await createClient(ctx);
967
- // Client automatically configured from connection
968
- });
969
-
970
- // ❌ WRONG - Direct instantiation bypasses context detection
971
- import { FluentClient } from '@fluentcommerce/fc-connect-sdk';
972
- const client = new FluentClient(config); // Don't do this in Versori
973
- ```
974
-
975
- #### 3. Logging Best Practices
976
-
977
- ```typescript
978
- // ✅ CORRECT - Use native log from context
979
- export const endpoint = webhook('name', {
980
- connection: 'fluent_commerce'
981
- }, async (ctx) => {
982
- const { log } = ctx;
983
- log('Processing started', { orderId: '123' });
984
-
985
- // SDK client receives log automatically
986
- const client = await createClient(ctx);
987
- });
988
-
989
- // ❌ WRONG - Don't use LoggingService in Versori
990
- import { LoggingService } from '@fluentcommerce/fc-connect-sdk';
991
- const logger = new LoggingService(); // Not needed in Versori
992
- ```
993
-
994
- #### 4. Auto-Pagination Syntax
995
-
996
- ```typescript
997
- // ✅ CORRECT - pagination object (NOT config)
998
- const result = await client.graphql({
999
- query,
1000
- variables: { first: 100 },
1001
- pagination: { // Use 'pagination', not 'config'
1002
- maxPages: 50,
1003
- pageSize: 100
1004
- }
1005
- });
1006
-
1007
- // ❌ WRONG - Old syntax with 'config'
1008
- const result = await client.graphql({
1009
- query,
1010
- variables: { first: 100 },
1011
- config: { // Use 'pagination' parameter instead
1012
- maxPages: 50
1013
- }
1014
- });
1015
- ```
1016
-
1017
- #### 5. SDK Version Specification
1018
-
1019
- ```json
1020
- {
1021
- "dependencies": {
1022
- "@fluentcommerce/fc-connect-sdk": "^0.1.39",
1023
- "@versori/run": "latest",
1024
- "fast-xml-parser": "^4.3.0"
1025
- }
1026
- }
1027
- ```
1028
-
1029
- #### 6. Workflow Step Return Values
1030
-
1031
- ```typescript
1032
- // ✅ CORRECT - Return raw data, let handlers wrap it
1033
- export const endpoint = webhook('name', {
1034
- response: {
1035
- mode: 'sync',
1036
- onSuccess: (ctx) => new Response(ctx.data, {
1037
- status: 200,
1038
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
1039
- })
1040
- }
1041
- })
1042
- .then(fn('generate', () => {
1043
- return '<xml>data</xml>'; // Return raw string
1044
- }));
1045
-
1046
- // ❌ WRONG - Don't return Response objects from workflow steps
1047
- export const endpoint = webhook('name', {
1048
- response: { mode: 'sync', onSuccess: (ctx) => ctx.data }
1049
- })
1050
- .then(fn('generate', () => {
1051
- return new Response('<xml>data</xml>'); // Wrong! Handler should do this
1052
- }));
1053
- ```
1054
-
1055
- #### 7. Error Handling Pattern
1056
-
1057
- ```typescript
1058
- // ✅ CORRECT - .catch() returns error data, onError wraps it
1059
- export const endpoint = webhook('name', {
1060
- response: {
1061
- mode: 'sync',
1062
- onSuccess: (ctx) => new Response(ctx.data, {
1063
- status: 200,
1064
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
1065
- }),
1066
- onError: (ctx) => new Response(ctx.data, {
1067
- status: 500,
1068
- headers: { 'Content-Type': 'application/xml; charset=utf-8' }
1069
- })
1070
- }
1071
- })
1072
- .then(fn('process', () => '<success/>'))
1073
- .catch((error) => {
1074
- // Return error XML string - onError handler will wrap it
1075
- return `<error>${error.message}</error>`;
1076
- });
1077
-
1078
- // ❌ WRONG - Throwing without catch or returning Response
1079
- export const endpoint = webhook('name')
1080
- .then(fn('process', () => {
1081
- throw new Error('Failed'); // Will cause 500 with JSON error
1082
- }));
1083
- ```
1084
-
1085
- ### Validation Checklist
1086
-
1087
- Before deploying to Versori, verify:
1088
-
1089
- **Syntax:**
1090
- - [ ] Buffer explicitly imported: `import { Buffer } from 'node:buffer';`
1091
- - [ ] webhook() has response.mode: 'sync' for custom handlers
1092
- - [ ] onSuccess and onError both defined
1093
- - [ ] Both handlers return Response objects
1094
- - [ ] Workflow steps return raw data (not Response objects)
1095
-
1096
- **SDK Integration:**
1097
- - [ ] createClient() used (not direct instantiation)
1098
- - [ ] Native ctx.log used (not LoggingService)
1099
- - [ ] Auto-pagination uses 'pagination' object (not 'config')
1100
- - [ ] SDK version is ^0.1.27 or later
1101
-
1102
- **Response Handling:**
1103
- - [ ] Content-Type headers match actual content
1104
- - [ ] charset=utf-8 included for text formats
1105
- - [ ] onError uses same Content-Type as onSuccess
1106
- - [ ] Error .catch() returns proper format string
1107
-
1108
- **Testing:**
1109
- - [ ] Tested with curl to verify raw output
1110
- - [ ] Verified Content-Type header is correct
1111
- - [ ] Tested error scenarios return proper format
1112
- - [ ] Validated XML with parser (if XML)
1113
-
1114
- ## Version Compatibility
1115
-
1116
- This pattern works with:
1117
-
1118
- **Versori Runtime:**
1119
- - @versori/run v0.4.4 (latest stable)
1120
- - @versori/run v0.4.3
1121
- - @versori/run v0.4.2
1122
- - @versori/run v0.4.1
1123
- - @versori/run v0.4.0
1124
- - @versori/run v0.4.0-alpha.2
1125
-
1126
- All v0.4.x versions use the same `sendResponse()` implementation that streams Response objects directly.
1127
-
1128
- **FC Connect SDK:**
1129
- - @fluentcommerce/fc-connect-sdk v0.1.27+
1130
- - @fluentcommerce/fc-connect-sdk v0.1.26
1131
- - @fluentcommerce/fc-connect-sdk v0.1.25
1132
- - All v0.1.x versions support Versori platform integration
1133
-
1134
- ## Related Guides
1135
-
1136
- - **[Versori Platform Integration](../../../04-REFERENCE/platforms/versori/)** - Complete Versori platform guide
1137
- - **[GraphQL Mutation Mapping Guide](../../../02-CORE-GUIDES/mapping/graphql-mutation-mapping/)** - XML/JSON to GraphQL mutations
1138
- - **[Universal Mapping Guide](../../../02-CORE-GUIDES/mapping/)** - Field transformation patterns
1139
- - **[Webhook Validation Guide](../../../02-CORE-GUIDES/webhook-validation/)** - Webhook signature validation
1140
-
1141
- ## Real-World Example Reference
1142
-
1143
- See complete production implementation:
1144
-
1145
- - **File**: `Sandbox Hibbet SFCC to Fluent Order integration (1)/src/workflows/process-order-detail-request.ts`
1146
- - **Pattern**: XML request → GraphQL query → XML response
1147
- - **Features**: Full error handling, extraction mapping, XMLBuilder integration
1148
-
1149
- ## Summary
1150
-
1151
- **Golden Rule:** For non-JSON content types in Versori webhooks, **ALWAYS** use custom `onSuccess` and `onError` handlers that return `Response` objects with the correct Content-Type header.
1152
-
1153
- **Why It Matters:**
1154
-
1155
- - Default handlers JSON-encode all responses (breaks XML/HTML/CSV)
1156
- - Custom handlers bypass encoding and stream content directly
1157
- - Proper Content-Type headers ensure correct client behavior
1158
- - Consistent error handling provides better API experience
1159
-
1160
- **Impact:** This pattern saves hours of debugging and ensures proper content delivery for XML APIs, HTML pages, CSV exports, and other non-JSON formats. It's critical for SOAP integrations, enterprise systems, and file downloads.
1
+ # Versori Webhook: XML/HTML Response Patterns
2
+
3
+ **FC Connect SDK Use Case Guide**
4
+
5
+ > **SDK**: [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)
6
+ > **Version**: Use latest - `npm install @fluentcommerce/fc-connect-sdk@latest`
7
+
8
+ **Context**: Return non-JSON content (XML, HTML, CSV) from Versori HTTP webhooks
9
+
10
+ **Complexity**: Low-Medium
11
+
12
+ **Runtime**: Versori Platform
13
+
14
+ **Estimated Lines**: ~300 lines
15
+
16
+ ## What You'll Build
17
+
18
+ - Versori webhook with XML response
19
+ - Custom onSuccess/onError handlers
20
+ - Response object with proper Content-Type
21
+ - XMLBuilder for generating XML
22
+ - Error responses in XML format
23
+
24
+ ## SDK Methods Used
25
+
26
+ - `webhook('name', { response: { mode, onSuccess, onError } })` - Versori webhook config
27
+ - `XMLBuilder(options)` - Build XML responses
28
+ - `builder.build(data)` - Generate XML string
29
+ - `new Response(body, { status, headers })` - Custom response objects
30
+
31
+ ---
32
+
33
+ ## Versori Workflows Structure
34
+
35
+ **Key Concept**: Versori workflows are organized by **trigger type** at the first level, then by **specific workflow** with descriptive file names.
36
+
37
+ **Trigger Types:**
38
+ - **`webhook()`** → HTTP-based triggers (event-driven) - Creates HTTP endpoints
39
+ - **`schedule()`** → Time-based triggers (cron expressions) - NOT exposed as HTTP endpoints
40
+ - **`http()`** → External API calls (chained from webhook/schedule)
41
+ - **`fn()`** → Internal processing (chained from webhook/schedule)
42
+
43
+ ### Recommended Project Structure
44
+
45
+ ```
46
+ xml-response-patterns/
47
+ ├── index.ts # Entry point - exports all workflows
48
+ └── src/
49
+ ├── workflows/
50
+ │ └── webhook/
51
+ │ └── xml-response.ts # Webhook: Return XML responses
52
+
53
+ ├── services/
54
+ │ └── xml-builder.service.ts # Shared XML building logic (reusable)
55
+
56
+ └── config/
57
+ └── xml-templates.json # XML templates
58
+ ```
59
+
60
+ **Benefits:**
61
+ - ✅ Clear trigger separation (`webhook/` vs `scheduled/`)
62
+ - ✅ Descriptive file names (easy to browse and understand)
63
+ - ✅ Scalable (add new workflows without cluttering)
64
+ - ✅ Reusable code in `services/` (DRY principle)
65
+ - ✅ Easy to modify individual workflows without affecting others
66
+
67
+ ---
68
+
69
+ ## The Critical Problem
70
+
71
+ By default, Versori webhooks **JSON-encode all responses**. This breaks non-JSON content types like XML, HTML, and CSV.
72
+
73
+ ### The Wrong Way (Default Behavior)
74
+
75
+ ```typescript
76
+ import { webhook, fn } from '@versori/run';
77
+
78
+ // ❌ PROBLEM: Returns JSON-encoded XML string
79
+ export const badExample = webhook('xml-endpoint', async (ctx) => {
80
+ return '<?xml version="1.0"?><order><id>123</id></order>';
81
+ });
82
+
83
+ // Response Body: "<?xml version=\"1.0\"?><order><id>123</id></order>"
84
+ // Content-Type: application/json
85
+ // Problem: XML is wrapped in JSON string with escaped quotes!
86
+ ```
87
+
88
+ **What happens:**
89
+
90
+ 1. Your workflow returns an XML string
91
+ 2. Versori's default handler runs `JSON.stringify()` on it
92
+ 3. Client receives a JSON-encoded string instead of raw XML
93
+ 4. Content-Type is set to `application/json` instead of `application/xml`
94
+
95
+ ### The Right Way (Custom Response Objects)
96
+
97
+ ```typescript
98
+ import { webhook, fn } from '@versori/run';
99
+
100
+ // ✅ SOLUTION: Returns raw XML
101
+ export const goodExample = webhook('xml-endpoint', {
102
+ response: {
103
+ mode: 'sync',
104
+ onSuccess: (ctx) => new Response(ctx.data, {
105
+ status: 200,
106
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
107
+ }),
108
+ onError: (ctx) => new Response(ctx.data, {
109
+ status: 500,
110
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
111
+ })
112
+ }
113
+ })
114
+ .then(fn('generate-xml', () => {
115
+ return '<?xml version="1.0"?><order><id>123</id></order>';
116
+ }));
117
+
118
+ // Response Body: <?xml version="1.0"?><order><id>123</id></order>
119
+ // Content-Type: application/xml; charset=utf-8
120
+ // Success: Raw XML streamed directly to client!
121
+ ```
122
+
123
+ **Why this works:**
124
+
125
+ - Custom handlers return `Response` objects
126
+ - Versori's `sendResponse()` function streams Response bodies directly via Node.js `pipeline()`
127
+ - No JSON encoding is applied to Response objects
128
+ - Content-Type header is preserved exactly as specified
129
+
130
+ ## Complete Working Examples
131
+
132
+ ### Example 1: Basic JSON Response (Default Behavior)
133
+
134
+ For JSON responses, no custom handlers are needed:
135
+
136
+ ```typescript
137
+ import { webhook, fn } from '@versori/run';
138
+
139
+ /**
140
+ * Default JSON response - no custom handlers needed
141
+ * Versori automatically JSON-encodes and sets Content-Type: application/json
142
+ */
143
+ export const jsonEndpoint = webhook('json-data', async (ctx) => {
144
+ return {
145
+ orderId: '12345',
146
+ status: 'COMPLETED',
147
+ items: [
148
+ { sku: 'ABC123', quantity: 2 },
149
+ { sku: 'DEF456', quantity: 1 }
150
+ ]
151
+ };
152
+ });
153
+
154
+ // Response Body: {"orderId":"12345","status":"COMPLETED","items":[...]}
155
+ // Content-Type: application/json
156
+ // ✅ Perfect for JSON data!
157
+ ```
158
+
159
+ ### Example 2: XML Response with XMLBuilder
160
+
161
+ Full XML response workflow with proper error handling:
162
+
163
+ ```typescript
164
+ import { webhook, fn, http } from '@versori/run';
165
+ // FC Connect SDK
166
+ // Install: npm install @fluentcommerce/fc-connect-sdk@latest
167
+ // Docs: https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk
168
+ // GitHub: https://github.com/fluentcommerce/fc-connect-sdk
169
+ import { createClient } from '@fluentcommerce/fc-connect-sdk';
170
+ import { XMLBuilder } from 'fast-xml-parser';
171
+
172
+ /**
173
+ * XML Response Webhook
174
+ *
175
+ * CRITICAL PATTERNS:
176
+ * 1. Configure custom onSuccess/onError handlers
177
+ * 2. Both handlers return Response objects
178
+ * 3. Set Content-Type: application/xml
179
+ * 4. Workflow steps return raw strings (not Response objects)
180
+ * 5. Error handler also returns XML
181
+ */
182
+ export const orderXmlEndpoint = webhook('order-xml', {
183
+ response: {
184
+ mode: 'sync',
185
+ // Success handler - wraps XML string in Response object
186
+ onSuccess: (ctx) => new Response(ctx.data, {
187
+ status: 200,
188
+ headers: {
189
+ 'Content-Type': 'application/xml; charset=utf-8',
190
+ 'X-Execution-Id': ctx.executionId,
191
+ 'Cache-Control': 'no-cache'
192
+ }
193
+ }),
194
+ // Error handler - also returns XML format
195
+ onError: (ctx) => new Response(ctx.data, {
196
+ status: 500,
197
+ headers: {
198
+ 'Content-Type': 'application/xml; charset=utf-8',
199
+ 'X-Execution-Id': ctx.executionId
200
+ }
201
+ })
202
+ },
203
+ cors: true
204
+ })
205
+ // Step 1: Extract order ID from request
206
+ .then(fn('parse-request', ({ data }) => {
207
+ // Versori auto-parses XML when Content-Type is application/xml
208
+ const orderId = data?.OrderRequest?.OrderId;
209
+ if (!orderId) {
210
+ throw new Error('OrderId missing from request');
211
+ }
212
+ return { orderId };
213
+ }))
214
+ // Step 2: Fetch order from Fluent Commerce
215
+ .then(http('fetch-order', {
216
+ connection: 'fluent_commerce'
217
+ }, async (ctx) => {
218
+ const client = await createClient(ctx);
219
+ const result = await client.graphql({
220
+ query: `query GetOrder($ref: String) {
221
+ order(ref: $ref) {
222
+ id
223
+ ref
224
+ status
225
+ totalPrice
226
+ customer {
227
+ firstName
228
+ lastName
229
+ username
230
+ }
231
+ items(first: 50) {
232
+ edges {
233
+ node {
234
+ ref
235
+ quantity
236
+ price
237
+ product {
238
+ ref
239
+ name
240
+ }
241
+ }
242
+ }
243
+ }
244
+ }
245
+ }`,
246
+ variables: { ref: ctx.data.orderId }
247
+ });
248
+
249
+ if (!result.data?.order) {
250
+ throw new Error(`Order not found: ${ctx.data.orderId}`);
251
+ }
252
+
253
+ return { order: result.data.order };
254
+ }))
255
+ // Step 3: Transform to XML format
256
+ .then(fn('build-xml', ({ data }) => {
257
+ const { order } = data;
258
+
259
+ // Initialize XML Builder
260
+ const builder = new XMLBuilder({
261
+ ignoreAttributes: false,
262
+ attributeNamePrefix: '@',
263
+ format: true,
264
+ indentBy: ' ',
265
+ suppressEmptyNode: true
266
+ });
267
+
268
+ // Build XML structure
269
+ const xmlObject = {
270
+ '?xml': {
271
+ '@version': '1.0',
272
+ '@encoding': 'UTF-8'
273
+ },
274
+ OrderResponse: {
275
+ '@xmlns': 'http://api.example.com/schema/order/1.0',
276
+ Order: {
277
+ OrderId: order.ref,
278
+ Status: order.status,
279
+ TotalPrice: {
280
+ '@currency': 'USD',
281
+ '#text': order.totalPrice
282
+ },
283
+ Customer: {
284
+ FirstName: order.customer.firstName,
285
+ LastName: order.customer.lastName,
286
+ Email: order.customer.username
287
+ },
288
+ Items: {
289
+ Item: order.items.edges.map(edge => ({
290
+ SKU: edge.node.product.ref,
291
+ ProductName: edge.node.product.name,
292
+ Quantity: edge.node.quantity,
293
+ Price: edge.node.price
294
+ }))
295
+ }
296
+ }
297
+ }
298
+ };
299
+
300
+ // Generate XML string
301
+ const xmlString = builder.build(xmlObject);
302
+
303
+ // Return XML string - onSuccess handler will wrap it
304
+ return xmlString;
305
+ }))
306
+ // Error handling - return XML error format
307
+ .catch(({ data }) => {
308
+ const errorMessage = data instanceof Error ? data.message : String(data);
309
+
310
+ // Return error XML string - onError handler will wrap it
311
+ return `<?xml version="1.0" encoding="UTF-8"?>
312
+ <OrderResponse xmlns="http://api.example.com/schema/order/1.0">
313
+ <Error>
314
+ <Code>PROCESSING_ERROR</Code>
315
+ <Message>${errorMessage}</Message>
316
+ <Timestamp>${new Date().toISOString()}</Timestamp>
317
+ </Error>
318
+ </OrderResponse>`;
319
+ });
320
+ ```
321
+
322
+ **Testing this endpoint:**
323
+
324
+ ```bash
325
+ # Send XML request
326
+ curl -X POST https://your-workspace.versori.run/order-xml \
327
+ -H "Content-Type: application/xml" \
328
+ -d '<?xml version="1.0"?>
329
+ <OrderRequest>
330
+ <OrderId>ORD-12345</OrderId>
331
+ </OrderRequest>'
332
+
333
+ # Success Response (200 OK):
334
+ <?xml version="1.0" encoding="UTF-8"?>
335
+ <OrderResponse xmlns="http://api.example.com/schema/order/1.0">
336
+ <Order>
337
+ <OrderId>ORD-12345</OrderId>
338
+ <Status>COMPLETED</Status>
339
+ <TotalPrice currency="USD">199.99</TotalPrice>
340
+ ...
341
+ </Order>
342
+ </OrderResponse>
343
+
344
+ # Error Response (500 Internal Server Error):
345
+ <?xml version="1.0" encoding="UTF-8"?>
346
+ <OrderResponse xmlns="http://api.example.com/schema/order/1.0">
347
+ <Error>
348
+ <Code>PROCESSING_ERROR</Code>
349
+ <Message>Order not found: ORD-12345</Message>
350
+ <Timestamp>2025-01-15T10:30:00Z</Timestamp>
351
+ </Error>
352
+ </OrderResponse>
353
+ ```
354
+
355
+ ### Example 3: HTML Response
356
+
357
+ Return HTML pages from webhooks (useful for status pages, documentation):
358
+
359
+ ```typescript
360
+ import { webhook, fn } from '@versori/run';
361
+
362
+ export const statusPage = webhook('status', {
363
+ response: {
364
+ mode: 'sync',
365
+ onSuccess: (ctx) => new Response(ctx.data, {
366
+ status: 200,
367
+ headers: { 'Content-Type': 'text/html; charset=utf-8' }
368
+ })
369
+ }
370
+ })
371
+ .then(fn('generate-html', () => {
372
+ return `<!DOCTYPE html>
373
+ <html lang="en">
374
+ <head>
375
+ <meta charset="UTF-8">
376
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
377
+ <title>Service Status</title>
378
+ <style>
379
+ body {
380
+ font-family: Arial, sans-serif;
381
+ max-width: 800px;
382
+ margin: 50px auto;
383
+ padding: 20px;
384
+ }
385
+ .status {
386
+ padding: 20px;
387
+ background-color: #4CAF50;
388
+ color: white;
389
+ border-radius: 5px;
390
+ }
391
+ .service {
392
+ margin: 10px 0;
393
+ padding: 10px;
394
+ border: 1px solid #ddd;
395
+ border-radius: 3px;
396
+ }
397
+ </style>
398
+ </head>
399
+ <body>
400
+ <h1>Service Status Dashboard</h1>
401
+ <div class="status">
402
+ <h2>✓ All Systems Operational</h2>
403
+ </div>
404
+ <div class="service">
405
+ <h3>Inventory Ingestion</h3>
406
+ <p>Status: <strong>Operational</strong></p>
407
+ <p>Last Run: ${new Date().toISOString()}</p>
408
+ </div>
409
+ <div class="service">
410
+ <h3>Order Processing</h3>
411
+ <p>Status: <strong>Operational</strong></p>
412
+ </div>
413
+ </body>
414
+ </html>`;
415
+ }));
416
+ ```
417
+
418
+ ### Example 4: CSV Response
419
+
420
+ Download data as CSV files:
421
+
422
+ ```typescript
423
+ import { webhook, fn, http } from '@versori/run';
424
+ import { createClient } from '@fluentcommerce/fc-connect-sdk';
425
+
426
+ export const exportInventory = webhook('export-inventory-csv', {
427
+ response: {
428
+ mode: 'sync',
429
+ onSuccess: (ctx) => new Response(ctx.data, {
430
+ status: 200,
431
+ headers: {
432
+ 'Content-Type': 'text/csv; charset=utf-8',
433
+ 'Content-Disposition': 'attachment; filename="inventory-export.csv"'
434
+ }
435
+ })
436
+ }
437
+ })
438
+ .then(http('fetch-inventory', {
439
+ connection: 'fluent_commerce'
440
+ }, async (ctx) => {
441
+ const client = await createClient(ctx);
442
+ const result = await client.graphql({
443
+ query: `query {
444
+ inventoryQuantities(first: 100) {
445
+ edges {
446
+ node {
447
+ ref
448
+ quantity
449
+ location { ref }
450
+ product { ref name }
451
+ }
452
+ }
453
+ }
454
+ }`
455
+ });
456
+
457
+ return { items: result.data.inventoryQuantities.edges };
458
+ }))
459
+ .then(fn('build-csv', ({ data }) => {
460
+ // CSV Header
461
+ let csv = 'SKU,Product Name,Location,Quantity\n';
462
+
463
+ // CSV Rows
464
+ data.items.forEach(edge => {
465
+ const item = edge.node;
466
+ const sku = item.product?.ref || '';
467
+ const name = (item.product?.name || '').replace(/"/g, '""'); // Escape quotes
468
+ const location = item.location?.ref || '';
469
+ const qty = item.quantity || 0;
470
+
471
+ csv += `"${sku}","${name}","${location}",${qty}\n`;
472
+ });
473
+
474
+ return csv;
475
+ }));
476
+ ```
477
+
478
+ ### Example 5: Plain Text Response
479
+
480
+ Health check or simple text endpoints:
481
+
482
+ ```typescript
483
+ import { webhook, fn } from '@versori/run';
484
+
485
+ export const healthCheck = webhook('health', {
486
+ response: {
487
+ mode: 'sync',
488
+ onSuccess: (ctx) => new Response(ctx.data, {
489
+ status: 200,
490
+ headers: { 'Content-Type': 'text/plain; charset=utf-8' }
491
+ })
492
+ }
493
+ })
494
+ .then(fn('check-health', () => {
495
+ const uptime = process.uptime();
496
+ const timestamp = new Date().toISOString();
497
+
498
+ return `Service Status: Operational
499
+ Uptime: ${uptime.toFixed(0)} seconds
500
+ Timestamp: ${timestamp}
501
+ }));
502
+ ```
503
+
504
+ ## Key Patterns Explained
505
+
506
+ ### Pattern 1: Why Custom Response Objects Are Needed
507
+
508
+ **The Technical Details:**
509
+
510
+ Versori's `sendResponse()` function (from @versori/run v0.4.4):
511
+
512
+ ```typescript
513
+ function sendResponse(res, response) {
514
+ res.status(response.status);
515
+ response.headers.forEach((value, key) => {
516
+ res.setHeader(key, value);
517
+ });
518
+ if (response.body) {
519
+ pipeline(response.body, res); // Streams directly without encoding
520
+ }
521
+ }
522
+ ```
523
+
524
+ **Key insight:** When you return a `Response` object, Versori uses Node.js `pipeline()` to stream the body directly to the HTTP response **without any JSON encoding**.
525
+
526
+ **Default handlers** (when you don't provide custom ones):
527
+
528
+ ```typescript
529
+ // Simplified version of default behavior
530
+ const defaultOnSuccess = (ctx) => {
531
+ return JSON.stringify(ctx.data); // ❌ Encodes everything as JSON
532
+ };
533
+ ```
534
+
535
+ ### Pattern 2: onSuccess Handler Pattern
536
+
537
+ The `onSuccess` handler receives context and must return a `Response` object:
538
+
539
+ ```typescript
540
+ onSuccess: (ctx) => {
541
+ // ctx.data = output from final .then() step
542
+ // ctx.executionId = unique execution ID
543
+ // ctx.metadata = any metadata from workflow
544
+
545
+ return new Response(ctx.data, {
546
+ status: 200, // HTTP status code
547
+ headers: {
548
+ 'Content-Type': 'application/xml; charset=utf-8',
549
+ 'X-Execution-Id': ctx.executionId,
550
+ 'Cache-Control': 'no-cache',
551
+ // Any custom headers...
552
+ }
553
+ });
554
+ }
555
+ ```
556
+
557
+ **Important:** Your workflow steps should return **raw strings**, not Response objects. The handler wraps them.
558
+
559
+ ### Pattern 3: onError Handler Pattern
560
+
561
+ The `onError` handler handles exceptions and should match the content type:
562
+
563
+ ```typescript
564
+ onError: (ctx) => {
565
+ // ctx.data = error from .catch() or thrown exception
566
+ // ctx.executionId = unique execution ID
567
+
568
+ return new Response(ctx.data, {
569
+ status: 500, // or 400, 404, etc.
570
+ headers: {
571
+ 'Content-Type': 'application/xml; charset=utf-8', // Match success type!
572
+ 'X-Execution-Id': ctx.executionId
573
+ }
574
+ });
575
+ }
576
+ ```
577
+
578
+ **Best practice:** Use the same Content-Type for errors as for success responses. If your API returns XML on success, return XML errors too.
579
+
580
+ ### Pattern 4: Content-Type Headers
581
+
582
+ Always include charset for text-based formats:
583
+
584
+ ```typescript
585
+ // ✅ CORRECT - Includes charset
586
+ 'Content-Type': 'application/xml; charset=utf-8'
587
+ 'Content-Type': 'text/html; charset=utf-8'
588
+ 'Content-Type': 'text/csv; charset=utf-8'
589
+ 'Content-Type': 'text/plain; charset=utf-8'
590
+
591
+ // ❌ INCOMPLETE - Missing charset (may work but not recommended)
592
+ 'Content-Type': 'application/xml'
593
+
594
+ // ✅ CORRECT - Binary formats don't need charset
595
+ 'Content-Type': 'application/pdf'
596
+ 'Content-Type': 'image/png'
597
+ ```
598
+
599
+ ### Pattern 5: XMLBuilder Integration
600
+
601
+ Using `fast-xml-parser` to generate clean XML:
602
+
603
+ ```typescript
604
+ import { XMLBuilder } from 'fast-xml-parser';
605
+
606
+ // Initialize builder with options
607
+ const builder = new XMLBuilder({
608
+ ignoreAttributes: false, // Include XML attributes
609
+ attributeNamePrefix: '@', // Prefix for attributes
610
+ textNodeName: '#text', // Key for text content
611
+ format: true, // Pretty-print
612
+ indentBy: ' ', // Indentation
613
+ suppressEmptyNode: true // Don't output <tag></tag> for nulls
614
+ });
615
+
616
+ // Define XML structure
617
+ const xmlObject = {
618
+ '?xml': { // XML declaration
619
+ '@version': '1.0',
620
+ '@encoding': 'UTF-8'
621
+ },
622
+ Root: {
623
+ '@xmlns': 'http://...', // Root attributes start with @
624
+ Child: 'value',
625
+ Another: {
626
+ '@id': '123', // Element with attribute and text
627
+ '#text': 'content'
628
+ },
629
+ List: {
630
+ Item: ['item1', 'item2'] // Arrays become multiple elements
631
+ }
632
+ }
633
+ };
634
+
635
+ // Generate XML string
636
+ const xmlString = builder.build(xmlObject);
637
+ ```
638
+
639
+ **Generated Output:**
640
+
641
+ ```xml
642
+ <?xml version="1.0" encoding="UTF-8"?>
643
+ <Root xmlns="http://...">
644
+ <Child>value</Child>
645
+ <Another id="123">content</Another>
646
+ <List>
647
+ <Item>item1</Item>
648
+ <Item>item2</Item>
649
+ </List>
650
+ </Root>
651
+ ```
652
+
653
+ ## The JSON Encoding Problem
654
+
655
+ ### Side-by-Side Comparison
656
+
657
+ #### ❌ WRONG: Default Behavior (JSON-Encoded)
658
+
659
+ ```typescript
660
+ export const badXmlEndpoint = webhook('bad-xml', async (ctx) => {
661
+ return '<?xml version="1.0"?><order><id>123</id></order>';
662
+ });
663
+ ```
664
+
665
+ **What the client receives:**
666
+
667
+ ```bash
668
+ $ curl https://workspace.versori.run/bad-xml
669
+
670
+ # Response:
671
+ "<?xml version=\"1.0\"?><order><id>123</id></order>"
672
+
673
+ # Response Headers:
674
+ Content-Type: application/json
675
+ Content-Length: 52
676
+ ```
677
+
678
+ **Problems:**
679
+
680
+ 1. XML is wrapped in quotes
681
+ 2. Special characters are escaped (`\n`, `\"`)
682
+ 3. Content-Type is JSON, not XML
683
+ 4. Cannot be parsed as XML by clients
684
+ 5. Requires client-side JSON parsing then XML parsing
685
+
686
+ #### ✅ RIGHT: Custom Response Objects
687
+
688
+ ```typescript
689
+ export const goodXmlEndpoint = webhook('good-xml', {
690
+ response: {
691
+ mode: 'sync',
692
+ onSuccess: (ctx) => new Response(ctx.data, {
693
+ status: 200,
694
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
695
+ })
696
+ }
697
+ })
698
+ .then(fn('gen', () => '<?xml version="1.0"?><order><id>123</id></order>'));
699
+ ```
700
+
701
+ **What the client receives:**
702
+
703
+ ```bash
704
+ $ curl https://workspace.versori.run/good-xml
705
+
706
+ # Response:
707
+ <?xml version="1.0"?><order><id>123</id></order>
708
+
709
+ # Response Headers:
710
+ Content-Type: application/xml; charset=utf-8
711
+ Content-Length: 47
712
+ ```
713
+
714
+ **Benefits:**
715
+
716
+ 1. Raw XML delivered to client
717
+ 2. No escaping or encoding
718
+ 3. Correct Content-Type header
719
+ 4. Client can parse directly as XML
720
+ 5. Standard HTTP semantics
721
+
722
+ ### Visual Example: What Gets Sent
723
+
724
+ **Bad (JSON-encoded):**
725
+
726
+ ```
727
+ HTTP/1.1 200 OK
728
+ Content-Type: application/json
729
+
730
+ "<?xml version=\"1.0\"?><order><id>123</id></order>"
731
+ ```
732
+
733
+ **Good (Raw XML):**
734
+
735
+ ```
736
+ HTTP/1.1 200 OK
737
+ Content-Type: application/xml; charset=utf-8
738
+
739
+ <?xml version="1.0"?><order><id>123</id></order>
740
+ ```
741
+
742
+ ## Common Issues and Solutions
743
+
744
+ ### Issue 1: XML Still Being JSON-Encoded
745
+
746
+ **Symptom:** Response is wrapped in quotes with escaped characters.
747
+
748
+ **Cause:** Missing custom response handlers.
749
+
750
+ **Solution:**
751
+
752
+ ```typescript
753
+ // ❌ Missing handlers
754
+ export const endpoint = webhook('test')
755
+ .then(fn('gen', () => '<xml>data</xml>'));
756
+
757
+ // ✅ Add custom handlers
758
+ export const endpoint = webhook('test', {
759
+ response: {
760
+ mode: 'sync',
761
+ onSuccess: (ctx) => new Response(ctx.data, {
762
+ status: 200,
763
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
764
+ })
765
+ }
766
+ })
767
+ .then(fn('gen', () => '<xml>data</xml>'));
768
+ ```
769
+
770
+ ### Issue 2: Wrong Content-Type in Response
771
+
772
+ **Symptom:** Browser tries to download file or displays incorrectly.
773
+
774
+ **Cause:** Content-Type doesn't match actual content.
775
+
776
+ **Solution:**
777
+
778
+ ```typescript
779
+ // ❌ WRONG - XML with JSON content type
780
+ headers: { 'Content-Type': 'application/json' }
781
+
782
+ // ✅ RIGHT - Match content type to content
783
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
784
+ ```
785
+
786
+ **Content-Type Reference:**
787
+
788
+ - XML: `application/xml; charset=utf-8`
789
+ - HTML: `text/html; charset=utf-8`
790
+ - CSV: `text/csv; charset=utf-8`
791
+ - Plain text: `text/plain; charset=utf-8`
792
+ - JSON: `application/json` (default, no custom handler needed)
793
+
794
+ ### Issue 3: Error Responses Return JSON Instead of XML
795
+
796
+ **Symptom:** Success returns XML, but errors return JSON.
797
+
798
+ **Cause:** Missing `onError` handler.
799
+
800
+ **Solution:**
801
+
802
+ ```typescript
803
+ export const endpoint = webhook('test', {
804
+ response: {
805
+ mode: 'sync',
806
+ onSuccess: (ctx) => new Response(ctx.data, {
807
+ status: 200,
808
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
809
+ }),
810
+ // ✅ Add error handler with same content type
811
+ onError: (ctx) => new Response(ctx.data, {
812
+ status: 500,
813
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
814
+ })
815
+ }
816
+ })
817
+ .then(fn('gen', () => '<success/>'))
818
+ .catch(() => '<error/>'); // Make sure .catch() returns XML string
819
+ ```
820
+
821
+ ### Issue 4: Accidental Double-Encoding
822
+
823
+ **Symptom:** Response has extra quotes or escaped characters.
824
+
825
+ **Cause:** Calling `JSON.stringify()` on data before returning.
826
+
827
+ **Solution:**
828
+
829
+ ```typescript
830
+ // ❌ WRONG - Don't stringify in handler
831
+ onSuccess: (ctx) => new Response(JSON.stringify(ctx.data), {
832
+ status: 200,
833
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
834
+ })
835
+
836
+ // ✅ RIGHT - Pass raw data
837
+ onSuccess: (ctx) => new Response(ctx.data, {
838
+ status: 200,
839
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
840
+ })
841
+ ```
842
+
843
+ ## Testing Your Implementation
844
+
845
+ ### Test 1: Verify Content-Type Header
846
+
847
+ ```bash
848
+ # Check response headers
849
+ curl -v https://your-workspace.versori.run/your-endpoint
850
+
851
+ # Look for:
852
+ # ✅ Content-Type: application/xml; charset=utf-8
853
+ # ❌ Content-Type: application/json
854
+ ```
855
+
856
+ ### Test 2: Verify Raw Content
857
+
858
+ ```bash
859
+ # Get response body
860
+ curl https://your-workspace.versori.run/your-endpoint
861
+
862
+ # Expected (raw XML):
863
+ # <?xml version="1.0" encoding="UTF-8"?>
864
+ # <order><id>123</id></order>
865
+
866
+ # NOT expected (JSON-encoded):
867
+ # "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<order><id>123</id></order>"
868
+ ```
869
+
870
+ ### Test 3: Verify Error Handling
871
+
872
+ ```bash
873
+ # Trigger an error (send invalid request)
874
+ curl -X POST https://your-workspace.versori.run/your-endpoint \
875
+ -H "Content-Type: application/xml" \
876
+ -d '<?xml version="1.0"?><Invalid/>'
877
+
878
+ # Should return:
879
+ # - Status: 500 (or appropriate error code)
880
+ # - Content-Type: application/xml (same as success)
881
+ # - Body: XML error message
882
+ ```
883
+
884
+ ### Test 4: XML Parser Validation
885
+
886
+ ```bash
887
+ # Pipe response through xmllint to validate XML
888
+ curl https://your-workspace.versori.run/your-endpoint | xmllint --format -
889
+
890
+ # Should format successfully without errors
891
+ ```
892
+
893
+ ## Implementation Checklist
894
+
895
+ When implementing non-JSON webhooks, verify:
896
+
897
+ - [ ] Webhook configured with `response.mode: 'sync'`
898
+ - [ ] `onSuccess` handler defined and returns `Response` object
899
+ - [ ] `onError` handler defined and returns `Response` object
900
+ - [ ] Both handlers set correct `Content-Type` header
901
+ - [ ] Content-Type includes `charset=utf-8` for text formats
902
+ - [ ] Workflow `.then()` steps return raw strings (not Response objects)
903
+ - [ ] Workflow `.catch()` returns error string in correct format
904
+ - [ ] Status codes are appropriate (200, 400, 500, etc.)
905
+ - [ ] Error handler uses same Content-Type as success handler
906
+ - [ ] Tested with curl to verify raw output (no JSON encoding)
907
+ - [ ] Tested error scenarios return proper format
908
+ - [ ] No `JSON.stringify()` calls in custom handlers
909
+ - [ ] XML validated with parser (if XML response)
910
+
911
+
912
+ ## Versori Syntax Validation
913
+
914
+ ### Critical: Buffer Import Required
915
+
916
+ **For Deno/Versori runtime, ALWAYS import Buffer explicitly:**
917
+
918
+ ```typescript
919
+ // ✅ CORRECT - Explicit import required
920
+ import { Buffer } from 'node:buffer';
921
+
922
+ // Use Buffer for encoding operations
923
+ await sftp.uploadFile('utf8', Buffer.from(xmlContent), '/path/file.xml');
924
+ const decoded = Buffer.from(base64String, 'base64').toString('utf-8');
925
+ ```
926
+
927
+ **Why:** Deno runtime doesn't have `Buffer` as a global (unlike Node.js). Missing this import will cause runtime errors.
928
+
929
+ ### Validated Syntax Patterns for SDK ^0.1.27
930
+
931
+ #### 1. Webhook Response Configuration
932
+
933
+ ```typescript
934
+ // ✅ CORRECT - Webhook with custom response handlers
935
+ export const endpoint = webhook('name', {
936
+ response: {
937
+ mode: 'sync', // Required for custom handlers
938
+ onSuccess: (ctx) => new Response(ctx.data, {
939
+ status: 200,
940
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
941
+ }),
942
+ onError: (ctx) => new Response(ctx.data, {
943
+ status: 500,
944
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
945
+ })
946
+ },
947
+ cors: true // Optional CORS configuration
948
+ })
949
+ .then(fn('step', () => '<xml/>'));
950
+
951
+ // ❌ WRONG - Missing response configuration
952
+ export const endpoint = webhook('name', async (ctx) => {
953
+ return '<xml/>'; // Will be JSON-encoded!
954
+ });
955
+ ```
956
+
957
+ #### 2. Client Factory Usage
958
+
959
+ ```typescript
960
+ // ✅ CORRECT - Use createClient() factory
961
+ import { createClient } from '@fluentcommerce/fc-connect-sdk';
962
+
963
+ export const endpoint = webhook('name', {
964
+ connection: 'fluent_commerce'
965
+ }, async (ctx) => {
966
+ const client = await createClient(ctx);
967
+ // Client automatically configured from connection
968
+ });
969
+
970
+ // ❌ WRONG - Direct instantiation bypasses context detection
971
+ import { FluentClient } from '@fluentcommerce/fc-connect-sdk';
972
+ const client = new FluentClient(config); // Don't do this in Versori
973
+ ```
974
+
975
+ #### 3. Logging Best Practices
976
+
977
+ ```typescript
978
+ // ✅ CORRECT - Use native log from context
979
+ export const endpoint = webhook('name', {
980
+ connection: 'fluent_commerce'
981
+ }, async (ctx) => {
982
+ const { log } = ctx;
983
+ log('Processing started', { orderId: '123' });
984
+
985
+ // SDK client receives log automatically
986
+ const client = await createClient(ctx);
987
+ });
988
+
989
+ // ❌ WRONG - Don't use LoggingService in Versori
990
+ import { LoggingService } from '@fluentcommerce/fc-connect-sdk';
991
+ const logger = new LoggingService(); // Not needed in Versori
992
+ ```
993
+
994
+ #### 4. Auto-Pagination Syntax
995
+
996
+ ```typescript
997
+ // ✅ CORRECT - pagination object (NOT config)
998
+ const result = await client.graphql({
999
+ query,
1000
+ variables: { first: 100 },
1001
+ pagination: { // Use 'pagination', not 'config'
1002
+ maxPages: 50,
1003
+ pageSize: 100
1004
+ }
1005
+ });
1006
+
1007
+ // ❌ WRONG - Old syntax with 'config'
1008
+ const result = await client.graphql({
1009
+ query,
1010
+ variables: { first: 100 },
1011
+ config: { // Use 'pagination' parameter instead
1012
+ maxPages: 50
1013
+ }
1014
+ });
1015
+ ```
1016
+
1017
+ #### 5. SDK Version Specification
1018
+
1019
+ ```json
1020
+ {
1021
+ "dependencies": {
1022
+ "@fluentcommerce/fc-connect-sdk": "^0.1.39",
1023
+ "@versori/run": "latest",
1024
+ "fast-xml-parser": "^4.3.0"
1025
+ }
1026
+ }
1027
+ ```
1028
+
1029
+ #### 6. Workflow Step Return Values
1030
+
1031
+ ```typescript
1032
+ // ✅ CORRECT - Return raw data, let handlers wrap it
1033
+ export const endpoint = webhook('name', {
1034
+ response: {
1035
+ mode: 'sync',
1036
+ onSuccess: (ctx) => new Response(ctx.data, {
1037
+ status: 200,
1038
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
1039
+ })
1040
+ }
1041
+ })
1042
+ .then(fn('generate', () => {
1043
+ return '<xml>data</xml>'; // Return raw string
1044
+ }));
1045
+
1046
+ // ❌ WRONG - Don't return Response objects from workflow steps
1047
+ export const endpoint = webhook('name', {
1048
+ response: { mode: 'sync', onSuccess: (ctx) => ctx.data }
1049
+ })
1050
+ .then(fn('generate', () => {
1051
+ return new Response('<xml>data</xml>'); // Wrong! Handler should do this
1052
+ }));
1053
+ ```
1054
+
1055
+ #### 7. Error Handling Pattern
1056
+
1057
+ ```typescript
1058
+ // ✅ CORRECT - .catch() returns error data, onError wraps it
1059
+ export const endpoint = webhook('name', {
1060
+ response: {
1061
+ mode: 'sync',
1062
+ onSuccess: (ctx) => new Response(ctx.data, {
1063
+ status: 200,
1064
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
1065
+ }),
1066
+ onError: (ctx) => new Response(ctx.data, {
1067
+ status: 500,
1068
+ headers: { 'Content-Type': 'application/xml; charset=utf-8' }
1069
+ })
1070
+ }
1071
+ })
1072
+ .then(fn('process', () => '<success/>'))
1073
+ .catch((error) => {
1074
+ // Return error XML string - onError handler will wrap it
1075
+ return `<error>${error.message}</error>`;
1076
+ });
1077
+
1078
+ // ❌ WRONG - Throwing without catch or returning Response
1079
+ export const endpoint = webhook('name')
1080
+ .then(fn('process', () => {
1081
+ throw new Error('Failed'); // Will cause 500 with JSON error
1082
+ }));
1083
+ ```
1084
+
1085
+ ### Validation Checklist
1086
+
1087
+ Before deploying to Versori, verify:
1088
+
1089
+ **Syntax:**
1090
+ - [ ] Buffer explicitly imported: `import { Buffer } from 'node:buffer';`
1091
+ - [ ] webhook() has response.mode: 'sync' for custom handlers
1092
+ - [ ] onSuccess and onError both defined
1093
+ - [ ] Both handlers return Response objects
1094
+ - [ ] Workflow steps return raw data (not Response objects)
1095
+
1096
+ **SDK Integration:**
1097
+ - [ ] createClient() used (not direct instantiation)
1098
+ - [ ] Native ctx.log used (not LoggingService)
1099
+ - [ ] Auto-pagination uses 'pagination' object (not 'config')
1100
+ - [ ] SDK version is ^0.1.27 or later
1101
+
1102
+ **Response Handling:**
1103
+ - [ ] Content-Type headers match actual content
1104
+ - [ ] charset=utf-8 included for text formats
1105
+ - [ ] onError uses same Content-Type as onSuccess
1106
+ - [ ] Error .catch() returns proper format string
1107
+
1108
+ **Testing:**
1109
+ - [ ] Tested with curl to verify raw output
1110
+ - [ ] Verified Content-Type header is correct
1111
+ - [ ] Tested error scenarios return proper format
1112
+ - [ ] Validated XML with parser (if XML)
1113
+
1114
+ ## Version Compatibility
1115
+
1116
+ This pattern works with:
1117
+
1118
+ **Versori Runtime:**
1119
+ - @versori/run v0.4.4 (latest stable)
1120
+ - @versori/run v0.4.3
1121
+ - @versori/run v0.4.2
1122
+ - @versori/run v0.4.1
1123
+ - @versori/run v0.4.0
1124
+ - @versori/run v0.4.0-alpha.2
1125
+
1126
+ All v0.4.x versions use the same `sendResponse()` implementation that streams Response objects directly.
1127
+
1128
+ **FC Connect SDK:**
1129
+ - @fluentcommerce/fc-connect-sdk v0.1.27+
1130
+ - @fluentcommerce/fc-connect-sdk v0.1.26
1131
+ - @fluentcommerce/fc-connect-sdk v0.1.25
1132
+ - All v0.1.x versions support Versori platform integration
1133
+
1134
+ ## Related Guides
1135
+
1136
+ - **[Versori Platform Integration](../../../04-REFERENCE/platforms/versori/)** - Complete Versori platform guide
1137
+ - **[GraphQL Mutation Mapping Guide](../../../02-CORE-GUIDES/mapping/graphql-mutation-mapping/)** - XML/JSON to GraphQL mutations
1138
+ - **[Universal Mapping Guide](../../../02-CORE-GUIDES/mapping/)** - Field transformation patterns
1139
+ - **[Webhook Validation Guide](../../../02-CORE-GUIDES/webhook-validation/)** - Webhook signature validation
1140
+
1141
+ ## Real-World Example Reference
1142
+
1143
+ See complete production implementation:
1144
+
1145
+ - **File**: `Sandbox Hibbet SFCC to Fluent Order integration (1)/src/workflows/process-order-detail-request.ts`
1146
+ - **Pattern**: XML request → GraphQL query → XML response
1147
+ - **Features**: Full error handling, extraction mapping, XMLBuilder integration
1148
+
1149
+ ## Summary
1150
+
1151
+ **Golden Rule:** For non-JSON content types in Versori webhooks, **ALWAYS** use custom `onSuccess` and `onError` handlers that return `Response` objects with the correct Content-Type header.
1152
+
1153
+ **Why It Matters:**
1154
+
1155
+ - Default handlers JSON-encode all responses (breaks XML/HTML/CSV)
1156
+ - Custom handlers bypass encoding and stream content directly
1157
+ - Proper Content-Type headers ensure correct client behavior
1158
+ - Consistent error handling provides better API experience
1159
+
1160
+ **Impact:** This pattern saves hours of debugging and ensures proper content delivery for XML APIs, HTML pages, CSV exports, and other non-JSON formats. It's critical for SOAP integrations, enterprise systems, and file downloads.