@fluentcommerce/fc-connect-sdk 0.1.54 โ†’ 0.1.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (476) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +11 -0
  3. package/dist/cjs/clients/fluent-client.js +13 -6
  4. package/dist/cjs/utils/pagination-helpers.js +38 -2
  5. package/dist/cjs/versori/fluent-versori-client.js +11 -5
  6. package/dist/esm/clients/fluent-client.js +13 -6
  7. package/dist/esm/utils/pagination-helpers.js +38 -2
  8. package/dist/esm/versori/fluent-versori-client.js +11 -5
  9. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  10. package/dist/tsconfig.tsbuildinfo +1 -1
  11. package/dist/tsconfig.types.tsbuildinfo +1 -1
  12. package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
  13. package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
  14. package/docs/00-START-HERE/cli-documentation-index.md +202 -202
  15. package/docs/00-START-HERE/cli-quick-reference.md +252 -252
  16. package/docs/00-START-HERE/decision-tree.md +552 -552
  17. package/docs/00-START-HERE/getting-started.md +1070 -1070
  18. package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
  19. package/docs/00-START-HERE/readme.md +237 -237
  20. package/docs/00-START-HERE/retailerid-configuration.md +404 -404
  21. package/docs/00-START-HERE/sdk-philosophy.md +794 -794
  22. package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
  23. package/docs/01-TEMPLATES/faq.md +686 -686
  24. package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
  25. package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
  26. package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
  27. package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
  28. package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
  29. package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
  30. package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
  31. package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
  32. package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
  33. package/docs/01-TEMPLATES/readme.md +957 -957
  34. package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
  35. package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
  36. package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
  37. package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
  38. package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
  39. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
  40. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
  41. package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
  42. package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
  43. package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
  44. package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
  45. package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
  46. package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
  47. package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
  48. package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
  49. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
  50. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
  51. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
  52. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
  53. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
  54. package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
  55. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
  56. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
  57. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
  58. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
  59. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
  60. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
  61. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
  62. package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
  63. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
  64. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
  65. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
  66. package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
  67. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
  68. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
  69. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
  70. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
  71. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
  72. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
  73. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
  74. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
  75. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
  76. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
  77. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
  78. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
  79. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
  80. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
  81. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
  82. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
  83. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
  84. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
  85. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
  86. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
  87. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
  88. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
  89. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
  90. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
  91. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
  92. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
  93. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
  94. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
  95. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
  96. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
  97. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
  98. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
  99. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
  100. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
  101. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
  102. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
  103. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
  104. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
  105. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
  106. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
  107. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
  108. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
  109. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
  110. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
  111. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
  112. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
  113. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
  114. package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
  115. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
  116. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
  117. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
  118. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
  119. package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
  120. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
  121. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
  122. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
  123. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
  124. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
  125. package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
  126. package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
  127. package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
  128. package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
  129. package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
  130. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
  131. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
  132. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
  133. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
  134. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
  135. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
  136. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
  137. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
  138. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
  139. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
  140. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
  141. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
  142. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
  143. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
  144. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
  145. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
  146. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
  147. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
  148. package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
  149. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
  150. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
  151. package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
  152. package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
  153. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
  154. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
  155. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
  156. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
  157. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
  158. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
  159. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
  160. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
  161. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
  162. package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
  163. package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
  164. package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
  165. package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
  166. package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
  167. package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
  168. package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
  169. package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
  170. package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
  171. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
  172. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
  173. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
  174. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
  175. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
  176. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
  177. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
  178. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
  179. package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
  180. package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
  181. package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
  182. package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
  183. package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
  184. package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
  185. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
  186. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
  187. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
  188. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
  189. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
  190. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
  191. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
  192. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
  193. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
  194. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
  195. package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
  196. package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
  197. package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
  198. package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
  199. package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
  200. package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
  201. package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
  202. package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
  203. package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
  204. package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
  205. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
  206. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
  207. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
  208. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
  209. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
  210. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
  211. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
  212. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
  213. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
  214. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
  215. package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
  216. package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
  217. package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
  218. package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
  219. package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
  220. package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
  221. package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
  222. package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
  223. package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
  224. package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
  225. package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
  226. package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
  227. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
  228. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
  229. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
  230. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
  231. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
  232. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
  233. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
  234. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
  235. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
  236. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
  237. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
  238. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
  239. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
  240. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
  241. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
  242. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
  243. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
  244. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
  245. package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
  246. package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
  247. package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
  248. package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
  249. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
  250. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
  251. package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
  252. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
  253. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
  254. package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
  255. package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
  256. package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
  257. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
  258. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
  259. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
  260. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
  261. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
  262. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
  263. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
  264. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
  265. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
  266. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
  267. package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
  268. package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
  269. package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
  270. package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
  271. package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
  272. package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
  273. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
  274. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
  275. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
  276. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
  277. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
  278. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
  279. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
  280. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
  281. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
  282. package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
  283. package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
  284. package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
  285. package/docs/02-CORE-GUIDES/readme.md +194 -194
  286. package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
  287. package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
  288. package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
  289. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
  290. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
  291. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
  292. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
  293. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
  294. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
  295. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
  296. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
  297. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
  298. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
  299. package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
  300. package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
  301. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
  302. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
  303. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
  304. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
  305. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
  306. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
  307. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
  308. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
  309. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
  310. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
  311. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
  312. package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
  313. package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
  314. package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
  315. package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
  316. package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
  317. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
  318. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
  319. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
  320. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
  321. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
  322. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
  323. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
  324. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
  325. package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
  326. package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
  327. package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
  328. package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
  329. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
  330. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
  331. package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
  332. package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
  333. package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
  334. package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
  335. package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
  336. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
  337. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
  338. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
  339. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
  340. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
  341. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
  342. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
  343. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
  344. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
  345. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
  346. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
  347. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
  348. package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
  349. package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
  350. package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
  351. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
  352. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
  353. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
  354. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
  355. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
  356. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
  357. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
  358. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
  359. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
  360. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
  361. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
  362. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
  363. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
  364. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
  365. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
  366. package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
  367. package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
  368. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
  369. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
  370. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
  371. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
  372. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
  373. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
  374. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
  375. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
  376. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
  377. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
  378. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
  379. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
  380. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
  381. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
  382. package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
  383. package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
  384. package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
  385. package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
  386. package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
  387. package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
  388. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
  389. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
  390. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
  391. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
  392. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
  393. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
  394. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
  395. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
  396. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
  397. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
  398. package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
  399. package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
  400. package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
  401. package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
  402. package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
  403. package/docs/03-PATTERN-GUIDES/readme.md +159 -159
  404. package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
  405. package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
  406. package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
  407. package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
  408. package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
  409. package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
  410. package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
  411. package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
  412. package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
  413. package/docs/04-REFERENCE/architecture/readme.md +279 -279
  414. package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
  415. package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
  416. package/docs/04-REFERENCE/platforms/readme.md +135 -135
  417. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
  418. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
  419. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
  420. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
  421. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
  422. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
  423. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
  424. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
  425. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
  426. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
  427. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
  428. package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
  429. package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
  430. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
  431. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
  432. package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
  433. package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
  434. package/docs/04-REFERENCE/readme.md +148 -148
  435. package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
  436. package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
  437. package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
  438. package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
  439. package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
  440. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
  441. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
  442. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
  443. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
  444. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
  445. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
  446. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
  447. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
  448. package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
  449. package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
  450. package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
  451. package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
  452. package/docs/04-REFERENCE/schema/readme.md +141 -141
  453. package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
  454. package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
  455. package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
  456. package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
  457. package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
  458. package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
  459. package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
  460. package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
  461. package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
  462. package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
  463. package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
  464. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
  465. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
  466. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
  467. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
  468. package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
  469. package/docs/04-REFERENCE/testing/readme.md +86 -86
  470. package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
  471. package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
  472. package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
  473. package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
  474. package/docs/template-loading-matrix.md +242 -242
  475. package/package.json +5 -3
  476. package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
