@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.55

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 (475) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/clients/fluent-client.js +13 -6
  3. package/dist/cjs/utils/pagination-helpers.js +38 -2
  4. package/dist/cjs/versori/fluent-versori-client.js +11 -5
  5. package/dist/esm/clients/fluent-client.js +13 -6
  6. package/dist/esm/utils/pagination-helpers.js +38 -2
  7. package/dist/esm/versori/fluent-versori-client.js +11 -5
  8. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  9. package/dist/tsconfig.tsbuildinfo +1 -1
  10. package/dist/tsconfig.types.tsbuildinfo +1 -1
  11. package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
  12. package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
  13. package/docs/00-START-HERE/cli-documentation-index.md +202 -202
  14. package/docs/00-START-HERE/cli-quick-reference.md +252 -252
  15. package/docs/00-START-HERE/decision-tree.md +552 -552
  16. package/docs/00-START-HERE/getting-started.md +1070 -1070
  17. package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
  18. package/docs/00-START-HERE/readme.md +237 -237
  19. package/docs/00-START-HERE/retailerid-configuration.md +404 -404
  20. package/docs/00-START-HERE/sdk-philosophy.md +794 -794
  21. package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
  22. package/docs/01-TEMPLATES/faq.md +686 -686
  23. package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
  24. package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
  25. package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
  26. package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
  27. package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
  28. package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
  29. package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
  30. package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
  31. package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
  32. package/docs/01-TEMPLATES/readme.md +957 -957
  33. package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
  34. package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
  35. package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
  36. package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
  37. package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
  38. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
  39. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
  40. package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
  41. package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
  42. package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
  43. package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
  44. package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
  45. package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
  46. package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
  47. package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
  48. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
  49. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
  50. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
  51. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
  52. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
  53. package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
  54. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
  55. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
  56. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
  57. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
  58. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
  59. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
  60. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
  61. package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
  62. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
  63. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
  64. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
  65. package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
  66. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
  67. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
  68. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
  69. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
  70. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
  71. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
  72. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
  73. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
  74. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
  75. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
  76. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
  77. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
  78. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
  79. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
  80. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
  81. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
  82. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
  83. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
  84. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
  85. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
  86. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
  87. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
  88. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
  89. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
  90. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
  91. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
  92. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
  93. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
  94. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
  95. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
  96. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
  97. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
  98. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
  99. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
  100. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
  101. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
  102. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
  103. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
  104. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
  105. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
  106. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
  107. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
  108. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
  109. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
  110. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
  111. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
  112. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
  113. package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
  114. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
  115. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
  116. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
  117. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
  118. package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
  119. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
  120. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
  121. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
  122. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
  123. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
  124. package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
  125. package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
  126. package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
  127. package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
  128. package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
  129. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
  130. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
  131. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
  132. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
  133. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
  134. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
  135. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
  136. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
  137. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
  138. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
  139. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
  140. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
  141. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
  142. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
  143. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
  144. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
  145. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
  146. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
  147. package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
  148. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
  149. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
  150. package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
  151. package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
  152. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
  153. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
  154. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
  155. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
  156. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
  157. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
  158. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
  159. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
  160. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
  161. package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
  162. package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
  163. package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
  164. package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
  165. package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
  166. package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
  167. package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
  168. package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
  169. package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
  170. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
  171. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
  172. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
  173. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
  174. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
  175. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
  176. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
  177. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
  178. package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
  179. package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
  180. package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
  181. package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
  182. package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
  183. package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
  184. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
  185. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
  186. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
  187. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
  188. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
  189. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
  190. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
  191. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
  192. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
  193. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
  194. package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
  195. package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
  196. package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
  197. package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
  198. package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
  199. package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
  200. package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
  201. package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
  202. package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
  203. package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
  204. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
  205. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
  206. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
  207. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
  208. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
  209. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
  210. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
  211. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
  212. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
  213. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
  214. package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
  215. package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
  216. package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
  217. package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
  218. package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
  219. package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
  220. package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
  221. package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
  222. package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
  223. package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
  224. package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
  225. package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
  226. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
  227. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
  228. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
  229. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
  230. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
  231. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
  232. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
  233. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
  234. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
  235. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
  236. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
  237. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
  238. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
  239. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
  240. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
  241. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
  242. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
  243. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
  244. package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
  245. package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
  246. package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
  247. package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
  248. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
  249. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
  250. package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
  251. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
  252. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
  253. package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
  254. package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
  255. package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
  256. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
  257. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
  258. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
  259. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
  260. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
  261. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
  262. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
  263. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
  264. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
  265. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
  266. package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
  267. package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
  268. package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
  269. package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
  270. package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
  271. package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
  272. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
  273. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
  274. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
  275. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
  276. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
  277. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
  278. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
  279. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
  280. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
  281. package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
  282. package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
  283. package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
  284. package/docs/02-CORE-GUIDES/readme.md +194 -194
  285. package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
  286. package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
  287. package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
  288. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
  289. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
  290. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
  291. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
  292. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
  293. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
  294. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
  295. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
  296. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
  297. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
  298. package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
  299. package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
  300. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
  301. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
  302. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
  303. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
  304. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
  305. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
  306. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
  307. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
  308. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
  309. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
  310. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
  311. package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
  312. package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
  313. package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
  314. package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
  315. package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
  316. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
  317. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
  318. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
  319. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
  320. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
  321. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
  322. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
  323. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
  324. package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
  325. package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
  326. package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
  327. package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
  328. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
  329. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
  330. package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
  331. package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
  332. package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
  333. package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
  334. package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
  335. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
  336. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
  337. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
  338. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
  339. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
  340. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
  341. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
  342. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
  343. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
  344. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
  345. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
  346. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
  347. package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
  348. package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
  349. package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
  350. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
  351. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
  352. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
  353. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
  354. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
  355. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
  356. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
  357. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
  358. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
  359. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
  360. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
  361. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
  362. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
  363. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
  364. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
  365. package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
  366. package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
  367. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
  368. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
  369. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
  370. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
  371. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
  372. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
  373. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
  374. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
  375. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
  376. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
  377. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
  378. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
  379. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
  380. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
  381. package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
  382. package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
  383. package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
  384. package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
  385. package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
  386. package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
  387. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
  388. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
  389. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
  390. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
  391. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
  392. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
  393. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
  394. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
  395. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
  396. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
  397. package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
  398. package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
  399. package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
  400. package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
  401. package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
  402. package/docs/03-PATTERN-GUIDES/readme.md +159 -159
  403. package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
  404. package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
  405. package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
  406. package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
  407. package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
  408. package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
  409. package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
  410. package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
  411. package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
  412. package/docs/04-REFERENCE/architecture/readme.md +279 -279
  413. package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
  414. package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
  415. package/docs/04-REFERENCE/platforms/readme.md +135 -135
  416. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
  417. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
  418. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
  419. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
  420. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
  421. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
  422. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
  423. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
  424. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
  425. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
  426. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
  427. package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
  428. package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
  429. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
  430. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
  431. package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
  432. package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
  433. package/docs/04-REFERENCE/readme.md +148 -148
  434. package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
  435. package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
  436. package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
  437. package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
  438. package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
  439. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
  440. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
  441. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
  442. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
  443. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
  444. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
  445. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
  446. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
  447. package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
  448. package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
  449. package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
  450. package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
  451. package/docs/04-REFERENCE/schema/readme.md +141 -141
  452. package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
  453. package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
  454. package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
  455. package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
  456. package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
  457. package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
  458. package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
  459. package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
  460. package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
  461. package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
  462. package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
  463. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
  464. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
  465. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
  466. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
  467. package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
  468. package/docs/04-REFERENCE/testing/readme.md +86 -86
  469. package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
  470. package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
  471. package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
  472. package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
  473. package/docs/template-loading-matrix.md +242 -242
  474. package/package.json +5 -3
  475. 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.