@fluentcommerce/fc-connect-sdk 0.1.53 โ†’ 0.1.55

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