@@ -1,1330 +1,1330 @@
1
- # Resolver Pattern Guide
2
-
3
- **FC Connect SDK - Transform Data with Custom Logic**
4
-
5
- Version: 2.0.0
6
- Last Updated: 2025-01-14
7
-
8
- ---
9
-
10
- ## ๐Ÿ“š Table of Contents
11
-
12
- 1. [Quick Start (5 Minutes)](#quick-start-5-minutes)
13
- 2. [Core Concepts](#core-concepts)
14
- 3. [Real-World Examples](#real-world-examples)
15
- 4. [Advanced Topics](#advanced-topics)
16
- - [Async Operations & API Calls](#async-operations--api-calls)
17
- - [Error Handling Patterns](#error-handling-patterns)
18
- - [Performance Optimization](#performance-optimization)
19
- - [Resolver-Only Fields & Required Validation](#resolver-only-fields--required-validation) โ† NEW
20
- 5. [Reference Documentation](#reference-documentation)
21
-
22
- ---
23
-
24
- ## ๐ŸŽฏ What You'll Learn
25
-
26
- By the end of this guide, you'll be able to:
27
-
28
- โœ… Write custom resolver functions for complex transformations
29
- โœ… Use the ResolverBuilder API for clean, maintainable code
30
- โœ… Handle order management and inventory data transformations
31
- โœ… Work with async operations (API calls, database lookups)
32
- โœ… Apply best practices for production-ready resolvers
33
-
34
- **Time to Complete:** 30 minutes to 2 hours (depending on depth)
35
-
36
- ---
37
-
38
- ## Quick Start (5 Minutes)
39
-
40
- ### What are Resolvers?
41
-
42
- **Resolvers** are custom JavaScript functions that transform source data into the format required by Fluent Commerce. They're your solution when JSON mapping isn't enough.
43
-
44
- **Use resolvers when you need:**
45
-
46
- - ๐Ÿงฎ Complex calculations (totals, aggregations, formulas)
47
- - ๐Ÿ”€ Conditional logic (if-then-else transformations)
48
- - ๐ŸŒ External API calls (customer lookup, price checks)
49
- - ๐Ÿ”„ Cross-referencing data (resolve IDs to full objects)
50
- - โ™ป๏ธ Reusable transformation logic
51
-
52
- ---
53
-
54
- ### Your First Resolver
55
-
56
- Let's transform an order from our e-commerce system to Fluent Commerce.
57
-
58
- **Step 1: Install the SDK**
59
-
60
- ```bash
61
- npm install @fluentcommerce/fc-connect-sdk
62
- ```
63
-
64
- **Step 2: Create Your First Resolver**
65
-
66
- ```typescript
67
- import { createResolverBuilder, ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
68
-
69
- // Create a builder instance
70
- const builder = createResolverBuilder();
71
-
72
- // Define your resolvers
73
- const resolvers = builder
74
- // Simple field mapping: Extract order reference
75
- .from('input.ref', 'orders.order@order-no')
76
-
77
- // With transformation: Parse price to number
78
- .from('input.totalPrice', 'orders.order.totals.order-total.gross-price', value =>
79
- parseFloat(value)
80
- )
81
-
82
- // Build the resolver map
83
- .build();
84
-
85
- export default resolvers;
86
- ```
87
-
88
- **Step 3: Use in Your Workflow**
89
-
90
- ```typescript
91
- import { http } from '@versori/run';
92
- import { createClient, XMLParserService, ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
93
- import resolvers from './resolvers';
94
-
95
- // Versori workflow - ctx comes from workflow parameter
96
- export default http('processOrder', async (ctx) => { // โ† ctx defined here!
97
- const { log, activation, fetch } = ctx;
98
-
99
- // 1. Parse input XML
100
- const parser = new XMLParserService(log);
101
- const orderData = await parser.parseFromString(activation.body);
102
-
103
- // 2. Apply resolvers
104
- const config = {
105
- defaultRetailerId: activation.getVariable('RETAILER_ID'),
106
- apiToken: activation.getVariable('API_TOKEN')
107
- };
108
-
109
- const transformedData = {};
110
- for (const [path, resolver] of Object.entries(resolvers)) {
111
- const value = await resolver(orderData, config, ResolverHelpers, ctx);
112
- setNestedValue(transformedData, path, value);
113
- }
114
-
115
- // 3. Send to Fluent Commerce
116
- const client = await createClient({ ...ctx, log });
117
-
118
- const result = await client.graphql({
119
- query: `mutation CreateOrder($input: CreateOrderInput!) {
120
- createOrder(input: $input) { id ref }
121
- }`,
122
- variables: { input: transformedData },
123
- });
124
-
125
- return { success: true, data: result };
126
- });
127
-
128
- function setNestedValue(obj: any, path: string, value: any) {
129
- const keys = path.split('.');
130
- let current = obj;
131
- for (let i = 0; i < keys.length - 1; i++) {
132
- current[keys[i]] = current[keys[i]] || {};
133
- current = current[keys[i]];
134
- }
135
- current[keys[keys.length - 1]] = value;
136
- }
137
- ```
138
-
139
- **๐ŸŽ‰ That's it!** You've created and executed your first resolver.
140
-
141
- ---
142
-
143
- ### Test Your Resolver
144
-
145
- Use our canonical test data to verify your resolver works:
146
-
147
- ```typescript
148
- import { canonicalOrder } from '../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json';
149
- import { ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
150
-
151
- // Test the resolver
152
- const result = resolvers\['input.ref'](canonicalOrder, {}, ResolverHelpers);
153
- console.log(result); // Expected: "ORD-2025-001"
154
- ```
155
-
156
- โœ… **Expected Output:** `"ORD-2025-001"`
157
-
158
- ๐Ÿ“– **See:** [Complete test data structure](../../../03-PATTERN-GUIDES/examples/test-data/) for resolver testing examples
159
-
160
- ---
161
-
162
- ## Core Concepts
163
-
164
- ### JSON Mapping vs Resolvers
165
-
166
- **Use JSON Mapping when:**
167
-
168
- - Simple field-to-field mapping
169
- - Standard transformations (toString, toNumber)
170
- - Static data structures
171
-
172
- ```json
173
- {
174
- "ref": { "source": "order.orderNo" },
175
- "totalPrice": { "source": "order.total", "resolver": "sdk.number" }
176
- }
177
- ```
178
-
179
- **Use Resolvers when:**
180
-
181
- - Complex calculations or business logic
182
- - Conditional transformations
183
- - External API calls
184
- - Multiple source aggregation
185
-
186
- ```typescript
187
- builder.field('input.totalDiscount', (data, config, helpers) => {
188
- // Calculate from multiple sources
189
- const itemDiscounts = helpers.sum(data.order.items, 'discount');
190
- const couponValue = helpers.get(data, 'order.coupon.value', 0);
191
- return itemDiscounts + couponValue;
192
- });
193
- ```
194
-
195
- ---
196
-
197
- ### The Four Resolver Parameters
198
-
199
- Every resolver receives four parameters:
200
-
201
- ```typescript
202
- type ResolverFunction = (
203
- value: unknown, // Extracted value from 'source' path
204
- data: unknown, // Full data context (includes named nodes)
205
- config: unknown, // Configuration object
206
- helpers: Helpers // Utility functions
207
- ) => unknown | Promise<unknown>;
208
- ```
209
-
210
- **You don't have to use all four** - just what you need!
211
-
212
- ---
213
-
214
- #### 1. `value` - The Extracted Value
215
-
216
- **What:** The value extracted from the `source` path in your mapping.
217
-
218
- **When defined:** When your field has a `source` property
219
- **When undefined:** When your field only has a `resolver` (resolver-only field)
220
-
221
- **Example: Using `value` from source**
222
-
223
- ```typescript
224
- // Mapping config
225
- {
226
- "ref": {
227
- "source": "orders.order@order-no",
228
- "resolver": "custom.addPrefix"
229
- }
230
- }
231
-
232
- // Resolver
233
- 'custom.addPrefix': (value, data, config, helpers) => {
234
- // value = "ORD-2025-001" (extracted from source)
235
- return `ORDER-${value}`;
236
- // Returns: "ORDER-ORD-2025-001"
237
- }
238
- ```
239
-
240
- **Example: Resolver-only (no source)**
241
-
242
- ```typescript
243
- // Mapping config (NO source!)
244
- {
245
- "totalDiscount": {
246
- "resolver": "custom.calculateTotalDiscount"
247
- }
248
- }
249
-
250
- // Resolver
251
- 'custom.calculateTotalDiscount': (value, data, config, helpers) => {
252
- // value = undefined (no source specified)
253
- // Use 'data' to access full context
254
- const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem', []);
255
- return helpers.sum(helpers.ensureArray(items), item =>
256
- helpers.parseFloatSafe(item['base-price'], 0) - helpers.parseFloatSafe(item['net-price'], 0)
257
- );
258
- }
259
- ```
260
-
261
- **Important: Required Fields with Resolvers**
262
-
263
- When using `required: true` with resolvers, validation timing depends on whether the field has a `source`:
264
-
265
- **Fields with `source`**: Validation happens **before** resolver execution
266
- ```json
267
- {
268
- "discount": {
269
- "source": "order.subtotal",
270
- "resolver": "custom.calculateDiscount",
271
- "required": true
272
- }
273
- }
274
- ```
275
- - โœ… Checks if `order.subtotal` exists in source data first
276
- - โœ… If missing โ†’ mapping fails immediately (resolver never runs)
277
- - โœ… If present โ†’ resolver runs to transform the value
278
-
279
- **Resolver-only fields** (no `source`): Validation happens **after** resolver execution
280
- ```json
281
- {
282
- "uuid": {
283
- "resolver": "custom.generateUUID",
284
- "required": true
285
- }
286
- }
287
- ```
288
- - โœ… Resolver runs first to generate value
289
- - โœ… Then validates that resolver produced a value
290
- - โœ… If resolver returns `null`, `undefined`, or empty string โ†’ mapping fails
291
-
292
- **Why this matters:** Resolvers can return empty values. `required: true` ensures validation happens **after** the resolver runs to catch these cases. If your resolver has conditional logic that might return `undefined`, use `required: true` to ensure the field always has a value.
293
-
294
- ๐Ÿ“– **Learn more:** [Resolver Parameters Deep Dive](./mapping-resolvers-resolver-parameters-reference.md)
295
-
296
- ---
297
-
298
- #### 2. `data` - Full Data Context
299
-
300
- **What:** The complete data object, including all named nodes from your mapping config.
301
-
302
- **When to use:** When you need to access data from different parts of your payload or from named nodes.
303
-
304
- **Example: Accessing order data**
305
-
306
- ```typescript
307
- builder.field('input.customer.email', (data, config, helpers) => {
308
- // Access nested data safely
309
- return helpers.get(data, 'orders.order.customer.customer-email');
310
- });
311
- ```
312
-
313
- **Example: Using named nodes**
314
-
315
- Named nodes let you parse embedded XML/JSON within your payload:
316
-
317
- ```json
318
- {
319
- "nodes": {
320
- "radialXml": {
321
- "extract": "orders.order.custom-attributes.custom-attribute[attribute-id=RadialData]",
322
- "parse": "xml"
323
- }
324
- }
325
- }
326
- ```
327
-
328
- ```typescript
329
- builder.field('input.specialInstructions', (data, config, helpers) => {
330
- // 'data' now contains both original data AND parsed nodes
331
- // data = {
332
- // orders: { ... original data ... },
333
- // radialXml: { ... parsed XML ... }
334
- // }
335
-
336
- const radialData = data.radialXml;
337
- return helpers.get(radialData, 'Order.SpecialInstructions.Text');
338
- });
339
- ```
340
-
341
- ---
342
-
343
- #### 3. `config` - Configuration Object
344
-
345
- **What:** Settings and defaults passed when executing resolvers.
346
-
347
- **When to use:** For environment-specific values, defaults, or API credentials.
348
-
349
- **Example: Config with fallbacks**
350
-
351
- ```typescript
352
- // Standalone Pattern
353
- const config = {
354
- defaultRetailerId: '1',
355
- defaultCurrency: 'USD',
356
- apiToken: process.env.EXTERNAL_API_TOKEN,
357
- };
358
-
359
- // Versori Platform Pattern
360
- const config = {
361
- defaultRetailerId: activation.getVariable('FLUENT_RETAILER_ID'),
362
- defaultCurrency: activation.getVariable('DEFAULT_CURRENCY') || 'USD',
363
- // Credentials accessed via ctx.credentials() in resolver
364
- };
365
-
366
- builder.withConfigFallback(
367
- 'input.retailer.id',
368
- 'orders.order.retailerId',
369
- 'defaultRetailerId' // Fallback key in config
370
- );
371
- ```
372
-
373
- **Versori Credential Access in Resolvers:**
374
-
375
- ```typescript
376
- // Use in async resolver for external API calls
377
- builder.field('input.enrichedData', async (data, config, helpers, ctx) => {
378
- // Option 1: Get from activation variables
379
- const apiToken = ctx.activation.getVariable('EXTERNAL_API_TOKEN');
380
-
381
- // Option 2: Get from connection credentials
382
- const apiCreds = await ctx.credentials().getAccessToken('external_api');
383
-
384
- const response = await ctx.fetch('https://api.example.com/enrich', {
385
- method: 'POST',
386
- headers: {
387
- 'Authorization': `Bearer ${apiCreds?.accessToken || apiToken}`,
388
- 'Content-Type': 'application/json'
389
- },
390
- body: JSON.stringify(data)
391
- });
392
-
393
- return response.json();
394
- });
395
- ```
396
-
397
- ---
398
-
399
- #### 4. `helpers` - Utility Functions
400
-
401
- **What:** Collection of 54 helper functions for common transformations.
402
-
403
- **Available helpers:**
404
-
405
- - **Data access:** `get()`, `ensureArray()`
406
- - **Parsing:** `parseFloatSafe()`, `parseIntSafe()`, `safeJsonParse()`
407
- - **Formatting:** `formatDate()`, `formatCurrency()`
408
- - **Arrays:** `sum()`, `avg()`, `groupBy()`, `chunk()`, `flatten()`
409
- - **Strings:** `slugify()`, `template()`, `truncate()`
410
- - **Validation:** `isValidEmail()`, `requireField()`
411
- - **Async:** `retry()`, `batchProcess()`
412
-
413
- **Example: Using helpers**
414
-
415
- ```typescript
416
- builder.field('input.items', (data, config, helpers) => {
417
- // Safe path access
418
- const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem');
419
-
420
- // Handle XML single vs array
421
- const itemsArray = helpers.ensureArray(items);
422
-
423
- // Transform with safe parsing
424
- return itemsArray.map(item => ({
425
- ref: item['@lineitem-id'],
426
- quantity: helpers.parseIntSafe(item.quantity, 1),
427
- price: helpers.parseFloatSafe(item['base-price'], 0),
428
- }));
429
- });
430
- ```
431
-
432
- ๐Ÿ“– **See all helpers:** [Resolver Helpers Reference](./mapping-resolvers-resolver-helpers-reference.md)
433
-
434
- ---
435
-
436
- ## Real-World Examples
437
-
438
- All examples use our **canonical datasets** for consistency. You can test every example!
439
-
440
- ๐Ÿ“ **Test Data:**
441
-
442
- - [canonical-order.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json) - Order management
443
- - [canonical-inventory.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json) - Inventory management
444
-
445
- ---
446
-
447
- ### Example 1: Order Management - Simple Transformation
448
-
449
- **Scenario:** Extract basic order fields from SFCC-style XML.
450
-
451
- **Source Data:** See [canonical-order.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json)
452
-
453
- **Goal:** Create Fluent Commerce order input with ref, totalPrice, and customer.
454
-
455
- ```typescript
456
- import { createResolverBuilder } from '@fluentcommerce/fc-connect-sdk';
457
-
458
- const builder = createResolverBuilder();
459
-
460
- export const orderResolvers = builder
461
- // Extract order reference (required field)
462
- .validate(
463
- 'input.ref',
464
- (data, config, helpers) => helpers.get(data, 'orders.order@order-no'),
465
- value => !!value || 'Order reference is required'
466
- )
467
-
468
- // Parse total price to number
469
- .from('input.totalPrice', 'orders.order.totals.order-total.gross-price', value =>
470
- parseFloat(value)
471
- )
472
-
473
- // Extract customer email
474
- .from('input.customer.email', 'orders.order.customer.customer-email')
475
-
476
- .build();
477
- ```
478
-
479
- **Test it:**
480
-
481
- ```typescript
482
- import { canonicalOrder } from '../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json';
483
- import { ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
484
-
485
- const result = {
486
- ref: orderResolvers\['input.ref'](canonicalOrder, {}, ResolverHelpers),
487
- totalPrice: orderResolvers\['input.totalPrice'](canonicalOrder, {}, ResolverHelpers),
488
- customer: {
489
- email: orderResolvers\['input.customer.email'](canonicalOrder, {}, ResolverHelpers),
490
- },
491
- };
492
-
493
- console.log(result);
494
- // Expected:
495
- // {
496
- // ref: "ORD-2025-001",
497
- // totalPrice: 151.17,
498
- // customer: { email: "john.doe@example.com" }
499
- // }
500
- ```
501
-
502
- โœ… **Expected Output:**
503
-
504
- ```json
505
- {
506
- "ref": "ORD-2025-001",
507
- "totalPrice": 151.17,
508
- "customer": { "email": "john.doe@example.com" }
509
- }
510
- ```
511
-
512
- ---
513
-
514
- ### Example 2: Order Management - Array Mapping
515
-
516
- **Scenario:** Transform line items array with quantity and price calculations.
517
-
518
- ```typescript
519
- export const itemResolvers = builder
520
- .mapArray(
521
- 'input.items',
522
- 'orders.order.product-lineitems.product-lineitem',
523
- (item, index, config, helpers) => ({
524
- ref: item['@lineitem-id'] || `ITEM-${index + 1}`,
525
- productRef: item['product-id'],
526
- quantity: helpers.parseIntSafe(item.quantity, 1),
527
- price: helpers.parseFloatSafe(item['base-price'], 0),
528
- totalPrice: helpers.parseFloatSafe(item['gross-price'], 0),
529
-
530
- attributes: {
531
- productName: item['product-name'],
532
- position: helpers.parseIntSafe(item.position, index + 1),
533
- taxAmount: helpers.parseFloatSafe(item.tax, 0),
534
- },
535
- })
536
- )
537
- .build();
538
- ```
539
-
540
- **Test it:**
541
-
542
- ```typescript
543
- const items = itemResolvers\['input.items'](canonicalOrder, {}, ResolverHelpers);
544
- console.log(items);
545
- ```
546
-
547
- โœ… **Expected Output:**
548
-
549
- ```json
550
- [
551
- {
552
- "ref": "ITEM-001",
553
- "productRef": "SKU-WM-001",
554
- "quantity": 2,
555
- "price": 29.99,
556
- "totalPrice": 64.78,
557
- "attributes": {
558
- "productName": "Wireless Mouse",
559
- "position": 1,
560
- "taxAmount": 4.8
561
- }
562
- },
563
- {
564
- "ref": "ITEM-002",
565
- "productRef": "SKU-KB-001",
566
- "quantity": 1,
567
- "price": 79.99,
568
- "totalPrice": 86.39,
569
- "attributes": {
570
- "productName": "Mechanical Keyboard",
571
- "position": 2,
572
- "taxAmount": 6.4
573
- }
574
- }
575
- ]
576
- ```
577
-
578
- ---
579
-
580
- ### Example 3: Inventory Management - Batch Ingestion
581
-
582
- **Scenario:** Transform WMS inventory data to Fluent Commerce batch format.
583
-
584
- **Source Data:** See [canonical-inventory.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json)
585
-
586
- ```typescript
587
- export const inventoryResolvers = builder
588
- // Extract location ID
589
- .from('input.locationId', 'inventory.header.location-id')
590
-
591
- // Transform inventory items array
592
- .mapArray('input.entities', 'inventory.items', (item, index, config, helpers) => ({
593
- skuRef: item.sku,
594
- locationRef: item.location.id,
595
- qty: helpers.parseIntSafe(item.quantity['on-hand'], 0),
596
-
597
- // Optional: Add expected delivery date
598
- expectedOn: helpers.get(item, 'dates.next-expected-receipt')
599
- ? new Date(item['dates']['next-expected-receipt']).toISOString()
600
- : null,
601
-
602
- attributes: {
603
- available: helpers.parseIntSafe(item.quantity.available, 0),
604
- reserved: helpers.parseIntSafe(item.quantity.reserved, 0),
605
- inTransit: helpers.parseIntSafe(item.quantity['in-transit'], 0),
606
- binLocation: item.attributes['bin-location'],
607
- lotNumber: item.attributes['lot-number'],
608
- },
609
- }))
610
-
611
- .build();
612
- ```
613
-
614
- **Test it:**
615
-
616
- ```typescript
617
- import { canonicalInventory } from '../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json';
618
-
619
- const result = {
620
- locationId: inventoryResolvers\['input.locationId'](canonicalInventory, {}, ResolverHelpers),
621
- entities: inventoryResolvers\['input.entities'](canonicalInventory, {}, ResolverHelpers),
622
- };
623
-
624
- console.log(result.entities[0]);
625
- ```
626
-
627
- โœ… **Expected Output:**
628
-
629
- ```json
630
- {
631
- "skuRef": "SKU-WM-001",
632
- "locationRef": "WH-001",
633
- "qty": 250,
634
- "expectedOn": "2025-01-20T00:00:00.000Z",
635
- "attributes": {
636
- "available": 200,
637
- "reserved": 50,
638
- "inTransit": 100,
639
- "binLocation": "A-12-03",
640
- "lotNumber": "LOT-2025-001"
641
- }
642
- }
643
- ```
644
-
645
- ---
646
-
647
- ### Example 4: Complex Calculation - Total Discount
648
-
649
- **Scenario:** Calculate total discount from multiple sources (item discounts + promotions).
650
-
651
- ```typescript
652
- builder.calculate('input.totalDiscount', (data, helpers) => {
653
- // Get line items
654
- const items = helpers.ensureArray(
655
- helpers.get(data, 'orders.order.product-lineitems.product-lineitem', [])
656
- );
657
-
658
- // Calculate item-level discounts
659
- const itemDiscounts = items.reduce((sum, item) => {
660
- const basePrice = helpers.parseFloatSafe(item['base-price'], 0);
661
- const netPrice = helpers.parseFloatSafe(item['net-price'], 0);
662
- const quantity = helpers.parseIntSafe(item.quantity, 1);
663
- return sum + (basePrice - netPrice) * quantity;
664
- }, 0);
665
-
666
- // Add order-level adjustment (if negative, it's a discount)
667
- const adjustment = helpers.parseFloatSafe(
668
- helpers.get(data, 'orders.order.totals.adjustment-total.gross-price'),
669
- 0
670
- );
671
-
672
- const orderDiscount = adjustment < 0 ? Math.abs(adjustment) : 0;
673
-
674
- const totalDiscount = itemDiscounts + orderDiscount;
675
-
676
- helpers.log?.info('Calculated total discount', {
677
- itemDiscounts,
678
- orderDiscount,
679
- totalDiscount,
680
- });
681
-
682
- return helpers.formatCurrency(totalDiscount, 2);
683
- });
684
- ```
685
-
686
- **Test it:**
687
-
688
- ```typescript
689
- const discount = resolvers\['input.totalDiscount'](canonicalOrder, {}, ResolverHelpers);
690
- console.log(discount); // Expected: "14.00" (from adjustment-total in canonical data)
691
- ```
692
-
693
- ---
694
-
695
- ### Example 5: Conditional Mapping - Order Type
696
-
697
- **Scenario:** Map channel type to Fluent order type with business rules.
698
-
699
- ```typescript
700
- builder.field('input.type', (data, config, helpers) => {
701
- const channelType = helpers.get(data, 'orders.order.channel-type');
702
- const isGift = helpers.get(data, 'orders.order.shipments.shipment.gift') === 'true';
703
-
704
- // Channel to order type mapping
705
- const channelMapping = {
706
- Storefront: 'HD',
707
- CallCenter: 'CC',
708
- Mobile: 'MOBILE',
709
- POS: 'STORE',
710
- };
711
-
712
- let orderType = helpers.mapValue(channelType, channelMapping, config.defaultOrderType || 'HD');
713
-
714
- // Business rule: Gift orders get special type
715
- if (isGift && orderType === 'HD') {
716
- orderType = 'GIFT_HD';
717
- }
718
-
719
- helpers.log?.debug('Mapped order type', { channelType, isGift, orderType });
720
-
721
- return orderType;
722
- });
723
- ```
724
-
725
- **Test it:**
726
-
727
- ```typescript
728
- const orderType = resolvers`'input.type'`;
729
- console.log(orderType); // Expected: "HD" (Storefront channel)
730
- ```
731
-
732
- ---
733
-
734
- ## Advanced Topics
735
-
736
- ### Async Operations & API Calls
737
-
738
- Resolvers can be async to call external APIs or perform lookups.
739
-
740
- **Example: Customer Lookup**
741
-
742
- ```typescript
743
- builder.field('input.customer.id', async (data, config, helpers) => {
744
- const customerId = helpers.get(data, 'orders.order.customer.customer-no');
745
-
746
- if (!helpers.fluentClient) {
747
- throw new Error('FluentClient is required for customer lookup');
748
- }
749
-
750
- // Use retry helper for resilience
751
- return await helpers.retry(
752
- async () => {
753
- // Query for existing customer
754
- const result = await helpers.fluentClient.graphql({
755
- query: `
756
- query GetCustomer($username: [String]) {
757
- customers(username: $username, first: 1) {
758
- edges {
759
- node { id username }
760
- }
761
- }
762
- }
763
- `,
764
- variables: { username: [customerId] },
765
- });
766
-
767
- const existing = result.data?.customers?.edges?.[0]?.node;
768
-
769
- if (existing) {
770
- helpers.log?.info('Found existing customer', { id: existing.id });
771
- return existing.id;
772
- }
773
-
774
- // Create new customer if not found
775
- helpers.log?.info('Creating new customer', { customerId });
776
- const createResult = await helpers.fluentClient.graphql({
777
- query: `
778
- mutation CreateCustomer($input: CreateCustomerInput!) {
779
- createCustomer(input: $input) { id }
780
- }
781
- `,
782
- variables: {
783
- input: {
784
- username: customerId,
785
- retailer: { id: config.defaultRetailerId },
786
- },
787
- },
788
- });
789
-
790
- return createResult.data?.createCustomer?.id;
791
- },
792
- 3, // Retry 3 times
793
- 500 // 500ms delay
794
- );
795
- });
796
- ```
797
-
798
- **Best Practices for Async Resolvers:**
799
-
800
- 1. โœ… **Always use error handling**
801
- 2. โœ… **Use `helpers.retry()` for transient failures**
802
- 3. โœ… **Add timeout protection**
803
- 4. โœ… **Log API calls for debugging**
804
- 5. โœ… **Cache results when possible**
805
-
806
- ๐Ÿ“– **Learn more:** [Async Patterns Cookbook](./mapping-resolvers-resolver-cookbook.md#async-patterns)
807
-
808
- ---
809
-
810
- ### Error Handling Patterns
811
-
812
- **Pattern 1: Validation with Custom Errors**
813
-
814
- ```typescript
815
- builder.validate(
816
- 'input.totalPrice',
817
- (data, config, helpers) => {
818
- const price = helpers.get(data, 'orders.order.totals.order-total.gross-price');
819
- return helpers.parseFloatSafe(price, 0);
820
- },
821
- value => value > 0 || 'Total price must be greater than zero'
822
- );
823
- ```
824
-
825
- **Pattern 2: Try-Catch with Fallbacks**
826
-
827
- ```typescript
828
- builder.field('input.customAttribute', (data, config, helpers) => {
829
- try {
830
- const attrs = helpers.get(data, 'orders.order.custom-attributes.custom-attribute');
831
- return helpers.extractCustomAttribute(attrs, 'specialValue');
832
- } catch (error) {
833
- helpers.log?.warn('Failed to extract custom attribute', { error });
834
- return config.defaultSpecialValue || null;
835
- }
836
- });
837
- ```
838
-
839
- ๐Ÿ“– **Learn more:** [Error Handling Guide](./mapping-resolvers-resolver-troubleshooting.md#error-patterns)
840
-
841
- ---
842
-
843
- ### Performance Optimization
844
-
845
- **1. Memoize Expensive Calculations**
846
-
847
- ```typescript
848
- import { ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
849
-
850
- const calculateComplexDiscount = ResolverHelpers.memoize((items, discountRules) => {
851
- // Expensive calculation cached by input
852
- return items.reduce((total, item) => {
853
- return total + applyDiscountRules(item, discountRules);
854
- }, 0);
855
- });
856
-
857
- builder.field('input.discount', (data, config, helpers) => {
858
- const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem', []);
859
- return calculateComplexDiscount(items, config.discountRules);
860
- });
861
- ```
862
-
863
- **2. Parallel Async Operations**
864
-
865
- ```typescript
866
- // โŒ Sequential (slow)
867
- const customer = await lookupCustomer(customerId);
868
- const inventory = await checkInventory(sku);
869
- const pricing = await getPricing(sku);
870
-
871
- // โœ… Parallel (fast)
872
- const [customer, inventory, pricing] = await Promise.all([
873
- lookupCustomer(customerId),
874
- checkInventory(sku),
875
- getPricing(sku),
876
- ]);
877
- ```
878
-
879
- **3. Batch Processing**
880
-
881
- ```typescript
882
- builder.field('input.enrichedItems', async (data, config, helpers) => {
883
- const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem', []);
884
-
885
- // Process in batches of 10
886
- return await helpers.batchProcess(
887
- items,
888
- async item => {
889
- // Enrich each item with external data
890
- const details = await fetchProductDetails(item['product-id']);
891
- return { ...item, ...details };
892
- },
893
- 10 // Batch size
894
- );
895
- });
896
- ```
897
-
898
- ๐Ÿ“– **Learn more:** [Performance Best Practices](./mapping-resolvers-resolver-cookbook.md#performance-optimization)
899
-
900
- ---
901
-
902
- ### Resolver-Only Fields & Required Validation
903
-
904
- **New in SDK v0.1.37:** Required validation for resolver-only fields (fields without a source).
905
-
906
- **What are resolver-only fields?**
907
-
908
- Resolver-only fields are fields that don't extract data from a source path, but instead generate values programmatically using a resolver function.
909
-
910
- **Use cases:**
911
-
912
- 1. **Generate unique IDs** - Create UUIDs or composite keys
913
- 2. **Derive values** - Calculate from other fields in the data
914
- 3. **Enrich with external data** - Look up values from APIs without a source field
915
- 4. **Apply business logic** - Determine values based on complex rules
916
-
917
- ---
918
-
919
- #### UniversalMapper Configuration
920
-
921
- **Example: Generate ID without source**
922
-
923
- ```json
924
- {
925
- "fields": {
926
- "id": {
927
- "resolver": "custom.generateProductId",
928
- "required": true
929
- },
930
- "name": {
931
- "source": "productName",
932
- "required": true
933
- },
934
- "enrichedData": {
935
- "resolver": "custom.enrichFromAPI",
936
- "required": false
937
- }
938
- }
939
- }
940
- ```
941
-
942
- **Resolver implementation:**
943
-
944
- ```typescript
945
- import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
946
- import { v4 as uuid } from 'uuid';
947
-
948
- const customResolvers = {
949
- // Generate UUID for each product (no source needed)
950
- 'custom.generateProductId': (value, sourceData, config, helpers) => {
951
- // value is undefined (no source)
952
- // Generate unique ID based on business logic
953
- const sku = helpers.get(sourceData, 'sku');
954
- const prefix = config.idPrefix || 'PROD';
955
- return `${prefix}-${sku}-${uuid()}`;
956
- },
957
-
958
- // Enrich with external API data
959
- 'custom.enrichFromAPI': async (value, sourceData, config, helpers) => {
960
- const sku = helpers.get(sourceData, 'sku');
961
-
962
- try {
963
- const response = await helpers.retry(async () => {
964
- return await fetch(`https://api.example.com/products/${sku}`);
965
- }, 3);
966
-
967
- return await response.json();
968
- } catch (error) {
969
- helpers.log?.warn('Failed to enrich product', { sku, error });
970
- return null; // Optional field, return null on failure
971
- }
972
- },
973
- };
974
-
975
- const mapper = new UniversalMapper(mappingConfig, { customResolvers });
976
- ```
977
-
978
- ---
979
-
980
- #### Validation Behavior
981
-
982
- **For resolver-only fields (`resolver` without `source`):**
983
-
984
- 1. โœ… **No source extraction** - Value starts as `undefined`
985
- 2. โœ… **Skip pre-validation** - Required validation does NOT run before resolver
986
- 3. โœ… **Execute resolver** - Resolver generates the value
987
- 4. โœ… **Post-validation** - Required validation runs AFTER resolver execution
988
-
989
- **For fields with source (`source` + `resolver`):**
990
-
991
- 1. โœ… **Extract from source** - Value extracted from data
992
- 2. โœ… **Validate required** - Required validation runs immediately
993
- 3. โœ… **Execute resolver** - Resolver transforms the extracted value
994
- 4. โœ… **No post-validation** - Required already validated before resolver
995
-
996
- ---
997
-
998
- #### When to Use Resolver-Only Required
999
-
1000
- **โœ… Good use cases:**
1001
-
1002
- ```json
1003
- {
1004
- "fields": {
1005
- // Generate unique transaction ID
1006
- "transactionId": {
1007
- "resolver": "custom.generateTransactionId",
1008
- "required": true
1009
- },
1010
-
1011
- // Look up customer ID by email from source
1012
- "customerId": {
1013
- "resolver": "custom.lookupCustomerByEmail",
1014
- "required": true
1015
- },
1016
-
1017
- // Calculate value from multiple source fields
1018
- "totalWeight": {
1019
- "resolver": "custom.calculateTotalWeight",
1020
- "required": true
1021
- },
1022
-
1023
- // Apply complex business rules
1024
- "fulfillmentType": {
1025
- "resolver": "custom.determineFulfillmentType",
1026
- "required": true
1027
- }
1028
- }
1029
- }
1030
- ```
1031
-
1032
- **โŒ Avoid for simple transformations:**
1033
-
1034
- ```json
1035
- {
1036
- "fields": {
1037
- // โŒ BAD - Use source + resolver instead
1038
- "uppercaseStatus": {
1039
- "resolver": "custom.getAndUppercaseStatus",
1040
- "required": true
1041
- },
1042
-
1043
- // โœ… GOOD - Extract then transform
1044
- "status": {
1045
- "source": "orderStatus",
1046
- "resolver": "sdk.uppercase",
1047
- "required": true
1048
- }
1049
- }
1050
- }
1051
- ```
1052
-
1053
- ---
1054
-
1055
- #### Complete Example: Product Ingestion
1056
-
1057
- ```typescript
1058
- import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
1059
- import { v4 as uuid } from 'uuid';
1060
-
1061
- // Mapping configuration
1062
- const productMappingConfig = {
1063
- fields: {
1064
- // Resolver-only: Generate unique product ID
1065
- id: {
1066
- resolver: 'custom.generateProductId',
1067
- required: true,
1068
- },
1069
-
1070
- // Source + resolver: Extract and transform
1071
- name: {
1072
- source: 'productName',
1073
- resolver: 'sdk.trim',
1074
- required: true,
1075
- },
1076
-
1077
- sku: {
1078
- source: 'sku',
1079
- required: true,
1080
- },
1081
-
1082
- // Resolver-only: Enrich with category data
1083
- category: {
1084
- resolver: 'custom.resolveCategoryFromSku',
1085
- required: false,
1086
- },
1087
-
1088
- // Static value
1089
- type: {
1090
- value: 'STANDARD',
1091
- required: true,
1092
- },
1093
- },
1094
- };
1095
-
1096
- // Custom resolvers
1097
- const customResolvers = {
1098
- 'custom.generateProductId': (value, sourceData, config, helpers) => {
1099
- const sku = helpers.get(sourceData, 'sku');
1100
- const retailerId = config.retailerId;
1101
- return `${retailerId}-${sku}-${uuid()}`;
1102
- },
1103
-
1104
- 'custom.resolveCategoryFromSku': async (value, sourceData, config, helpers) => {
1105
- const sku = helpers.get(sourceData, 'sku');
1106
-
1107
- // Lookup category from SKU prefix
1108
- const prefix = sku.substring(0, 3);
1109
- const categoryMap = {
1110
- 'ELE': 'Electronics',
1111
- 'CLO': 'Clothing',
1112
- 'FOO': 'Food',
1113
- };
1114
-
1115
- return categoryMap[prefix] || 'General';
1116
- },
1117
- };
1118
-
1119
- // Create mapper with custom resolvers
1120
- const mapper = new UniversalMapper(
1121
- productMappingConfig,
1122
- {
1123
- customResolvers,
1124
- context: { retailerId: '1' },
1125
- logger: console,
1126
- }
1127
- );
1128
-
1129
- // Map product data
1130
- const sourceData = {
1131
- sku: 'ELE-12345',
1132
- productName: ' Wireless Mouse ',
1133
- };
1134
-
1135
- const result = await mapper.map(sourceData);
1136
-
1137
- console.log(result);
1138
- // {
1139
- // success: true,
1140
- // data: {
1141
- // id: '1-ELE-12345-a1b2c3d4-...',
1142
- // name: 'Wireless Mouse',
1143
- // sku: 'ELE-12345',
1144
- // category: 'Electronics',
1145
- // type: 'STANDARD'
1146
- // }
1147
- // }
1148
- ```
1149
-
1150
- ---
1151
-
1152
- #### Required Validation Error Messages
1153
-
1154
- **Resolver-only field returns empty:**
1155
-
1156
- ```typescript
1157
- // If resolver returns null/undefined/''
1158
- {
1159
- success: false,
1160
- data: null,
1161
- errors: [
1162
- "Failed to map field 'id': Required field 'id' is missing or empty after resolver 'custom.generateId' execution"
1163
- ]
1164
- }
1165
- ```
1166
-
1167
- **Source-based required field missing:**
1168
-
1169
- ```typescript
1170
- // If source field is missing
1171
- {
1172
- success: false,
1173
- data: null,
1174
- errors: [
1175
- "Failed to map field 'sku': Required field 'sku' is missing or empty (source: sku)"
1176
- ]
1177
- }
1178
- ```
1179
-
1180
- ---
1181
-
1182
- #### Testing Resolver-Only Required Fields
1183
-
1184
- ```typescript
1185
- import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
1186
-
1187
- describe('Resolver-only required fields', () => {
1188
- it('should pass validation when resolver returns value', async () => {
1189
- const mapper = new UniversalMapper(
1190
- {
1191
- fields: {
1192
- id: {
1193
- resolver: 'custom.generateId',
1194
- required: true,
1195
- },
1196
- },
1197
- },
1198
- {
1199
- customResolvers: {
1200
- 'custom.generateId': () => 'generated-id-123',
1201
- },
1202
- }
1203
- );
1204
-
1205
- const result = await mapper.map({});
1206
-
1207
- expect(result.success).toBe(true);
1208
- expect(result.data.id).toBe('generated-id-123');
1209
- });
1210
-
1211
- it('should fail validation when resolver returns empty', async () => {
1212
- const mapper = new UniversalMapper(
1213
- {
1214
- fields: {
1215
- id: {
1216
- resolver: 'custom.generateId',
1217
- required: true,
1218
- },
1219
- },
1220
- },
1221
- {
1222
- customResolvers: {
1223
- 'custom.generateId': () => null, // Returns empty
1224
- },
1225
- }
1226
- );
1227
-
1228
- const result = await mapper.map({});
1229
-
1230
- expect(result.success).toBe(false);
1231
- expect(result.errors[0]).toContain('Required field');
1232
- });
1233
- });
1234
- ```
1235
-
1236
- ---
1237
-
1238
- ๐Ÿ“– **Learn more:** [Performance Best Practices](./mapping-resolvers-resolver-cookbook.md#performance-optimization)
1239
-
1240
- ---
1241
-
1242
- ## Reference Documentation
1243
-
1244
- ### ๐Ÿ“˜ Detailed References
1245
-
1246
- | Document | Description |
1247
- | ------------------------------------------------------------- | ---------------------------------------------------- |
1248
- | [Resolver API Reference](./mapping-resolvers-resolver-api-reference.md) | Complete ResolverBuilder API documentation |
1249
- | [Helper Functions Reference](./mapping-resolvers-resolver-helpers-reference.md) | All 54 helper functions with examples |
1250
- | [Parameters Deep Dive](./mapping-resolvers-resolver-parameters-reference.md) | Detailed explanation of value, data, config, helpers |
1251
- | [Troubleshooting Guide](./mapping-resolvers-resolver-troubleshooting.md) | Common issues and solutions |
1252
- | [Cookbook](./mapping-resolvers-resolver-cookbook.md) | Advanced patterns and recipes |
1253
-
1254
- ### ๐Ÿงช Test Examples
1255
-
1256
- All examples are validated with automated tests:
1257
-
1258
- ```bash
1259
- cd fc-connect-sdk
1260
- npm test -- examples/__tests__/resolver-guide-examples.test.ts
1261
- ```
1262
-
1263
- ๐Ÿ“ **Example Files:**
1264
-
1265
- - [Resolver Examples](../examples/)
1266
- - [Order Test Data](../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json)
1267
- - [Inventory Test Data](../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json)
1268
-
1269
- ---
1270
-
1271
- ## Best Practices Summary
1272
-
1273
- ### โœ… Do's
1274
-
1275
- 1. **Organize by domain** - Group related resolvers (order, customer, inventory)
1276
- 2. **Use config for defaults** - Never hardcode environment-specific values
1277
- 3. **Validate critical fields** - Use `.validate()` for required fields
1278
- 4. **Use helper functions** - Don't reinvent the wheel
1279
- 5. **Handle arrays gracefully** - Use `ensureArray()` and `mapArray()`
1280
- 6. **Log important decisions** - Help with debugging
1281
- 7. **Test in isolation** - Write unit tests for resolvers
1282
- 8. **Use TypeScript types** - Leverage type safety
1283
-
1284
- ### โŒ Don'ts
1285
-
1286
- 1. **Don't hardcode values** - Use config instead
1287
- 2. **Don't skip validation** - Validate required fields
1288
- 3. **Don't ignore errors** - Handle async failures gracefully
1289
- 4. **Don't forget to await** - Async resolvers must be awaited
1290
- 5. **Don't assume array structure** - XML can return object for single item
1291
- 6. **Don't skip logging** - Log for production debugging
1292
- 7. **Don't write untested code** - Test with canonical data
1293
-
1294
- ---
1295
-
1296
- ## Next Steps
1297
-
1298
- ### ๐ŸŽ“ Continue Learning
1299
-
1300
- 1. **Beginner (30 min):**
1301
- - โœ… Completed Quick Start
1302
- - ๐Ÿ“– Read [Resolver Parameters](./mapping-resolvers-resolver-parameters-reference.md)
1303
- - ๐Ÿงช Test examples with canonical data
1304
-
1305
- 2. **Intermediate (2 hours):**
1306
- - ๐Ÿ“– Read [API Reference](./mapping-resolvers-resolver-api-reference.md)
1307
- - ๐Ÿ’ป Build resolvers for your use case
1308
- - ๐Ÿงช Write tests for your resolvers
1309
-
1310
- 3. **Advanced (4 hours):**
1311
- - ๐Ÿ“– Read [Cookbook](./mapping-resolvers-resolver-cookbook.md)
1312
- - ๐ŸŒ Add async API calls
1313
- - ๐Ÿš€ Deploy to production
1314
-
1315
- ### ๐Ÿ†˜ Get Help
1316
-
1317
- - **GitHub Issues:** https://github.com/fluentcommerce/fc-connect-sdk/issues
1318
- - **Documentation:** https://docs.fluentcommerce.com
1319
- - **Email:** support@fluentcommerce.com
1320
-
1321
- ---
1322
-
1323
- **Document Version:** 2.0.0
1324
- **SDK Version:** 1.5.0+
1325
- **Last Updated:** 2025-01-14
1326
-
1327
- ---
1328
-
1329
- **License:** MIT
1330
- **Copyright:** ยฉ 2025 Fluent Commerce
1
+ # Resolver Pattern Guide
2
+
3
+ **FC Connect SDK - Transform Data with Custom Logic**
4
+
5
+ Version: 2.0.0
6
+ Last Updated: 2025-01-14
7
+
8
+ ---
9
+
10
+ ## ๐Ÿ“š Table of Contents
11
+
12
+ 1. [Quick Start (5 Minutes)](#quick-start-5-minutes)
13
+ 2. [Core Concepts](#core-concepts)
14
+ 3. [Real-World Examples](#real-world-examples)
15
+ 4. [Advanced Topics](#advanced-topics)
16
+ - [Async Operations & API Calls](#async-operations--api-calls)
17
+ - [Error Handling Patterns](#error-handling-patterns)
18
+ - [Performance Optimization](#performance-optimization)
19
+ - [Resolver-Only Fields & Required Validation](#resolver-only-fields--required-validation) โ† NEW
20
+ 5. [Reference Documentation](#reference-documentation)
21
+
22
+ ---
23
+
24
+ ## ๐ŸŽฏ What You'll Learn
25
+
26
+ By the end of this guide, you'll be able to:
27
+
28
+ โœ… Write custom resolver functions for complex transformations
29
+ โœ… Use the ResolverBuilder API for clean, maintainable code
30
+ โœ… Handle order management and inventory data transformations
31
+ โœ… Work with async operations (API calls, database lookups)
32
+ โœ… Apply best practices for production-ready resolvers
33
+
34
+ **Time to Complete:** 30 minutes to 2 hours (depending on depth)
35
+
36
+ ---
37
+
38
+ ## Quick Start (5 Minutes)
39
+
40
+ ### What are Resolvers?
41
+
42
+ **Resolvers** are custom JavaScript functions that transform source data into the format required by Fluent Commerce. They're your solution when JSON mapping isn't enough.
43
+
44
+ **Use resolvers when you need:**
45
+
46
+ - ๐Ÿงฎ Complex calculations (totals, aggregations, formulas)
47
+ - ๐Ÿ”€ Conditional logic (if-then-else transformations)
48
+ - ๐ŸŒ External API calls (customer lookup, price checks)
49
+ - ๐Ÿ”„ Cross-referencing data (resolve IDs to full objects)
50
+ - โ™ป๏ธ Reusable transformation logic
51
+
52
+ ---
53
+
54
+ ### Your First Resolver
55
+
56
+ Let's transform an order from our e-commerce system to Fluent Commerce.
57
+
58
+ **Step 1: Install the SDK**
59
+
60
+ ```bash
61
+ npm install @fluentcommerce/fc-connect-sdk
62
+ ```
63
+
64
+ **Step 2: Create Your First Resolver**
65
+
66
+ ```typescript
67
+ import { createResolverBuilder, ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
68
+
69
+ // Create a builder instance
70
+ const builder = createResolverBuilder();
71
+
72
+ // Define your resolvers
73
+ const resolvers = builder
74
+ // Simple field mapping: Extract order reference
75
+ .from('input.ref', 'orders.order@order-no')
76
+
77
+ // With transformation: Parse price to number
78
+ .from('input.totalPrice', 'orders.order.totals.order-total.gross-price', value =>
79
+ parseFloat(value)
80
+ )
81
+
82
+ // Build the resolver map
83
+ .build();
84
+
85
+ export default resolvers;
86
+ ```
87
+
88
+ **Step 3: Use in Your Workflow**
89
+
90
+ ```typescript
91
+ import { http } from '@versori/run';
92
+ import { createClient, XMLParserService, ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
93
+ import resolvers from './resolvers';
94
+
95
+ // Versori workflow - ctx comes from workflow parameter
96
+ export default http('processOrder', async (ctx) => { // โ† ctx defined here!
97
+ const { log, activation, fetch } = ctx;
98
+
99
+ // 1. Parse input XML
100
+ const parser = new XMLParserService(log);
101
+ const orderData = await parser.parseFromString(activation.body);
102
+
103
+ // 2. Apply resolvers
104
+ const config = {
105
+ defaultRetailerId: activation.getVariable('RETAILER_ID'),
106
+ apiToken: activation.getVariable('API_TOKEN')
107
+ };
108
+
109
+ const transformedData = {};
110
+ for (const [path, resolver] of Object.entries(resolvers)) {
111
+ const value = await resolver(orderData, config, ResolverHelpers, ctx);
112
+ setNestedValue(transformedData, path, value);
113
+ }
114
+
115
+ // 3. Send to Fluent Commerce
116
+ const client = await createClient({ ...ctx, log });
117
+
118
+ const result = await client.graphql({
119
+ query: `mutation CreateOrder($input: CreateOrderInput!) {
120
+ createOrder(input: $input) { id ref }
121
+ }`,
122
+ variables: { input: transformedData },
123
+ });
124
+
125
+ return { success: true, data: result };
126
+ });
127
+
128
+ function setNestedValue(obj: any, path: string, value: any) {
129
+ const keys = path.split('.');
130
+ let current = obj;
131
+ for (let i = 0; i < keys.length - 1; i++) {
132
+ current[keys[i]] = current[keys[i]] || {};
133
+ current = current[keys[i]];
134
+ }
135
+ current[keys[keys.length - 1]] = value;
136
+ }
137
+ ```
138
+
139
+ **๐ŸŽ‰ That's it!** You've created and executed your first resolver.
140
+
141
+ ---
142
+
143
+ ### Test Your Resolver
144
+
145
+ Use our canonical test data to verify your resolver works:
146
+
147
+ ```typescript
148
+ import { canonicalOrder } from '../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json';
149
+ import { ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
150
+
151
+ // Test the resolver
152
+ const result = resolvers\['input.ref'](canonicalOrder, {}, ResolverHelpers);
153
+ console.log(result); // Expected: "ORD-2025-001"
154
+ ```
155
+
156
+ โœ… **Expected Output:** `"ORD-2025-001"`
157
+
158
+ ๐Ÿ“– **See:** [Complete test data structure](../../../03-PATTERN-GUIDES/examples/test-data/) for resolver testing examples
159
+
160
+ ---
161
+
162
+ ## Core Concepts
163
+
164
+ ### JSON Mapping vs Resolvers
165
+
166
+ **Use JSON Mapping when:**
167
+
168
+ - Simple field-to-field mapping
169
+ - Standard transformations (toString, toNumber)
170
+ - Static data structures
171
+
172
+ ```json
173
+ {
174
+ "ref": { "source": "order.orderNo" },
175
+ "totalPrice": { "source": "order.total", "resolver": "sdk.number" }
176
+ }
177
+ ```
178
+
179
+ **Use Resolvers when:**
180
+
181
+ - Complex calculations or business logic
182
+ - Conditional transformations
183
+ - External API calls
184
+ - Multiple source aggregation
185
+
186
+ ```typescript
187
+ builder.field('input.totalDiscount', (data, config, helpers) => {
188
+ // Calculate from multiple sources
189
+ const itemDiscounts = helpers.sum(data.order.items, 'discount');
190
+ const couponValue = helpers.get(data, 'order.coupon.value', 0);
191
+ return itemDiscounts + couponValue;
192
+ });
193
+ ```
194
+
195
+ ---
196
+
197
+ ### The Four Resolver Parameters
198
+
199
+ Every resolver receives four parameters:
200
+
201
+ ```typescript
202
+ type ResolverFunction = (
203
+ value: unknown, // Extracted value from 'source' path
204
+ data: unknown, // Full data context (includes named nodes)
205
+ config: unknown, // Configuration object
206
+ helpers: Helpers // Utility functions
207
+ ) => unknown | Promise<unknown>;
208
+ ```
209
+
210
+ **You don't have to use all four** - just what you need!
211
+
212
+ ---
213
+
214
+ #### 1. `value` - The Extracted Value
215
+
216
+ **What:** The value extracted from the `source` path in your mapping.
217
+
218
+ **When defined:** When your field has a `source` property
219
+ **When undefined:** When your field only has a `resolver` (resolver-only field)
220
+
221
+ **Example: Using `value` from source**
222
+
223
+ ```typescript
224
+ // Mapping config
225
+ {
226
+ "ref": {
227
+ "source": "orders.order@order-no",
228
+ "resolver": "custom.addPrefix"
229
+ }
230
+ }
231
+
232
+ // Resolver
233
+ 'custom.addPrefix': (value, data, config, helpers) => {
234
+ // value = "ORD-2025-001" (extracted from source)
235
+ return `ORDER-${value}`;
236
+ // Returns: "ORDER-ORD-2025-001"
237
+ }
238
+ ```
239
+
240
+ **Example: Resolver-only (no source)**
241
+
242
+ ```typescript
243
+ // Mapping config (NO source!)
244
+ {
245
+ "totalDiscount": {
246
+ "resolver": "custom.calculateTotalDiscount"
247
+ }
248
+ }
249
+
250
+ // Resolver
251
+ 'custom.calculateTotalDiscount': (value, data, config, helpers) => {
252
+ // value = undefined (no source specified)
253
+ // Use 'data' to access full context
254
+ const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem', []);
255
+ return helpers.sum(helpers.ensureArray(items), item =>
256
+ helpers.parseFloatSafe(item['base-price'], 0) - helpers.parseFloatSafe(item['net-price'], 0)
257
+ );
258
+ }
259
+ ```
260
+
261
+ **Important: Required Fields with Resolvers**
262
+
263
+ When using `required: true` with resolvers, validation timing depends on whether the field has a `source`:
264
+
265
+ **Fields with `source`**: Validation happens **before** resolver execution
266
+ ```json
267
+ {
268
+ "discount": {
269
+ "source": "order.subtotal",
270
+ "resolver": "custom.calculateDiscount",
271
+ "required": true
272
+ }
273
+ }
274
+ ```
275
+ - โœ… Checks if `order.subtotal` exists in source data first
276
+ - โœ… If missing โ†’ mapping fails immediately (resolver never runs)
277
+ - โœ… If present โ†’ resolver runs to transform the value
278
+
279
+ **Resolver-only fields** (no `source`): Validation happens **after** resolver execution
280
+ ```json
281
+ {
282
+ "uuid": {
283
+ "resolver": "custom.generateUUID",
284
+ "required": true
285
+ }
286
+ }
287
+ ```
288
+ - โœ… Resolver runs first to generate value
289
+ - โœ… Then validates that resolver produced a value
290
+ - โœ… If resolver returns `null`, `undefined`, or empty string โ†’ mapping fails
291
+
292
+ **Why this matters:** Resolvers can return empty values. `required: true` ensures validation happens **after** the resolver runs to catch these cases. If your resolver has conditional logic that might return `undefined`, use `required: true` to ensure the field always has a value.
293
+
294
+ ๐Ÿ“– **Learn more:** [Resolver Parameters Deep Dive](./mapping-resolvers-resolver-parameters-reference.md)
295
+
296
+ ---
297
+
298
+ #### 2. `data` - Full Data Context
299
+
300
+ **What:** The complete data object, including all named nodes from your mapping config.
301
+
302
+ **When to use:** When you need to access data from different parts of your payload or from named nodes.
303
+
304
+ **Example: Accessing order data**
305
+
306
+ ```typescript
307
+ builder.field('input.customer.email', (data, config, helpers) => {
308
+ // Access nested data safely
309
+ return helpers.get(data, 'orders.order.customer.customer-email');
310
+ });
311
+ ```
312
+
313
+ **Example: Using named nodes**
314
+
315
+ Named nodes let you parse embedded XML/JSON within your payload:
316
+
317
+ ```json
318
+ {
319
+ "nodes": {
320
+ "radialXml": {
321
+ "extract": "orders.order.custom-attributes.custom-attribute[attribute-id=RadialData]",
322
+ "parse": "xml"
323
+ }
324
+ }
325
+ }
326
+ ```
327
+
328
+ ```typescript
329
+ builder.field('input.specialInstructions', (data, config, helpers) => {
330
+ // 'data' now contains both original data AND parsed nodes
331
+ // data = {
332
+ // orders: { ... original data ... },
333
+ // radialXml: { ... parsed XML ... }
334
+ // }
335
+
336
+ const radialData = data.radialXml;
337
+ return helpers.get(radialData, 'Order.SpecialInstructions.Text');
338
+ });
339
+ ```
340
+
341
+ ---
342
+
343
+ #### 3. `config` - Configuration Object
344
+
345
+ **What:** Settings and defaults passed when executing resolvers.
346
+
347
+ **When to use:** For environment-specific values, defaults, or API credentials.
348
+
349
+ **Example: Config with fallbacks**
350
+
351
+ ```typescript
352
+ // Standalone Pattern
353
+ const config = {
354
+ defaultRetailerId: '1',
355
+ defaultCurrency: 'USD',
356
+ apiToken: process.env.EXTERNAL_API_TOKEN,
357
+ };
358
+
359
+ // Versori Platform Pattern
360
+ const config = {
361
+ defaultRetailerId: activation.getVariable('FLUENT_RETAILER_ID'),
362
+ defaultCurrency: activation.getVariable('DEFAULT_CURRENCY') || 'USD',
363
+ // Credentials accessed via ctx.credentials() in resolver
364
+ };
365
+
366
+ builder.withConfigFallback(
367
+ 'input.retailer.id',
368
+ 'orders.order.retailerId',
369
+ 'defaultRetailerId' // Fallback key in config
370
+ );
371
+ ```
372
+
373
+ **Versori Credential Access in Resolvers:**
374
+
375
+ ```typescript
376
+ // Use in async resolver for external API calls
377
+ builder.field('input.enrichedData', async (data, config, helpers, ctx) => {
378
+ // Option 1: Get from activation variables
379
+ const apiToken = ctx.activation.getVariable('EXTERNAL_API_TOKEN');
380
+
381
+ // Option 2: Get from connection credentials
382
+ const apiCreds = await ctx.credentials().getAccessToken('external_api');
383
+
384
+ const response = await ctx.fetch('https://api.example.com/enrich', {
385
+ method: 'POST',
386
+ headers: {
387
+ 'Authorization': `Bearer ${apiCreds?.accessToken || apiToken}`,
388
+ 'Content-Type': 'application/json'
389
+ },
390
+ body: JSON.stringify(data)
391
+ });
392
+
393
+ return response.json();
394
+ });
395
+ ```
396
+
397
+ ---
398
+
399
+ #### 4. `helpers` - Utility Functions
400
+
401
+ **What:** Collection of 54 helper functions for common transformations.
402
+
403
+ **Available helpers:**
404
+
405
+ - **Data access:** `get()`, `ensureArray()`
406
+ - **Parsing:** `parseFloatSafe()`, `parseIntSafe()`, `safeJsonParse()`
407
+ - **Formatting:** `formatDate()`, `formatCurrency()`
408
+ - **Arrays:** `sum()`, `avg()`, `groupBy()`, `chunk()`, `flatten()`
409
+ - **Strings:** `slugify()`, `template()`, `truncate()`
410
+ - **Validation:** `isValidEmail()`, `requireField()`
411
+ - **Async:** `retry()`, `batchProcess()`
412
+
413
+ **Example: Using helpers**
414
+
415
+ ```typescript
416
+ builder.field('input.items', (data, config, helpers) => {
417
+ // Safe path access
418
+ const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem');
419
+
420
+ // Handle XML single vs array
421
+ const itemsArray = helpers.ensureArray(items);
422
+
423
+ // Transform with safe parsing
424
+ return itemsArray.map(item => ({
425
+ ref: item['@lineitem-id'],
426
+ quantity: helpers.parseIntSafe(item.quantity, 1),
427
+ price: helpers.parseFloatSafe(item['base-price'], 0),
428
+ }));
429
+ });
430
+ ```
431
+
432
+ ๐Ÿ“– **See all helpers:** [Resolver Helpers Reference](./mapping-resolvers-resolver-helpers-reference.md)
433
+
434
+ ---
435
+
436
+ ## Real-World Examples
437
+
438
+ All examples use our **canonical datasets** for consistency. You can test every example!
439
+
440
+ ๐Ÿ“ **Test Data:**
441
+
442
+ - [canonical-order.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json) - Order management
443
+ - [canonical-inventory.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json) - Inventory management
444
+
445
+ ---
446
+
447
+ ### Example 1: Order Management - Simple Transformation
448
+
449
+ **Scenario:** Extract basic order fields from SFCC-style XML.
450
+
451
+ **Source Data:** See [canonical-order.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json)
452
+
453
+ **Goal:** Create Fluent Commerce order input with ref, totalPrice, and customer.
454
+
455
+ ```typescript
456
+ import { createResolverBuilder } from '@fluentcommerce/fc-connect-sdk';
457
+
458
+ const builder = createResolverBuilder();
459
+
460
+ export const orderResolvers = builder
461
+ // Extract order reference (required field)
462
+ .validate(
463
+ 'input.ref',
464
+ (data, config, helpers) => helpers.get(data, 'orders.order@order-no'),
465
+ value => !!value || 'Order reference is required'
466
+ )
467
+
468
+ // Parse total price to number
469
+ .from('input.totalPrice', 'orders.order.totals.order-total.gross-price', value =>
470
+ parseFloat(value)
471
+ )
472
+
473
+ // Extract customer email
474
+ .from('input.customer.email', 'orders.order.customer.customer-email')
475
+
476
+ .build();
477
+ ```
478
+
479
+ **Test it:**
480
+
481
+ ```typescript
482
+ import { canonicalOrder } from '../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json';
483
+ import { ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
484
+
485
+ const result = {
486
+ ref: orderResolvers\['input.ref'](canonicalOrder, {}, ResolverHelpers),
487
+ totalPrice: orderResolvers\['input.totalPrice'](canonicalOrder, {}, ResolverHelpers),
488
+ customer: {
489
+ email: orderResolvers\['input.customer.email'](canonicalOrder, {}, ResolverHelpers),
490
+ },
491
+ };
492
+
493
+ console.log(result);
494
+ // Expected:
495
+ // {
496
+ // ref: "ORD-2025-001",
497
+ // totalPrice: 151.17,
498
+ // customer: { email: "john.doe@example.com" }
499
+ // }
500
+ ```
501
+
502
+ โœ… **Expected Output:**
503
+
504
+ ```json
505
+ {
506
+ "ref": "ORD-2025-001",
507
+ "totalPrice": 151.17,
508
+ "customer": { "email": "john.doe@example.com" }
509
+ }
510
+ ```
511
+
512
+ ---
513
+
514
+ ### Example 2: Order Management - Array Mapping
515
+
516
+ **Scenario:** Transform line items array with quantity and price calculations.
517
+
518
+ ```typescript
519
+ export const itemResolvers = builder
520
+ .mapArray(
521
+ 'input.items',
522
+ 'orders.order.product-lineitems.product-lineitem',
523
+ (item, index, config, helpers) => ({
524
+ ref: item['@lineitem-id'] || `ITEM-${index + 1}`,
525
+ productRef: item['product-id'],
526
+ quantity: helpers.parseIntSafe(item.quantity, 1),
527
+ price: helpers.parseFloatSafe(item['base-price'], 0),
528
+ totalPrice: helpers.parseFloatSafe(item['gross-price'], 0),
529
+
530
+ attributes: {
531
+ productName: item['product-name'],
532
+ position: helpers.parseIntSafe(item.position, index + 1),
533
+ taxAmount: helpers.parseFloatSafe(item.tax, 0),
534
+ },
535
+ })
536
+ )
537
+ .build();
538
+ ```
539
+
540
+ **Test it:**
541
+
542
+ ```typescript
543
+ const items = itemResolvers\['input.items'](canonicalOrder, {}, ResolverHelpers);
544
+ console.log(items);
545
+ ```
546
+
547
+ โœ… **Expected Output:**
548
+
549
+ ```json
550
+ [
551
+ {
552
+ "ref": "ITEM-001",
553
+ "productRef": "SKU-WM-001",
554
+ "quantity": 2,
555
+ "price": 29.99,
556
+ "totalPrice": 64.78,
557
+ "attributes": {
558
+ "productName": "Wireless Mouse",
559
+ "position": 1,
560
+ "taxAmount": 4.8
561
+ }
562
+ },
563
+ {
564
+ "ref": "ITEM-002",
565
+ "productRef": "SKU-KB-001",
566
+ "quantity": 1,
567
+ "price": 79.99,
568
+ "totalPrice": 86.39,
569
+ "attributes": {
570
+ "productName": "Mechanical Keyboard",
571
+ "position": 2,
572
+ "taxAmount": 6.4
573
+ }
574
+ }
575
+ ]
576
+ ```
577
+
578
+ ---
579
+
580
+ ### Example 3: Inventory Management - Batch Ingestion
581
+
582
+ **Scenario:** Transform WMS inventory data to Fluent Commerce batch format.
583
+
584
+ **Source Data:** See [canonical-inventory.json](../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json)
585
+
586
+ ```typescript
587
+ export const inventoryResolvers = builder
588
+ // Extract location ID
589
+ .from('input.locationId', 'inventory.header.location-id')
590
+
591
+ // Transform inventory items array
592
+ .mapArray('input.entities', 'inventory.items', (item, index, config, helpers) => ({
593
+ skuRef: item.sku,
594
+ locationRef: item.location.id,
595
+ qty: helpers.parseIntSafe(item.quantity['on-hand'], 0),
596
+
597
+ // Optional: Add expected delivery date
598
+ expectedOn: helpers.get(item, 'dates.next-expected-receipt')
599
+ ? new Date(item['dates']['next-expected-receipt']).toISOString()
600
+ : null,
601
+
602
+ attributes: {
603
+ available: helpers.parseIntSafe(item.quantity.available, 0),
604
+ reserved: helpers.parseIntSafe(item.quantity.reserved, 0),
605
+ inTransit: helpers.parseIntSafe(item.quantity['in-transit'], 0),
606
+ binLocation: item.attributes['bin-location'],
607
+ lotNumber: item.attributes['lot-number'],
608
+ },
609
+ }))
610
+
611
+ .build();
612
+ ```
613
+
614
+ **Test it:**
615
+
616
+ ```typescript
617
+ import { canonicalInventory } from '../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json';
618
+
619
+ const result = {
620
+ locationId: inventoryResolvers\['input.locationId'](canonicalInventory, {}, ResolverHelpers),
621
+ entities: inventoryResolvers\['input.entities'](canonicalInventory, {}, ResolverHelpers),
622
+ };
623
+
624
+ console.log(result.entities[0]);
625
+ ```
626
+
627
+ โœ… **Expected Output:**
628
+
629
+ ```json
630
+ {
631
+ "skuRef": "SKU-WM-001",
632
+ "locationRef": "WH-001",
633
+ "qty": 250,
634
+ "expectedOn": "2025-01-20T00:00:00.000Z",
635
+ "attributes": {
636
+ "available": 200,
637
+ "reserved": 50,
638
+ "inTransit": 100,
639
+ "binLocation": "A-12-03",
640
+ "lotNumber": "LOT-2025-001"
641
+ }
642
+ }
643
+ ```
644
+
645
+ ---
646
+
647
+ ### Example 4: Complex Calculation - Total Discount
648
+
649
+ **Scenario:** Calculate total discount from multiple sources (item discounts + promotions).
650
+
651
+ ```typescript
652
+ builder.calculate('input.totalDiscount', (data, helpers) => {
653
+ // Get line items
654
+ const items = helpers.ensureArray(
655
+ helpers.get(data, 'orders.order.product-lineitems.product-lineitem', [])
656
+ );
657
+
658
+ // Calculate item-level discounts
659
+ const itemDiscounts = items.reduce((sum, item) => {
660
+ const basePrice = helpers.parseFloatSafe(item['base-price'], 0);
661
+ const netPrice = helpers.parseFloatSafe(item['net-price'], 0);
662
+ const quantity = helpers.parseIntSafe(item.quantity, 1);
663
+ return sum + (basePrice - netPrice) * quantity;
664
+ }, 0);
665
+
666
+ // Add order-level adjustment (if negative, it's a discount)
667
+ const adjustment = helpers.parseFloatSafe(
668
+ helpers.get(data, 'orders.order.totals.adjustment-total.gross-price'),
669
+ 0
670
+ );
671
+
672
+ const orderDiscount = adjustment < 0 ? Math.abs(adjustment) : 0;
673
+
674
+ const totalDiscount = itemDiscounts + orderDiscount;
675
+
676
+ helpers.log?.info('Calculated total discount', {
677
+ itemDiscounts,
678
+ orderDiscount,
679
+ totalDiscount,
680
+ });
681
+
682
+ return helpers.formatCurrency(totalDiscount, 2);
683
+ });
684
+ ```
685
+
686
+ **Test it:**
687
+
688
+ ```typescript
689
+ const discount = resolvers\['input.totalDiscount'](canonicalOrder, {}, ResolverHelpers);
690
+ console.log(discount); // Expected: "14.00" (from adjustment-total in canonical data)
691
+ ```
692
+
693
+ ---
694
+
695
+ ### Example 5: Conditional Mapping - Order Type
696
+
697
+ **Scenario:** Map channel type to Fluent order type with business rules.
698
+
699
+ ```typescript
700
+ builder.field('input.type', (data, config, helpers) => {
701
+ const channelType = helpers.get(data, 'orders.order.channel-type');
702
+ const isGift = helpers.get(data, 'orders.order.shipments.shipment.gift') === 'true';
703
+
704
+ // Channel to order type mapping
705
+ const channelMapping = {
706
+ Storefront: 'HD',
707
+ CallCenter: 'CC',
708
+ Mobile: 'MOBILE',
709
+ POS: 'STORE',
710
+ };
711
+
712
+ let orderType = helpers.mapValue(channelType, channelMapping, config.defaultOrderType || 'HD');
713
+
714
+ // Business rule: Gift orders get special type
715
+ if (isGift && orderType === 'HD') {
716
+ orderType = 'GIFT_HD';
717
+ }
718
+
719
+ helpers.log?.debug('Mapped order type', { channelType, isGift, orderType });
720
+
721
+ return orderType;
722
+ });
723
+ ```
724
+
725
+ **Test it:**
726
+
727
+ ```typescript
728
+ const orderType = resolvers`'input.type'`;
729
+ console.log(orderType); // Expected: "HD" (Storefront channel)
730
+ ```
731
+
732
+ ---
733
+
734
+ ## Advanced Topics
735
+
736
+ ### Async Operations & API Calls
737
+
738
+ Resolvers can be async to call external APIs or perform lookups.
739
+
740
+ **Example: Customer Lookup**
741
+
742
+ ```typescript
743
+ builder.field('input.customer.id', async (data, config, helpers) => {
744
+ const customerId = helpers.get(data, 'orders.order.customer.customer-no');
745
+
746
+ if (!helpers.fluentClient) {
747
+ throw new Error('FluentClient is required for customer lookup');
748
+ }
749
+
750
+ // Use retry helper for resilience
751
+ return await helpers.retry(
752
+ async () => {
753
+ // Query for existing customer
754
+ const result = await helpers.fluentClient.graphql({
755
+ query: `
756
+ query GetCustomer($username: [String]) {
757
+ customers(username: $username, first: 1) {
758
+ edges {
759
+ node { id username }
760
+ }
761
+ }
762
+ }
763
+ `,
764
+ variables: { username: [customerId] },
765
+ });
766
+
767
+ const existing = result.data?.customers?.edges?.[0]?.node;
768
+
769
+ if (existing) {
770
+ helpers.log?.info('Found existing customer', { id: existing.id });
771
+ return existing.id;
772
+ }
773
+
774
+ // Create new customer if not found
775
+ helpers.log?.info('Creating new customer', { customerId });
776
+ const createResult = await helpers.fluentClient.graphql({
777
+ query: `
778
+ mutation CreateCustomer($input: CreateCustomerInput!) {
779
+ createCustomer(input: $input) { id }
780
+ }
781
+ `,
782
+ variables: {
783
+ input: {
784
+ username: customerId,
785
+ retailer: { id: config.defaultRetailerId },
786
+ },
787
+ },
788
+ });
789
+
790
+ return createResult.data?.createCustomer?.id;
791
+ },
792
+ 3, // Retry 3 times
793
+ 500 // 500ms delay
794
+ );
795
+ });
796
+ ```
797
+
798
+ **Best Practices for Async Resolvers:**
799
+
800
+ 1. โœ… **Always use error handling**
801
+ 2. โœ… **Use `helpers.retry()` for transient failures**
802
+ 3. โœ… **Add timeout protection**
803
+ 4. โœ… **Log API calls for debugging**
804
+ 5. โœ… **Cache results when possible**
805
+
806
+ ๐Ÿ“– **Learn more:** [Async Patterns Cookbook](./mapping-resolvers-resolver-cookbook.md#async-patterns)
807
+
808
+ ---
809
+
810
+ ### Error Handling Patterns
811
+
812
+ **Pattern 1: Validation with Custom Errors**
813
+
814
+ ```typescript
815
+ builder.validate(
816
+ 'input.totalPrice',
817
+ (data, config, helpers) => {
818
+ const price = helpers.get(data, 'orders.order.totals.order-total.gross-price');
819
+ return helpers.parseFloatSafe(price, 0);
820
+ },
821
+ value => value > 0 || 'Total price must be greater than zero'
822
+ );
823
+ ```
824
+
825
+ **Pattern 2: Try-Catch with Fallbacks**
826
+
827
+ ```typescript
828
+ builder.field('input.customAttribute', (data, config, helpers) => {
829
+ try {
830
+ const attrs = helpers.get(data, 'orders.order.custom-attributes.custom-attribute');
831
+ return helpers.extractCustomAttribute(attrs, 'specialValue');
832
+ } catch (error) {
833
+ helpers.log?.warn('Failed to extract custom attribute', { error });
834
+ return config.defaultSpecialValue || null;
835
+ }
836
+ });
837
+ ```
838
+
839
+ ๐Ÿ“– **Learn more:** [Error Handling Guide](./mapping-resolvers-resolver-troubleshooting.md#error-patterns)
840
+
841
+ ---
842
+
843
+ ### Performance Optimization
844
+
845
+ **1. Memoize Expensive Calculations**
846
+
847
+ ```typescript
848
+ import { ResolverHelpers } from '@fluentcommerce/fc-connect-sdk';
849
+
850
+ const calculateComplexDiscount = ResolverHelpers.memoize((items, discountRules) => {
851
+ // Expensive calculation cached by input
852
+ return items.reduce((total, item) => {
853
+ return total + applyDiscountRules(item, discountRules);
854
+ }, 0);
855
+ });
856
+
857
+ builder.field('input.discount', (data, config, helpers) => {
858
+ const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem', []);
859
+ return calculateComplexDiscount(items, config.discountRules);
860
+ });
861
+ ```
862
+
863
+ **2. Parallel Async Operations**
864
+
865
+ ```typescript
866
+ // โŒ Sequential (slow)
867
+ const customer = await lookupCustomer(customerId);
868
+ const inventory = await checkInventory(sku);
869
+ const pricing = await getPricing(sku);
870
+
871
+ // โœ… Parallel (fast)
872
+ const [customer, inventory, pricing] = await Promise.all([
873
+ lookupCustomer(customerId),
874
+ checkInventory(sku),
875
+ getPricing(sku),
876
+ ]);
877
+ ```
878
+
879
+ **3. Batch Processing**
880
+
881
+ ```typescript
882
+ builder.field('input.enrichedItems', async (data, config, helpers) => {
883
+ const items = helpers.get(data, 'orders.order.product-lineitems.product-lineitem', []);
884
+
885
+ // Process in batches of 10
886
+ return await helpers.batchProcess(
887
+ items,
888
+ async item => {
889
+ // Enrich each item with external data
890
+ const details = await fetchProductDetails(item['product-id']);
891
+ return { ...item, ...details };
892
+ },
893
+ 10 // Batch size
894
+ );
895
+ });
896
+ ```
897
+
898
+ ๐Ÿ“– **Learn more:** [Performance Best Practices](./mapping-resolvers-resolver-cookbook.md#performance-optimization)
899
+
900
+ ---
901
+
902
+ ### Resolver-Only Fields & Required Validation
903
+
904
+ **New in SDK v0.1.37:** Required validation for resolver-only fields (fields without a source).
905
+
906
+ **What are resolver-only fields?**
907
+
908
+ Resolver-only fields are fields that don't extract data from a source path, but instead generate values programmatically using a resolver function.
909
+
910
+ **Use cases:**
911
+
912
+ 1. **Generate unique IDs** - Create UUIDs or composite keys
913
+ 2. **Derive values** - Calculate from other fields in the data
914
+ 3. **Enrich with external data** - Look up values from APIs without a source field
915
+ 4. **Apply business logic** - Determine values based on complex rules
916
+
917
+ ---
918
+
919
+ #### UniversalMapper Configuration
920
+
921
+ **Example: Generate ID without source**
922
+
923
+ ```json
924
+ {
925
+ "fields": {
926
+ "id": {
927
+ "resolver": "custom.generateProductId",
928
+ "required": true
929
+ },
930
+ "name": {
931
+ "source": "productName",
932
+ "required": true
933
+ },
934
+ "enrichedData": {
935
+ "resolver": "custom.enrichFromAPI",
936
+ "required": false
937
+ }
938
+ }
939
+ }
940
+ ```
941
+
942
+ **Resolver implementation:**
943
+
944
+ ```typescript
945
+ import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
946
+ import { v4 as uuid } from 'uuid';
947
+
948
+ const customResolvers = {
949
+ // Generate UUID for each product (no source needed)
950
+ 'custom.generateProductId': (value, sourceData, config, helpers) => {
951
+ // value is undefined (no source)
952
+ // Generate unique ID based on business logic
953
+ const sku = helpers.get(sourceData, 'sku');
954
+ const prefix = config.idPrefix || 'PROD';
955
+ return `${prefix}-${sku}-${uuid()}`;
956
+ },
957
+
958
+ // Enrich with external API data
959
+ 'custom.enrichFromAPI': async (value, sourceData, config, helpers) => {
960
+ const sku = helpers.get(sourceData, 'sku');
961
+
962
+ try {
963
+ const response = await helpers.retry(async () => {
964
+ return await fetch(`https://api.example.com/products/${sku}`);
965
+ }, 3);
966
+
967
+ return await response.json();
968
+ } catch (error) {
969
+ helpers.log?.warn('Failed to enrich product', { sku, error });
970
+ return null; // Optional field, return null on failure
971
+ }
972
+ },
973
+ };
974
+
975
+ const mapper = new UniversalMapper(mappingConfig, { customResolvers });
976
+ ```
977
+
978
+ ---
979
+
980
+ #### Validation Behavior
981
+
982
+ **For resolver-only fields (`resolver` without `source`):**
983
+
984
+ 1. โœ… **No source extraction** - Value starts as `undefined`
985
+ 2. โœ… **Skip pre-validation** - Required validation does NOT run before resolver
986
+ 3. โœ… **Execute resolver** - Resolver generates the value
987
+ 4. โœ… **Post-validation** - Required validation runs AFTER resolver execution
988
+
989
+ **For fields with source (`source` + `resolver`):**
990
+
991
+ 1. โœ… **Extract from source** - Value extracted from data
992
+ 2. โœ… **Validate required** - Required validation runs immediately
993
+ 3. โœ… **Execute resolver** - Resolver transforms the extracted value
994
+ 4. โœ… **No post-validation** - Required already validated before resolver
995
+
996
+ ---
997
+
998
+ #### When to Use Resolver-Only Required
999
+
1000
+ **โœ… Good use cases:**
1001
+
1002
+ ```json
1003
+ {
1004
+ "fields": {
1005
+ // Generate unique transaction ID
1006
+ "transactionId": {
1007
+ "resolver": "custom.generateTransactionId",
1008
+ "required": true
1009
+ },
1010
+
1011
+ // Look up customer ID by email from source
1012
+ "customerId": {
1013
+ "resolver": "custom.lookupCustomerByEmail",
1014
+ "required": true
1015
+ },
1016
+
1017
+ // Calculate value from multiple source fields
1018
+ "totalWeight": {
1019
+ "resolver": "custom.calculateTotalWeight",
1020
+ "required": true
1021
+ },
1022
+
1023
+ // Apply complex business rules
1024
+ "fulfillmentType": {
1025
+ "resolver": "custom.determineFulfillmentType",
1026
+ "required": true
1027
+ }
1028
+ }
1029
+ }
1030
+ ```
1031
+
1032
+ **โŒ Avoid for simple transformations:**
1033
+
1034
+ ```json
1035
+ {
1036
+ "fields": {
1037
+ // โŒ BAD - Use source + resolver instead
1038
+ "uppercaseStatus": {
1039
+ "resolver": "custom.getAndUppercaseStatus",
1040
+ "required": true
1041
+ },
1042
+
1043
+ // โœ… GOOD - Extract then transform
1044
+ "status": {
1045
+ "source": "orderStatus",
1046
+ "resolver": "sdk.uppercase",
1047
+ "required": true
1048
+ }
1049
+ }
1050
+ }
1051
+ ```
1052
+
1053
+ ---
1054
+
1055
+ #### Complete Example: Product Ingestion
1056
+
1057
+ ```typescript
1058
+ import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
1059
+ import { v4 as uuid } from 'uuid';
1060
+
1061
+ // Mapping configuration
1062
+ const productMappingConfig = {
1063
+ fields: {
1064
+ // Resolver-only: Generate unique product ID
1065
+ id: {
1066
+ resolver: 'custom.generateProductId',
1067
+ required: true,
1068
+ },
1069
+
1070
+ // Source + resolver: Extract and transform
1071
+ name: {
1072
+ source: 'productName',
1073
+ resolver: 'sdk.trim',
1074
+ required: true,
1075
+ },
1076
+
1077
+ sku: {
1078
+ source: 'sku',
1079
+ required: true,
1080
+ },
1081
+
1082
+ // Resolver-only: Enrich with category data
1083
+ category: {
1084
+ resolver: 'custom.resolveCategoryFromSku',
1085
+ required: false,
1086
+ },
1087
+
1088
+ // Static value
1089
+ type: {
1090
+ value: 'STANDARD',
1091
+ required: true,
1092
+ },
1093
+ },
1094
+ };
1095
+
1096
+ // Custom resolvers
1097
+ const customResolvers = {
1098
+ 'custom.generateProductId': (value, sourceData, config, helpers) => {
1099
+ const sku = helpers.get(sourceData, 'sku');
1100
+ const retailerId = config.retailerId;
1101
+ return `${retailerId}-${sku}-${uuid()}`;
1102
+ },
1103
+
1104
+ 'custom.resolveCategoryFromSku': async (value, sourceData, config, helpers) => {
1105
+ const sku = helpers.get(sourceData, 'sku');
1106
+
1107
+ // Lookup category from SKU prefix
1108
+ const prefix = sku.substring(0, 3);
1109
+ const categoryMap = {
1110
+ 'ELE': 'Electronics',
1111
+ 'CLO': 'Clothing',
1112
+ 'FOO': 'Food',
1113
+ };
1114
+
1115
+ return categoryMap[prefix] || 'General';
1116
+ },
1117
+ };
1118
+
1119
+ // Create mapper with custom resolvers
1120
+ const mapper = new UniversalMapper(
1121
+ productMappingConfig,
1122
+ {
1123
+ customResolvers,
1124
+ context: { retailerId: '1' },
1125
+ logger: console,
1126
+ }
1127
+ );
1128
+
1129
+ // Map product data
1130
+ const sourceData = {
1131
+ sku: 'ELE-12345',
1132
+ productName: ' Wireless Mouse ',
1133
+ };
1134
+
1135
+ const result = await mapper.map(sourceData);
1136
+
1137
+ console.log(result);
1138
+ // {
1139
+ // success: true,
1140
+ // data: {
1141
+ // id: '1-ELE-12345-a1b2c3d4-...',
1142
+ // name: 'Wireless Mouse',
1143
+ // sku: 'ELE-12345',
1144
+ // category: 'Electronics',
1145
+ // type: 'STANDARD'
1146
+ // }
1147
+ // }
1148
+ ```
1149
+
1150
+ ---
1151
+
1152
+ #### Required Validation Error Messages
1153
+
1154
+ **Resolver-only field returns empty:**
1155
+
1156
+ ```typescript
1157
+ // If resolver returns null/undefined/''
1158
+ {
1159
+ success: false,
1160
+ data: null,
1161
+ errors: [
1162
+ "Failed to map field 'id': Required field 'id' is missing or empty after resolver 'custom.generateId' execution"
1163
+ ]
1164
+ }
1165
+ ```
1166
+
1167
+ **Source-based required field missing:**
1168
+
1169
+ ```typescript
1170
+ // If source field is missing
1171
+ {
1172
+ success: false,
1173
+ data: null,
1174
+ errors: [
1175
+ "Failed to map field 'sku': Required field 'sku' is missing or empty (source: sku)"
1176
+ ]
1177
+ }
1178
+ ```
1179
+
1180
+ ---
1181
+
1182
+ #### Testing Resolver-Only Required Fields
1183
+
1184
+ ```typescript
1185
+ import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
1186
+
1187
+ describe('Resolver-only required fields', () => {
1188
+ it('should pass validation when resolver returns value', async () => {
1189
+ const mapper = new UniversalMapper(
1190
+ {
1191
+ fields: {
1192
+ id: {
1193
+ resolver: 'custom.generateId',
1194
+ required: true,
1195
+ },
1196
+ },
1197
+ },
1198
+ {
1199
+ customResolvers: {
1200
+ 'custom.generateId': () => 'generated-id-123',
1201
+ },
1202
+ }
1203
+ );
1204
+
1205
+ const result = await mapper.map({});
1206
+
1207
+ expect(result.success).toBe(true);
1208
+ expect(result.data.id).toBe('generated-id-123');
1209
+ });
1210
+
1211
+ it('should fail validation when resolver returns empty', async () => {
1212
+ const mapper = new UniversalMapper(
1213
+ {
1214
+ fields: {
1215
+ id: {
1216
+ resolver: 'custom.generateId',
1217
+ required: true,
1218
+ },
1219
+ },
1220
+ },
1221
+ {
1222
+ customResolvers: {
1223
+ 'custom.generateId': () => null, // Returns empty
1224
+ },
1225
+ }
1226
+ );
1227
+
1228
+ const result = await mapper.map({});
1229
+
1230
+ expect(result.success).toBe(false);
1231
+ expect(result.errors[0]).toContain('Required field');
1232
+ });
1233
+ });
1234
+ ```
1235
+
1236
+ ---
1237
+
1238
+ ๐Ÿ“– **Learn more:** [Performance Best Practices](./mapping-resolvers-resolver-cookbook.md#performance-optimization)
1239
+
1240
+ ---
1241
+
1242
+ ## Reference Documentation
1243
+
1244
+ ### ๐Ÿ“˜ Detailed References
1245
+
1246
+ | Document | Description |
1247
+ | ------------------------------------------------------------- | ---------------------------------------------------- |
1248
+ | [Resolver API Reference](./mapping-resolvers-resolver-api-reference.md) | Complete ResolverBuilder API documentation |
1249
+ | [Helper Functions Reference](./mapping-resolvers-resolver-helpers-reference.md) | All 54 helper functions with examples |
1250
+ | [Parameters Deep Dive](./mapping-resolvers-resolver-parameters-reference.md) | Detailed explanation of value, data, config, helpers |
1251
+ | [Troubleshooting Guide](./mapping-resolvers-resolver-troubleshooting.md) | Common issues and solutions |
1252
+ | [Cookbook](./mapping-resolvers-resolver-cookbook.md) | Advanced patterns and recipes |
1253
+
1254
+ ### ๐Ÿงช Test Examples
1255
+
1256
+ All examples are validated with automated tests:
1257
+
1258
+ ```bash
1259
+ cd fc-connect-sdk
1260
+ npm test -- examples/__tests__/resolver-guide-examples.test.ts
1261
+ ```
1262
+
1263
+ ๐Ÿ“ **Example Files:**
1264
+
1265
+ - [Resolver Examples](../examples/)
1266
+ - [Order Test Data](../../../03-PATTERN-GUIDES/examples/test-data/canonical-order.json)
1267
+ - [Inventory Test Data](../../../03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json)
1268
+
1269
+ ---
1270
+
1271
+ ## Best Practices Summary
1272
+
1273
+ ### โœ… Do's
1274
+
1275
+ 1. **Organize by domain** - Group related resolvers (order, customer, inventory)
1276
+ 2. **Use config for defaults** - Never hardcode environment-specific values
1277
+ 3. **Validate critical fields** - Use `.validate()` for required fields
1278
+ 4. **Use helper functions** - Don't reinvent the wheel
1279
+ 5. **Handle arrays gracefully** - Use `ensureArray()` and `mapArray()`
1280
+ 6. **Log important decisions** - Help with debugging
1281
+ 7. **Test in isolation** - Write unit tests for resolvers
1282
+ 8. **Use TypeScript types** - Leverage type safety
1283
+
1284
+ ### โŒ Don'ts
1285
+
1286
+ 1. **Don't hardcode values** - Use config instead
1287
+ 2. **Don't skip validation** - Validate required fields
1288
+ 3. **Don't ignore errors** - Handle async failures gracefully
1289
+ 4. **Don't forget to await** - Async resolvers must be awaited
1290
+ 5. **Don't assume array structure** - XML can return object for single item
1291
+ 6. **Don't skip logging** - Log for production debugging
1292
+ 7. **Don't write untested code** - Test with canonical data
1293
+
1294
+ ---
1295
+
1296
+ ## Next Steps
1297
+
1298
+ ### ๐ŸŽ“ Continue Learning
1299
+
1300
+ 1. **Beginner (30 min):**
1301
+ - โœ… Completed Quick Start
1302
+ - ๐Ÿ“– Read [Resolver Parameters](./mapping-resolvers-resolver-parameters-reference.md)
1303
+ - ๐Ÿงช Test examples with canonical data
1304
+
1305
+ 2. **Intermediate (2 hours):**
1306
+ - ๐Ÿ“– Read [API Reference](./mapping-resolvers-resolver-api-reference.md)
1307
+ - ๐Ÿ’ป Build resolvers for your use case
1308
+ - ๐Ÿงช Write tests for your resolvers
1309
+
1310
+ 3. **Advanced (4 hours):**
1311
+ - ๐Ÿ“– Read [Cookbook](./mapping-resolvers-resolver-cookbook.md)
1312
+ - ๐ŸŒ Add async API calls
1313
+ - ๐Ÿš€ Deploy to production
1314
+
1315
+ ### ๐Ÿ†˜ Get Help
1316
+
1317
+ - **GitHub Issues:** https://github.com/fluentcommerce/fc-connect-sdk/issues
1318
+ - **Documentation:** https://docs.fluentcommerce.com
1319
+ - **Email:** support@fluentcommerce.com
1320
+
1321
+ ---
1322
+
1323
+ **Document Version:** 2.0.0
1324
+ **SDK Version:** 1.5.0+
1325
+ **Last Updated:** 2025-01-14
1326
+
1327
+ ---
1328
+
1329
+ **License:** MIT
1330
+ **Copyright:** ยฉ 2025 Fluent Commerce