@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/clients/fluent-client.js +13 -6
  3. package/dist/cjs/utils/pagination-helpers.js +38 -2
  4. package/dist/cjs/versori/fluent-versori-client.js +11 -5
  5. package/dist/esm/clients/fluent-client.js +13 -6
  6. package/dist/esm/utils/pagination-helpers.js +38 -2
  7. package/dist/esm/versori/fluent-versori-client.js +11 -5
  8. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  9. package/dist/tsconfig.tsbuildinfo +1 -1
  10. package/dist/tsconfig.types.tsbuildinfo +1 -1
  11. package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
  12. package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
  13. package/docs/00-START-HERE/cli-documentation-index.md +202 -202
  14. package/docs/00-START-HERE/cli-quick-reference.md +252 -252
  15. package/docs/00-START-HERE/decision-tree.md +552 -552
  16. package/docs/00-START-HERE/getting-started.md +1070 -1070
  17. package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
  18. package/docs/00-START-HERE/readme.md +237 -237
  19. package/docs/00-START-HERE/retailerid-configuration.md +404 -404
  20. package/docs/00-START-HERE/sdk-philosophy.md +794 -794
  21. package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
  22. package/docs/01-TEMPLATES/faq.md +686 -686
  23. package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
  24. package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
  25. package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
  26. package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
  27. package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
  28. package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
  29. package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
  30. package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
  31. package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
  32. package/docs/01-TEMPLATES/readme.md +957 -957
  33. package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
  34. package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
  35. package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
  36. package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
  37. package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
  38. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
  39. package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
  40. package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
  41. package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
  42. package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
  43. package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
  44. package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
  45. package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
  46. package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
  47. package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
  48. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
  49. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
  50. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
  51. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
  52. package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
  53. package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
  54. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
  55. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
  56. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
  57. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
  58. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
  59. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
  60. package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
  61. package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
  62. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
  63. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
  64. package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
  65. package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
  66. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
  67. package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
  68. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
  69. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
  70. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
  71. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
  72. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
  73. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
  74. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
  75. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
  76. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
  77. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
  78. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
  79. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
  80. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
  81. package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
  82. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
  83. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
  84. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
  85. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
  86. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
  87. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
  88. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
  89. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
  90. package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
  91. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
  92. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
  93. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
  94. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
  95. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
  96. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
  97. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
  98. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
  99. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
  100. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
  101. package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
  102. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
  103. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
  104. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
  105. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
  106. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
  107. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
  108. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
  109. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
  110. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
  111. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
  112. package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
  113. package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
  114. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
  115. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
  116. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
  117. package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
  118. package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
  119. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
  120. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
  121. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
  122. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
  123. package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
  124. package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
  125. package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
  126. package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
  127. package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
  128. package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
  129. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
  130. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
  131. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
  132. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
  133. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
  134. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
  135. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
  136. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
  137. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
  138. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
  139. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
  140. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
  141. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
  142. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
  143. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
  144. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
  145. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
  146. package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
  147. package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
  148. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
  149. package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
  150. package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
  151. package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
  152. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
  153. package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
  154. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
  155. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
  156. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
  157. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
  158. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
  159. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
  160. package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
  161. package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
  162. package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
  163. package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
  164. package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
  165. package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
  166. package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
  167. package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
  168. package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
  169. package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
  170. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
  171. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
  172. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
  173. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
  174. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
  175. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
  176. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
  177. package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
  178. package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
  179. package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
  180. package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
  181. package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
  182. package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
  183. package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
  184. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
  185. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
  186. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
  187. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
  188. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
  189. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
  190. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
  191. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
  192. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
  193. package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
  194. package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
  195. package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
  196. package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
  197. package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
  198. package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
  199. package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
  200. package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
  201. package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
  202. package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
  203. package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
  204. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
  205. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
  206. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
  207. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
  208. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
  209. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
  210. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
  211. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
  212. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
  213. package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
  214. package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
  215. package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
  216. package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
  217. package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
  218. package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
  219. package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
  220. package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
  221. package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
  222. package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
  223. package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
  224. package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
  225. package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
  226. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
  227. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
  228. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
  229. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
  230. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
  231. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
  232. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
  233. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
  234. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
  235. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
  236. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
  237. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
  238. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
  239. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
  240. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
  241. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
  242. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
  243. package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
  244. package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
  245. package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
  246. package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
  247. package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
  248. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
  249. package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
  250. package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
  251. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
  252. package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
  253. package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
  254. package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
  255. package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
  256. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
  257. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
  258. package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
  259. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
  260. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
  261. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
  262. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
  263. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
  264. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
  265. package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
  266. package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
  267. package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
  268. package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
  269. package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
  270. package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
  271. package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
  272. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
  273. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
  274. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
  275. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
  276. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
  277. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
  278. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
  279. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
  280. package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
  281. package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
  282. package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
  283. package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
  284. package/docs/02-CORE-GUIDES/readme.md +194 -194
  285. package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
  286. package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
  287. package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
  288. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
  289. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
  290. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
  291. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
  292. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
  293. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
  294. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
  295. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
  296. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
  297. package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
  298. package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
  299. package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
  300. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
  301. package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
  302. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
  303. package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
  304. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
  305. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
  306. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
  307. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
  308. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
  309. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
  310. package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
  311. package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
  312. package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
  313. package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
  314. package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
  315. package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
  316. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
  317. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
  318. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
  319. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
  320. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
  321. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
  322. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
  323. package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
  324. package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
  325. package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
  326. package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
  327. package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
  328. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
  329. package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
  330. package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
  331. package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
  332. package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
  333. package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
  334. package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
  335. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
  336. package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
  337. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
  338. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
  339. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
  340. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
  341. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
  342. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
  343. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
  344. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
  345. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
  346. package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
  347. package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
  348. package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
  349. package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
  350. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
  351. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
  352. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
  353. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
  354. package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
  355. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
  356. package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
  357. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
  358. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
  359. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
  360. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
  361. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
  362. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
  363. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
  364. package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
  365. package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
  366. package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
  367. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
  368. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
  369. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
  370. package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
  371. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
  372. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
  373. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
  374. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
  375. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
  376. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
  377. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
  378. package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
  379. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
  380. package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
  381. package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
  382. package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
  383. package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
  384. package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
  385. package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
  386. package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
  387. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
  388. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
  389. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
  390. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
  391. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
  392. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
  393. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
  394. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
  395. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
  396. package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
  397. package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
  398. package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
  399. package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
  400. package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
  401. package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
  402. package/docs/03-PATTERN-GUIDES/readme.md +159 -159
  403. package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
  404. package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
  405. package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
  406. package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
  407. package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
  408. package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
  409. package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
  410. package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
  411. package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
  412. package/docs/04-REFERENCE/architecture/readme.md +279 -279
  413. package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
  414. package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
  415. package/docs/04-REFERENCE/platforms/readme.md +135 -135
  416. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
  417. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
  418. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
  419. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
  420. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
  421. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
  422. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
  423. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
  424. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
  425. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
  426. package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
  427. package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
  428. package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
  429. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
  430. package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
  431. package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
  432. package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
  433. package/docs/04-REFERENCE/readme.md +148 -148
  434. package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
  435. package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
  436. package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
  437. package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
  438. package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
  439. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
  440. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
  441. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
  442. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
  443. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
  444. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
  445. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
  446. package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
  447. package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
  448. package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
  449. package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
  450. package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
  451. package/docs/04-REFERENCE/schema/readme.md +141 -141
  452. package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
  453. package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
  454. package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
  455. package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
  456. package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
  457. package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
  458. package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
  459. package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
  460. package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
  461. package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
  462. package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
  463. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
  464. package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
  465. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
  466. package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
  467. package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
  468. package/docs/04-REFERENCE/testing/readme.md +86 -86
  469. package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
  470. package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
  471. package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
  472. package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
  473. package/docs/template-loading-matrix.md +242 -242
  474. package/package.json +5 -3
  475. package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
@@ -1,1185 +1,1185 @@
1
- # Standalone: Multi-Channel Inventory Sync (Real-Time ATP to Marketplaces)
2
-
3
- **FC Connect SDK Use Case Guide**
4
-
5
- > **SDK**: [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)
6
- > **Version**: Use latest - `npm install @fluentcommerce/fc-connect-sdk@latest`
7
-
8
- **Context**: Node.js script that aggregates Available-to-Promise (ATP) inventory from Fluent Commerce and pushes real-time updates to multiple marketplaces (Amazon, eBay, Walmart)
9
-
10
- **Complexity**: High
11
-
12
- **Runtime**: Node.js >=18
13
-
14
- **Estimated Lines**: ~950 lines
15
-
16
- **Volume**: Large (10k-100k SKUs, multiple marketplaces)
17
-
18
- **Latency**: Near real-time (every 5-15 min)
19
-
20
- **Pattern**: GraphQL pagination → external marketplace APIs
21
-
22
- ## What You'll Build
23
-
24
- - OAuth2-authenticated Fluent Commerce client
25
- - GraphQL query with auto-pagination for inventory positions
26
- - ATP (Available-to-Promise) aggregation across multiple locations
27
- - Marketplace-specific buffer stock calculations
28
- - Parallel marketplace updates with rate limiting:
29
- - Amazon MWS/SP-API integration
30
- - eBay Trading API integration
31
- - Walmart Seller API integration
32
- - Per-marketplace error handling and retry logic
33
- - SLA tracking (15-minute sync requirement)
34
- - Comprehensive metrics and logging
35
- - Dry-run mode for testing
36
- - State management to prevent duplicate updates
37
-
38
- ## SDK Methods Used
39
-
40
- - `createClient({ config: { baseUrl, clientId, clientSecret, retailerId } })` - OAuth2 client
41
- - `client.graphql({ query, variables, pagination })` - Query with auto-pagination
42
- - `UniversalMapper(mappingConfig)` - Transform Fluent data to marketplace formats
43
- - `createConsoleLogger()` - Simple console logger
44
- - `toStructuredLogger(logger, context)` - Add context to logs
45
- - `generateCorrelationId()` - Generate unique correlation IDs
46
- - State tracking for incremental updates
47
-
48
- ---
49
-
50
- ## Complete Working Implementation
51
-
52
- ### 1. Project Setup
53
-
54
- ```bash
55
- # Create project directory
56
- mkdir multi-channel-inventory-sync
57
- cd multi-channel-inventory-sync
58
-
59
- # Initialize Node.js project
60
- npm init -y
61
-
62
- # Install dependencies
63
- npm install @fluentcommerce/fc-connect-sdk dotenv axios p-limit p-retry
64
- ```
65
-
66
- ### 2. Environment Configuration
67
-
68
- Create `.env` file:
69
-
70
- ```bash
71
- # Fluent Commerce OAuth2
72
- FLUENT_BASE_URL=https://api.fluentcommerce.com
73
- FLUENT_CLIENT_ID=your-oauth2-client-id
74
- FLUENT_CLIENT_SECRET=your-oauth2-client-secret
75
- FLUENT_RETAILER_ID=your-retailer-id
76
-
77
- # Sync Configuration
78
- SYNC_INTERVAL_MINUTES=15
79
- SLA_THRESHOLD_MINUTES=15
80
- MAX_RECORDS_PER_SYNC=100000
81
- DRY_RUN=false
82
-
83
- # Amazon SP-API Credentials
84
- AMAZON_ENABLED=true
85
- AMAZON_MARKETPLACE_ID=ATVPDKIKX0DER
86
- AMAZON_SELLER_ID=your-amazon-seller-id
87
- AMAZON_REFRESH_TOKEN=your-amazon-refresh-token
88
- AMAZON_CLIENT_ID=amzn1.application-oa2-client.xxxxx
89
- AMAZON_CLIENT_SECRET=your-amazon-client-secret
90
- AMAZON_AWS_ACCESS_KEY_ID=your-aws-access-key
91
- AMAZON_AWS_SECRET_ACCESS_KEY=your-aws-secret-key
92
- AMAZON_REGION=us-east-1
93
- AMAZON_ROLE_ARN=arn:aws:iam::123456789:role/SellingPartnerAPI
94
- AMAZON_BUFFER_STOCK=5
95
- AMAZON_RATE_LIMIT=10
96
-
97
- # eBay Trading API Credentials
98
- EBAY_ENABLED=true
99
- EBAY_APP_ID=your-ebay-app-id
100
- EBAY_DEV_ID=your-ebay-dev-id
101
- EBAY_CERT_ID=your-ebay-cert-id
102
- EBAY_AUTH_TOKEN=your-ebay-auth-token
103
- EBAY_SITE_ID=0
104
- EBAY_SANDBOX=false
105
- EBAY_BUFFER_STOCK=3
106
- EBAY_RATE_LIMIT=5
107
-
108
- # Walmart Seller API Credentials
109
- WALMART_ENABLED=true
110
- WALMART_CLIENT_ID=your-walmart-client-id
111
- WALMART_CLIENT_SECRET=your-walmart-client-secret
112
- WALMART_CHANNEL_TYPE=0a7d6c3e-e9a0-4a0c-8d6a-f6c6f1e7a5c7
113
- WALMART_BUFFER_STOCK=10
114
- WALMART_RATE_LIMIT=20
115
-
116
- # Logging
117
- LOG_LEVEL=info
118
- METRICS_ENABLED=true
119
- ```
120
-
121
- ### 3. Package Configuration
122
-
123
- Create `package.json`:
124
-
125
- ```json
126
- {
127
- "name": "multi-channel-inventory-sync",
128
- "version": "1.0.0",
129
- "type": "module",
130
- "description": "Real-time ATP inventory sync from Fluent Commerce to multiple marketplaces",
131
- "main": "src/index.js",
132
- "scripts": {
133
- "start": "node src/index.js",
134
- "sync:once": "node src/index.js --once",
135
- "sync:continuous": "node src/index.js",
136
- "sync:dry-run": "DRY_RUN=true node src/index.js --once",
137
- "test": "node --test tests/**/*.test.js"
138
- },
139
- "dependencies": {
140
- "@fluentcommerce/fc-connect-sdk": "^0.1.39",
141
- "axios": "^1.6.0",
142
- "dotenv": "^16.0.0",
143
- "p-limit": "^5.0.0",
144
- "p-retry": "^6.0.0"
145
- },
146
- "devDependencies": {
147
- "@types/node": "^20.0.0"
148
- },
149
- "engines": {
150
- "node": ">=18.0.0"
151
- }
152
- }
153
- ```
154
-
155
- ### 4. TypeScript Configuration (tsconfig.json)
156
-
157
- ```json
158
- {
159
- "compilerOptions": {
160
- "module": "ES2022",
161
- "target": "ES2024",
162
- "moduleResolution": "node"
163
- }
164
- }
165
- ```
166
-
167
- ### 5. Main Script Implementation (src/multi-channel-sync.ts)
168
-
169
- > **⚠️ RUNTIME COMPATIBILITY NOTE:**
170
- > This template includes `import { Buffer } from 'node:buffer';` for Deno/Versori compatibility.
171
- > While Buffer is globally available in Node.js and this import is optional for Node.js-only deployments,
172
- > including it ensures the code works across all runtimes (Node.js, Deno, Versori) without modification.
173
-
174
- ```typescript
175
- import 'dotenv/config';
176
- import { Buffer } from 'node:buffer'; // Required for Deno/Versori runtime compatibility
177
-
178
- // FC Connect SDK+
179
- // Install: npm install @fluentcommerce/fc-connect-sdk@latest
180
- // Docs: https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk
181
- // GitHub: https://github.com/fluentcommerce/fc-connect-sdk
182
-
183
- import {
184
- createClient,
185
- type FluentClient,
186
- type StructuredLogger,
187
- createConsoleLogger,
188
- toStructuredLogger
189
- } from '@fluentcommerce/fc-connect-sdk';
190
-
191
- import axios, { AxiosInstance } from 'axios';
192
- import pLimit from 'p-limit';
193
-
194
- // ============================================================================
195
- // TYPES & INTERFACES
196
- // ============================================================================
197
-
198
- interface InventoryPosition {
199
- productRef: string;
200
- locationRef: string;
201
- quantity: number;
202
- onHand: number;
203
- available: number;
204
- reserved: number;
205
- }
206
-
207
- interface ChannelConfig {
208
- enabled: boolean;
209
- apiClient: AxiosInstance;
210
- bufferStock: number;
211
- rateLimit: number;
212
- }
213
-
214
- interface SyncMetrics {
215
- startTime: Date;
216
- endTime?: Date;
217
- totalSKUs: number;
218
- successfulUpdates: number;
219
- failedUpdates: number;
220
- skippedUpdates: number;
221
- errors: Array<{ sku: string; channel: string; error: string }>;
222
- rateLimitHits: number;
223
- avgResponseTime: number;
224
- }
225
-
226
- // ============================================================================
227
- // CONFIGURATION
228
- // ============================================================================
229
-
230
- const config = {
231
- fluent: {
232
- baseUrl: process.env.FLUENT_BASE_URL!,
233
- clientId: process.env.FLUENT_CLIENT_ID!,
234
- clientSecret: process.env.FLUENT_CLIENT_SECRET!,
235
- retailerId: process.env.FLUENT_RETAILER_ID!,
236
- },
237
- amazon: {
238
- enabled: process.env.AMAZON_ENABLED === 'true',
239
- clientId: process.env.AMAZON_CLIENT_ID!,
240
- clientSecret: process.env.AMAZON_CLIENT_SECRET!,
241
- refreshToken: process.env.AMAZON_REFRESH_TOKEN!,
242
- marketplaceId: process.env.AMAZON_MARKETPLACE_ID!,
243
- sellerId: process.env.AMAZON_SELLER_ID!,
244
- bufferStock: parseInt(process.env.AMAZON_BUFFER_STOCK || '5'),
245
- rateLimit: parseInt(process.env.AMAZON_RATE_LIMIT || '10'),
246
- },
247
- ebay: {
248
- enabled: process.env.EBAY_ENABLED === 'true',
249
- appId: process.env.EBAY_APP_ID!,
250
- certId: process.env.EBAY_CERT_ID!,
251
- authToken: process.env.EBAY_AUTH_TOKEN!,
252
- siteId: process.env.EBAY_SITE_ID || '0',
253
- bufferStock: parseInt(process.env.EBAY_BUFFER_STOCK || '3'),
254
- rateLimit: parseInt(process.env.EBAY_RATE_LIMIT || '5'),
255
- },
256
- walmart: {
257
- enabled: process.env.WALMART_ENABLED === 'true',
258
- clientId: process.env.WALMART_CLIENT_ID!,
259
- clientSecret: process.env.WALMART_CLIENT_SECRET!,
260
- channelType: process.env.WALMART_CHANNEL_TYPE!,
261
- bufferStock: parseInt(process.env.WALMART_BUFFER_STOCK || '10'),
262
- rateLimit: parseInt(process.env.WALMART_RATE_LIMIT || '20'),
263
- },
264
- processing: {
265
- concurrency: parseInt(process.env.CONCURRENCY || '10'),
266
- metricsEnabled: process.env.METRICS_ENABLED === 'true',
267
- },
268
- };
269
-
270
- // ============================================================================
271
- // MARKETPLACE API CLIENTS
272
- // ============================================================================
273
-
274
- class AmazonAPIClient {
275
- private client: AxiosInstance;
276
- private accessToken?: string;
277
- private tokenExpiry?: Date;
278
-
279
- constructor(
280
- private config: typeof config.amazon,
281
- private logger: StructuredLogger
282
- ) {
283
- this.client = axios.create({
284
- baseURL: 'https://sellingpartnerapi-na.amazon.com',
285
- timeout: 30000,
286
- });
287
- }
288
-
289
- async ensureAuthenticated(): Promise<void> {
290
- if (this.accessToken && this.tokenExpiry && new Date() < this.tokenExpiry) {
291
- return; // Token still valid
292
- }
293
-
294
- this.logger.info('Refreshing Amazon SP-API access token');
295
-
296
- const response = await axios.post('https://api.amazon.com/auth/o2/token', {
297
- grant_type: 'refresh_token',
298
- refresh_token: this.config.refreshToken,
299
- client_id: this.config.clientId,
300
- client_secret: this.config.clientSecret,
301
- });
302
-
303
- this.accessToken = response.data.access_token;
304
- this.tokenExpiry = new Date(Date.now() + response.data.expires_in * 1000);
305
-
306
- this.logger.info('Amazon SP-API token refreshed successfully');
307
- }
308
-
309
- async updateInventory(sku: string, quantity: number): Promise<void> {
310
- await this.ensureAuthenticated();
311
-
312
- const payload = {
313
- marketplaceId: this.config.marketplaceId,
314
- sellerId: this.config.sellerId,
315
- feeds: [
316
- {
317
- feedType: 'POST_INVENTORY_AVAILABILITY_DATA',
318
- feedOptions: {
319
- encoding: 'UTF-8',
320
- },
321
- feedContent: this.buildInventoryFeedXml(sku, quantity),
322
- },
323
- ],
324
- };
325
-
326
- await this.client.post('/feeds/2021-06-30/feeds', payload, {
327
- headers: {
328
- 'x-amz-access-token': this.accessToken,
329
- 'Content-Type': 'application/json',
330
- },
331
- });
332
- }
333
-
334
- private buildInventoryFeedXml(sku: string, quantity: number): string {
335
- return `<?xml version="1.0" encoding="UTF-8"?>
336
- <AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
337
- <Header>
338
- <DocumentVersion>1.01</DocumentVersion>
339
- <MerchantIdentifier>${this.config.sellerId}</MerchantIdentifier>
340
- </Header>
341
- <MessageType>Inventory</MessageType>
342
- <Message>
343
- <MessageID>1</MessageID>
344
- <OperationType>Update</OperationType>
345
- <Inventory>
346
- <SKU>${sku}</SKU>
347
- <Quantity>${quantity}</Quantity>
348
- <FulfillmentLatency>2</FulfillmentLatency>
349
- </Inventory>
350
- </Message>
351
- </AmazonEnvelope>`;
352
- }
353
- }
354
-
355
- class eBayAPIClient {
356
- private client: AxiosInstance;
357
-
358
- constructor(
359
- private config: typeof config.ebay,
360
- private logger: StructuredLogger
361
- ) {
362
- this.client = axios.create({
363
- baseURL: 'https://api.ebay.com/ws/api.dll',
364
- timeout: 30000,
365
- });
366
- }
367
-
368
- async updateInventory(sku: string, quantity: number): Promise<void> {
369
- const xmlRequest = `<?xml version="1.0" encoding="utf-8"?>
370
- <ReviseInventoryStatusRequest xmlns="urn:ebay:apis:eBLBaseComponents">
371
- <RequesterCredentials>
372
- <eBayAuthToken>${this.config.authToken}</eBayAuthToken>
373
- </RequesterCredentials>
374
- <InventoryStatus>
375
- <SKU>${sku}</SKU>
376
- <Quantity>${quantity}</Quantity>
377
- </InventoryStatus>
378
- </ReviseInventoryStatusRequest>`;
379
-
380
- await this.client.post('', xmlRequest, {
381
- headers: {
382
- 'X-EBAY-API-SITEID': this.config.siteId,
383
- 'X-EBAY-API-COMPATIBILITY-LEVEL': '967',
384
- 'X-EBAY-API-CALL-NAME': 'ReviseInventoryStatus',
385
- 'Content-Type': 'text/xml',
386
- },
387
- });
388
- }
389
- }
390
-
391
- class WalmartAPIClient {
392
- private client: AxiosInstance;
393
- private accessToken?: string;
394
- private tokenExpiry?: Date;
395
-
396
- constructor(
397
- private config: typeof config.walmart,
398
- private logger: StructuredLogger
399
- ) {
400
- this.client = axios.create({
401
- baseURL: 'https://marketplace.walmartapis.com/v3',
402
- timeout: 30000,
403
- });
404
- }
405
-
406
- async ensureAuthenticated(): Promise<void> {
407
- if (this.accessToken && this.tokenExpiry && new Date() < this.tokenExpiry) {
408
- return;
409
- }
410
-
411
- this.logger.info('Refreshing Walmart Marketplace access token');
412
-
413
- const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString(
414
- 'base64'
415
- );
416
-
417
- const response = await axios.post(
418
- 'https://marketplace.walmartapis.com/v3/token',
419
- 'grant_type=client_credentials',
420
- {
421
- headers: {
422
- Authorization: `Basic ${credentials}`,
423
- 'Content-Type': 'application/x-www-form-urlencoded',
424
- 'WM_SVC.NAME': 'Walmart Marketplace',
425
- 'WM_QOS.CORRELATION_ID': Date.now().toString(),
426
- },
427
- }
428
- );
429
-
430
- this.accessToken = response.data.access_token;
431
- this.tokenExpiry = new Date(Date.now() + response.data.expires_in * 1000);
432
-
433
- this.logger.info('Walmart access token refreshed successfully');
434
- }
435
-
436
- async updateInventory(sku: string, quantity: number): Promise<void> {
437
- await this.ensureAuthenticated();
438
-
439
- const payload = {
440
- sku,
441
- quantity: {
442
- unit: 'EACH',
443
- amount: quantity,
444
- },
445
- };
446
-
447
- await this.client.put(`/inventory?sku=${sku}`, payload, {
448
- headers: {
449
- 'WM_SEC.ACCESS_TOKEN': this.accessToken,
450
- 'WM_SVC.NAME': 'Walmart Marketplace',
451
- 'WM_QOS.CORRELATION_ID': Date.now().toString(),
452
- 'Content-Type': 'application/json',
453
- },
454
- });
455
- }
456
- }
457
-
458
- // ============================================================================
459
- // MULTI-CHANNEL INVENTORY SYNCHRONIZER
460
- // ============================================================================
461
-
462
- class MultiChannelInventorySync {
463
- private fluentClient: FluentClient;
464
- private logger: StructuredLogger;
465
- private channels: Map<string, ChannelConfig> = new Map();
466
- private metrics: SyncMetrics;
467
-
468
- constructor() {
469
- this.logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
470
-
471
- this.metrics = {
472
- startTime: new Date(),
473
- totalSKUs: 0,
474
- successfulUpdates: 0,
475
- failedUpdates: 0,
476
- skippedUpdates: 0,
477
- errors: [],
478
- rateLimitHits: 0,
479
- avgResponseTime: 0,
480
- };
481
- }
482
-
483
- async initialize(): Promise<void> {
484
- this.logger.info('Initializing Multi-Channel Inventory Sync');
485
-
486
- // Initialize Fluent Commerce client
487
- this.fluentClient = await createClient({ config: config.fluent });
488
-
489
- // Initialize marketplace API clients
490
- if (config.amazon.enabled) {
491
- const amazonClient = new AmazonAPIClient(config.amazon, this.logger);
492
- this.channels.set('amazon', {
493
- enabled: true,
494
- apiClient: amazonClient as any,
495
- bufferStock: config.amazon.bufferStock,
496
- rateLimit: config.amazon.rateLimit,
497
- });
498
- this.logger.info('Amazon SP-API client initialized');
499
- }
500
-
501
- if (config.ebay.enabled) {
502
- const ebayClient = new eBayAPIClient(config.ebay, this.logger);
503
- this.channels.set('ebay', {
504
- enabled: true,
505
- apiClient: ebayClient as any,
506
- bufferStock: config.ebay.bufferStock,
507
- rateLimit: config.ebay.rateLimit,
508
- });
509
- this.logger.info('eBay Trading API client initialized');
510
- }
511
-
512
- if (config.walmart.enabled) {
513
- const walmartClient = new WalmartAPIClient(config.walmart, this.logger);
514
- this.channels.set('walmart', {
515
- enabled: true,
516
- apiClient: walmartClient as any,
517
- bufferStock: config.walmart.bufferStock,
518
- rateLimit: config.walmart.rateLimit,
519
- });
520
- this.logger.info('Walmart Marketplace API client initialized');
521
- }
522
-
523
- this.logger.info(`Initialized ${this.channels.size} marketplace channels`);
524
- }
525
-
526
- async syncInventory(): Promise<void> {
527
- this.logger.info('Starting multi-channel inventory sync');
528
- this.metrics.startTime = new Date();
529
-
530
- try {
531
- // Step 1: Fetch all ATP inventory from Fluent Commerce
532
- const inventory = await this.fetchFluentInventory();
533
- this.metrics.totalSKUs = inventory.length;
534
-
535
- this.logger.info(`Fetched ${inventory.length} inventory positions from Fluent`);
536
-
537
- // Step 2: Calculate ATP for each channel with buffer stock
538
- const channelInventory = this.calculateChannelInventory(inventory);
539
-
540
- // Step 3: Update each marketplace in parallel with rate limiting
541
- await this.updateMarketplaces(channelInventory);
542
-
543
- this.metrics.endTime = new Date();
544
- this.logMetrics();
545
-
546
- this.logger.info('Multi-channel inventory sync completed successfully');
547
- } catch (error: any) {
548
- this.logger.error('Multi-channel inventory sync failed', error);
549
- throw error;
550
- }
551
- }
552
-
553
- private async fetchFluentInventory(): Promise<InventoryPosition[]> {
554
- const query = `
555
- query GetInventory($retailerId: ID!, $first: Int!, $after: String) {
556
- inventoryQuantities(
557
- first: $first
558
- after: $after
559
- retailerId: $retailerId
560
- type: "AVAILABLE"
561
- ) {
562
- edges {
563
- node {
564
- productRef
565
- locationRef
566
- quantity
567
- onHand
568
- available
569
- reserved
570
- }
571
- cursor
572
- }
573
- pageInfo {
574
- hasNextPage
575
- }
576
- }
577
- }
578
- `;
579
-
580
- const result = await this.fluentClient.graphql({
581
- query,
582
- variables: {
583
- retailerId: config.fluent.retailerId,
584
- first: 250,
585
- },
586
- pagination: {
587
- maxPages: 500,
588
- },
589
- });
590
-
591
- if (result.errors) {
592
- throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`);
593
- }
594
-
595
- const edges = (result.data as any).inventoryQuantities?.edges || [];
596
- return edges.map((edge: any) => edge.node);
597
- }
598
-
599
- private calculateChannelInventory(
600
- inventory: InventoryPosition[]
601
- ): Map<string, Map<string, number>> {
602
- const channelInventory = new Map<string, Map<string, number>>();
603
-
604
- for (const [channelName, channelConfig] of this.channels) {
605
- const skuQuantities = new Map<string, number>();
606
-
607
- for (const position of inventory) {
608
- const atpQuantity = position.available || 0;
609
- const channelQuantity = Math.max(0, atpQuantity - channelConfig.bufferStock);
610
- skuQuantities.set(position.productRef, channelQuantity);
611
- }
612
-
613
- channelInventory.set(channelName, skuQuantities);
614
- }
615
-
616
- return channelInventory;
617
- }
618
-
619
- private async updateMarketplaces(
620
- channelInventory: Map<string, Map<string, number>>
621
- ): Promise<void> {
622
- const updatePromises: Promise<void>[] = [];
623
-
624
- for (const [channelName, skuQuantities] of channelInventory) {
625
- const channelConfig = this.channels.get(channelName)!;
626
- const limit = pLimit(channelConfig.rateLimit);
627
-
628
- const channelPromises = Array.from(skuQuantities.entries()).map(([sku, quantity]) =>
629
- limit(async () => {
630
- try {
631
- const startTime = Date.now();
632
-
633
- if (channelName === 'amazon') {
634
- await (channelConfig.apiClient as any).updateInventory(sku, quantity);
635
- } else if (channelName === 'ebay') {
636
- await (channelConfig.apiClient as any).updateInventory(sku, quantity);
637
- } else if (channelName === 'walmart') {
638
- await (channelConfig.apiClient as any).updateInventory(sku, quantity);
639
- }
640
-
641
- const duration = Date.now() - startTime;
642
- this.metrics.successfulUpdates++;
643
-
644
- this.logger.debug(`Updated ${channelName} inventory for ${sku}: ${quantity}`, {
645
- duration,
646
- });
647
- } catch (error: any) {
648
- this.metrics.failedUpdates++;
649
- this.metrics.errors.push({
650
- sku,
651
- channel: channelName,
652
- error: error.message,
653
- });
654
-
655
- if (error.response?.status === 429) {
656
- this.metrics.rateLimitHits++;
657
- }
658
-
659
- this.logger.warn(`Failed to update ${channelName} inventory for ${sku}`, {
660
- error: error.message,
661
- status: error.response?.status,
662
- });
663
- }
664
- })
665
- );
666
-
667
- updatePromises.push(...channelPromises);
668
- }
669
-
670
- await Promise.all(updatePromises);
671
- }
672
-
673
- private logMetrics(): void {
674
- if (!config.processing.metricsEnabled) return;
675
-
676
- const duration = this.metrics.endTime
677
- ? (this.metrics.endTime.getTime() - this.metrics.startTime.getTime()) / 1000
678
- : 0;
679
-
680
- this.logger.info('='.repeat(80));
681
- this.logger.info('SYNC METRICS', {
682
- duration: `${duration.toFixed(2)}s`,
683
- totalSKUs: this.metrics.totalSKUs,
684
- successfulUpdates: this.metrics.successfulUpdates,
685
- failedUpdates: this.metrics.failedUpdates,
686
- skippedUpdates: this.metrics.skippedUpdates,
687
- successRate: `${((this.metrics.successfulUpdates / (this.metrics.successfulUpdates + this.metrics.failedUpdates)) * 100).toFixed(2)}%`,
688
- rateLimitHits: this.metrics.rateLimitHits,
689
- errorCount: this.metrics.errors.length,
690
- });
691
-
692
- if (this.metrics.errors.length > 0) {
693
- this.logger.warn('Error summary (first 10):', {
694
- errors: this.metrics.errors.slice(0, 10),
695
- });
696
- }
697
-
698
- this.logger.info('='.repeat(80));
699
- }
700
- }
701
-
702
- // ============================================================================
703
- // MAIN ENTRY POINT
704
- // ============================================================================
705
-
706
- async function main() {
707
- const sync = new MultiChannelInventorySync();
708
-
709
- try {
710
- await sync.initialize();
711
- await sync.syncInventory();
712
-
713
- console.log('Multi-channel inventory sync completed successfully');
714
- process.exit(0);
715
- } catch (error: any) {
716
- console.error('Fatal error:', error);
717
- process.exit(1);
718
- }
719
- }
720
-
721
- // Run if executed directly
722
- if (require.main === module) {
723
- main();
724
- }
725
-
726
- export { MultiChannelInventorySync };
727
- ```
728
-
729
- ---
730
-
731
- ## Key Patterns Explained
732
-
733
- ### Pattern 1: GraphQL Auto-Pagination for Large Datasets
734
-
735
- **Challenge**: Efficiently fetch 10k-100k inventory positions without manual pagination logic
736
-
737
- **Solution**: Use SDK's built-in auto-pagination with progress callbacks
738
-
739
- ```javascript
740
- const result = await fluentClient.graphql({
741
- query,
742
- variables: { retailerId, first: 200 },
743
- pagination: {
744
- maxRecords: 100000,
745
- maxPages: 500,
746
- },
747
- });
748
- ```
749
-
750
- **Why This Works**:
751
-
752
- - **Automatic**: No manual cursor tracking needed
753
- - **Safe**: Built-in protections against infinite loops
754
- - **Efficient**: Streams data as it's received
755
- - **Observable**: Progress callbacks for monitoring
756
-
757
- ### Pattern 2: ATP Aggregation with Location Rollup
758
-
759
- **Challenge**: Calculate total Available-to-Promise across multiple warehouses/stores per SKU
760
-
761
- **Solution**: Map-based aggregation with location tracking
762
-
763
- ```javascript
764
- function aggregateATP(inventoryPositions) {
765
- const atpMap = new Map();
766
- for (const position of inventoryPositions) {
767
- const sku = position.productRef;
768
- const availableQty = Math.max(0, position.availableQty || 0);
769
-
770
- if (!atpMap.has(sku)) {
771
- atpMap.set(sku, {
772
- sku,
773
- totalATP: 0,
774
- locations: [],
775
- lastUpdated: position.updatedOn,
776
- });
777
- }
778
-
779
- const aggregated = atpMap.get(sku);
780
- aggregated.totalATP += availableQty;
781
- aggregated.locations.push({
782
- locationRef: position.locationRef,
783
- availableQty: availableQty,
784
- });
785
- }
786
- return atpMap;
787
- }
788
- ```
789
-
790
- **Why This Works**:
791
-
792
- - **O(n) complexity**: Single pass through inventory
793
- - **Location visibility**: Track which locations contribute to total
794
- - **Negative protection**: `Math.max(0, ...)` prevents negative ATP
795
- - **Timestamp tracking**: Know when inventory was last updated
796
-
797
- ### Pattern 3: Marketplace-Specific Buffer Stock
798
-
799
- **Challenge**: Different marketplaces need different safety buffers to prevent overselling
800
-
801
- **Solution**: Configurable buffer per marketplace
802
-
803
- ```javascript
804
- // Configuration
805
- const buffers = {
806
- amazon: 5, // Lower buffer (fast fulfillment)
807
- ebay: 3, // Moderate buffer
808
- walmart: 10, // Higher buffer (longer fulfillment)
809
- };
810
-
811
- // Application
812
- function applyBufferStock(totalATP, bufferStock) {
813
- return Math.max(0, totalATP - bufferStock);
814
- }
815
-
816
- // Example: SKU with 50 ATP across all locations
817
- const amazonQty = applyBufferStock(50, 5); // 45 available on Amazon
818
- const ebayQty = applyBufferStock(50, 3); // 47 available on eBay
819
- const walmartQty = applyBufferStock(50, 10); // 40 available on Walmart
820
- ```
821
-
822
- **Why This Works**:
823
-
824
- - **Oversell prevention**: Accounts for sync delays and processing time
825
- - **Marketplace flexibility**: Different risk profiles per marketplace
826
- - **Safety floor**: `Math.max(0, ...)` ensures quantity never goes negative
827
- - **Configurable**: Easy to adjust per marketplace requirements
828
-
829
- ### Pattern 4: Parallel Marketplace Updates with Rate Limiting
830
-
831
- **Challenge**: Update multiple marketplaces efficiently without exceeding API rate limits
832
-
833
- **Solution**: Parallel execution with per-marketplace rate limiters
834
-
835
- ```javascript
836
- import pLimit from 'p-limit';
837
-
838
- // Each marketplace has its own rate limiter
839
- class AmazonMarketplace {
840
- constructor(config) {
841
- this.limiter = pLimit(config.rateLimit); // 10 req/sec
842
- }
843
-
844
- async updateInventory(sku, quantity) {
845
- // Rate-limited execution
846
- return this.limiter(() => this.makeApiCall(sku, quantity));
847
- }
848
- }
849
-
850
- // Parallel sync across all marketplaces
851
- const syncResults = await Promise.all(
852
- marketplaces.map(marketplace => marketplace.syncInventory(atpMap))
853
- );
854
- ```
855
-
856
- **Why This Works**:
857
-
858
- - **Parallel execution**: All marketplaces sync simultaneously
859
- - **Independent rate limits**: Each marketplace respects its own limits
860
- - **Error isolation**: Failure in one marketplace doesn't affect others
861
- - **Concurrency control**: p-limit prevents overwhelming APIs
862
-
863
- ### Pattern 5: Exponential Backoff Retry Strategy
864
-
865
- **Challenge**: Handle transient API failures (429 rate limits, 500 server errors)
866
-
867
- **Solution**: p-retry with exponential backoff
868
-
869
- ```javascript
870
- import pRetry from 'p-retry';
871
-
872
- async updateInventory(sku, quantity) {
873
- return pRetry(
874
- async () => {
875
- // Attempt API call
876
- const response = await axios.put(endpoint, payload);
877
-
878
- // Check for retryable errors
879
- if (response.status === 429) {
880
- throw new Error('Rate limit exceeded'); // Will retry
881
- }
882
-
883
- return response.data;
884
- },
885
- {
886
- retries: 3,
887
- factor: 2, // Exponential backoff factor
888
- minTimeout: 1000, // 1s, 2s, 4s delays
889
- onFailedAttempt: error => {
890
- logger.warn(`Retry attempt ${error.attemptNumber}`, {
891
- retriesLeft: error.retriesLeft,
892
- });
893
- },
894
- }
895
- );
896
- }
897
- ```
898
-
899
- **Why This Works**:
900
-
901
- - **Transient failure recovery**: Handles temporary API issues
902
- - **Exponential backoff**: Reduces load on overloaded APIs
903
- - **Configurable retries**: 3 attempts is reasonable for most cases
904
- - **Observable**: Logs each retry attempt for debugging
905
-
906
- ### Pattern 6: SLA Tracking and Compliance
907
-
908
- **Challenge**: Ensure sync completes within 15-minute SLA requirement
909
-
910
- **Solution**: Duration tracking with SLA compliance check
911
-
912
- ```javascript
913
- function checkSLA(durationMs) {
914
- const durationMinutes = durationMs / 60000;
915
- const slaThreshold = 15; // 15-minute requirement
916
- const slaMet = durationMinutes <= slaThreshold;
917
-
918
- if (!slaMet) {
919
- logger.warn('SLA BREACH: Sync exceeded threshold', {
920
- durationMinutes: durationMinutes.toFixed(2),
921
- threshold: slaThreshold,
922
- });
923
- metrics.increment('sla_breaches');
924
- // Alert via PagerDuty, Slack, etc.
925
- }
926
-
927
- return slaMet;
928
- }
929
- ```
930
-
931
- **Why This Works**:
932
-
933
- - **Clear threshold**: 15 minutes is measurable and actionable
934
- - **Automated detection**: No manual checking needed
935
- - **Alerting hook**: Can trigger notifications on breach
936
- - **Metrics tracking**: Historical SLA compliance data
937
-
938
- ### Pattern 7: Dry-Run Mode for Safe Testing
939
-
940
- **Challenge**: Test sync logic without actually updating marketplaces
941
-
942
- **Solution**: Dry-run flag that short-circuits API calls
943
-
944
- ```javascript
945
- async updateInventory(sku, quantity, dryRun = false) {
946
- if (dryRun) {
947
- this.logger.info(`[DRY RUN] Would update inventory`, { sku, quantity });
948
- return { success: true, sku, quantity, dryRun: true };
949
- }
950
-
951
- // Real API call
952
- return this.makeApiCall(sku, quantity);
953
- }
954
-
955
- // Usage
956
- npm run sync:dry-run
957
- ```
958
-
959
- **Why This Works**:
960
-
961
- - **Safe testing**: Validate logic without side effects
962
- - **End-to-end flow**: Tests everything except final API call
963
- - **Easy toggle**: Environment variable or CLI flag
964
- - **Visible logging**: Clear indication of dry-run mode
965
-
966
- ---
967
-
968
- ## Testing
969
-
970
- ### Dry-Run Test
971
-
972
- ```bash
973
- # Test sync without updating marketplaces
974
- DRY_RUN=true npm run sync:once
975
-
976
- # Expected output:
977
- # [DRY RUN] Would update Amazon inventory { sku: 'PROD-001', quantity: 45 }
978
- # [DRY RUN] Would update eBay inventory { sku: 'PROD-001', quantity: 47 }
979
- # [DRY RUN] Would update Walmart inventory { sku: 'PROD-001', quantity: 40 }
980
- ```
981
-
982
- ### Single Sync Execution
983
-
984
- ```bash
985
- # Run once and exit
986
- npm run sync:once
987
-
988
- # Check logs
989
- cat logs/inventory-sync.log | grep "COMPLETE"
990
- ```
991
-
992
- ### Continuous Sync Mode
993
-
994
- ```bash
995
- # Run continuously (every 15 minutes)
996
- npm run sync:continuous
997
-
998
- # Check next sync time in logs
999
- ```
1000
-
1001
- ---
1002
-
1003
- ## Deployment Options
1004
-
1005
- ### Option 1: Docker Container
1006
-
1007
- Create `Dockerfile`:
1008
-
1009
- ```dockerfile
1010
- FROM node:18-alpine
1011
-
1012
- WORKDIR /app
1013
-
1014
- # Copy package files
1015
- COPY package*.json ./
1016
-
1017
- # Install dependencies
1018
- RUN npm ci --only=production
1019
-
1020
- # Copy application code
1021
- COPY src ./src
1022
-
1023
- # Create state directory
1024
- RUN mkdir -p /app/state
1025
-
1026
- # Run continuous sync
1027
- CMD ["node", "src/index.js"]
1028
- ```
1029
-
1030
- Build and run:
1031
-
1032
- ```bash
1033
- # Build image
1034
- docker build -t multi-channel-sync .
1035
-
1036
- # Run container
1037
- docker run -d \
1038
- --name inventory-sync \
1039
- --env-file .env \
1040
- --restart unless-stopped \
1041
- --volume ./state:/app/state \
1042
- multi-channel-sync
1043
- ```
1044
-
1045
- ### Option 2: AWS ECS Task
1046
-
1047
- Create `ecs-task-definition.json`:
1048
-
1049
- ```json
1050
- {
1051
- "family": "multi-channel-inventory-sync",
1052
- "networkMode": "awsvpc",
1053
- "requiresCompatibilities": ["FARGATE"],
1054
- "cpu": "1024",
1055
- "memory": "2048",
1056
- "containerDefinitions": [
1057
- {
1058
- "name": "inventory-sync",
1059
- "image": "your-registry/multi-channel-sync:latest",
1060
- "essential": true,
1061
- "environment": [
1062
- { "name": "LOG_LEVEL", "value": "info" },
1063
- { "name": "SYNC_INTERVAL_MINUTES", "value": "15" }
1064
- ],
1065
- "secrets": [
1066
- {
1067
- "name": "FLUENT_CLIENT_ID",
1068
- "valueFrom": "arn:aws:secretsmanager:us-east-1:123:secret:fluent-client-id"
1069
- }
1070
- ],
1071
- "logConfiguration": {
1072
- "logDriver": "awslogs",
1073
- "options": {
1074
- "awslogs-group": "/ecs/inventory-sync",
1075
- "awslogs-region": "us-east-1",
1076
- "awslogs-stream-prefix": "ecs"
1077
- }
1078
- }
1079
- }
1080
- ]
1081
- }
1082
- ```
1083
-
1084
- Deploy:
1085
-
1086
- ```bash
1087
- aws ecs register-task-definition --cli-input-json file://ecs-task-definition.json
1088
- aws ecs create-service \
1089
- --cluster production \
1090
- --service-name inventory-sync \
1091
- --task-definition multi-channel-inventory-sync \
1092
- --desired-count 1 \
1093
- --launch-type FARGATE
1094
- ```
1095
-
1096
- ---
1097
-
1098
- ## Common Issues & Solutions
1099
-
1100
- ### Issue 1: SLA Breach (Sync Takes >15 Minutes)
1101
-
1102
- **Symptoms**:
1103
-
1104
- - Log shows "SLA BREACH" warning
1105
- - Sync duration exceeds 15 minutes
1106
-
1107
- **Solutions**:
1108
-
1109
- 1. **Reduce page size** (faster initial response):
1110
-
1111
- ```javascript
1112
- variables: {
1113
- first: 100;
1114
- } // Instead of 200
1115
- ```
1116
-
1117
- 2. **Increase parallelism**:
1118
-
1119
- ```javascript
1120
- const limiter = pLimit(20); // Increase from 10
1121
- ```
1122
-
1123
- 3. **Optimize marketplace rate limits** (if APIs allow):
1124
-
1125
- ```bash
1126
- AMAZON_RATE_LIMIT=20 # Increase from 10
1127
- ```
1128
-
1129
- 4. **Split sync by marketplace** (run separately):
1130
-
1131
- ```bash
1132
- AMAZON_ENABLED=true EBAY_ENABLED=false WALMART_ENABLED=false npm run sync:once
1133
- ```
1134
-
1135
- ---
1136
-
1137
- ## Related Guides
1138
-
1139
- - **GraphQL Query Export**: [`./graphql-query-export.md`](./graphql-query-export.md) - GraphQL pagination patterns
1140
- - **Multi-Source Aggregation**: `./04-multi-source-aggregation.md` - Data aggregation strategies
1141
- - **Error Handling Patterns**: `../../03-PATTERN-GUIDES/error-handling/readme.md` - Retry and error handling
1142
- - **Universal Mapping Guide**: `../../02-CORE-GUIDES/mapping/readme.md` - Field transformations
1143
- - **SDK API Reference**: `../../readme.md` - Core SDK documentation
1144
-
1145
- ---
1146
-
1147
- ## Production Checklist
1148
-
1149
- Before deploying to production:
1150
-
1151
- - [ ] All marketplace credentials secured (AWS Secrets Manager, Vault)
1152
- - [ ] Rate limits configured per marketplace API documentation
1153
- - [ ] Buffer stock values tested and approved by business
1154
- - [ ] SLA threshold aligned with business requirements
1155
- - [ ] Monitoring dashboards created (sync duration, SLA compliance, error rates)
1156
- - [ ] Alerting configured (PagerDuty, Slack, email)
1157
- - [ ] Dry-run testing completed with production data
1158
- - [ ] Load testing with 100k+ SKUs
1159
- - [ ] State management enabled to prevent duplicate processing
1160
- - [ ] Logging configured (CloudWatch, Datadog, Splunk)
1161
- - [ ] Error tracking integrated (Sentry, Rollbar)
1162
- - [ ] Documentation updated with runbooks
1163
- - [ ] On-call team trained on troubleshooting
1164
- - [ ] Disaster recovery plan documented
1165
- - [ ] Metrics baseline established (average sync duration, success rate)
1166
-
1167
- ---
1168
-
1169
- **Next Steps**:
1170
-
1171
- 1. Customize buffer stock values per marketplace and product category
1172
- 2. Implement incremental sync (only process changed inventory)
1173
- 3. Add webhook integration for real-time inventory updates
1174
- 4. Set up monitoring dashboards (Grafana, Datadog)
1175
- 5. Integrate with incident management (PagerDuty)
1176
- 6. Add marketplace-specific SKU mapping (Fluent SKU → Marketplace SKU)
1177
- 7. Implement A/B testing for buffer stock optimization
1178
-
1179
- **Support**:
1180
-
1181
- - SDK Issues: https://github.com/fluentcommerce/fc-connect-sdk/issues
1182
- - Fluent Commerce API: https://docs.fluentcommerce.com
1183
- - Amazon SP-API: https://developer-docs.amazon.com/sp-api/
1184
- - eBay Trading API: https://developer.ebay.com/devzone/xml/docs/reference/ebay/
1185
- - Walmart Seller API: https://developer.walmart.com/
1
+ # Standalone: Multi-Channel Inventory Sync (Real-Time ATP to Marketplaces)
2
+
3
+ **FC Connect SDK Use Case Guide**
4
+
5
+ > **SDK**: [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)
6
+ > **Version**: Use latest - `npm install @fluentcommerce/fc-connect-sdk@latest`
7
+
8
+ **Context**: Node.js script that aggregates Available-to-Promise (ATP) inventory from Fluent Commerce and pushes real-time updates to multiple marketplaces (Amazon, eBay, Walmart)
9
+
10
+ **Complexity**: High
11
+
12
+ **Runtime**: Node.js >=18
13
+
14
+ **Estimated Lines**: ~950 lines
15
+
16
+ **Volume**: Large (10k-100k SKUs, multiple marketplaces)
17
+
18
+ **Latency**: Near real-time (every 5-15 min)
19
+
20
+ **Pattern**: GraphQL pagination → external marketplace APIs
21
+
22
+ ## What You'll Build
23
+
24
+ - OAuth2-authenticated Fluent Commerce client
25
+ - GraphQL query with auto-pagination for inventory positions
26
+ - ATP (Available-to-Promise) aggregation across multiple locations
27
+ - Marketplace-specific buffer stock calculations
28
+ - Parallel marketplace updates with rate limiting:
29
+ - Amazon MWS/SP-API integration
30
+ - eBay Trading API integration
31
+ - Walmart Seller API integration
32
+ - Per-marketplace error handling and retry logic
33
+ - SLA tracking (15-minute sync requirement)
34
+ - Comprehensive metrics and logging
35
+ - Dry-run mode for testing
36
+ - State management to prevent duplicate updates
37
+
38
+ ## SDK Methods Used
39
+
40
+ - `createClient({ config: { baseUrl, clientId, clientSecret, retailerId } })` - OAuth2 client
41
+ - `client.graphql({ query, variables, pagination })` - Query with auto-pagination
42
+ - `UniversalMapper(mappingConfig)` - Transform Fluent data to marketplace formats
43
+ - `createConsoleLogger()` - Simple console logger
44
+ - `toStructuredLogger(logger, context)` - Add context to logs
45
+ - `generateCorrelationId()` - Generate unique correlation IDs
46
+ - State tracking for incremental updates
47
+
48
+ ---
49
+
50
+ ## Complete Working Implementation
51
+
52
+ ### 1. Project Setup
53
+
54
+ ```bash
55
+ # Create project directory
56
+ mkdir multi-channel-inventory-sync
57
+ cd multi-channel-inventory-sync
58
+
59
+ # Initialize Node.js project
60
+ npm init -y
61
+
62
+ # Install dependencies
63
+ npm install @fluentcommerce/fc-connect-sdk dotenv axios p-limit p-retry
64
+ ```
65
+
66
+ ### 2. Environment Configuration
67
+
68
+ Create `.env` file:
69
+
70
+ ```bash
71
+ # Fluent Commerce OAuth2
72
+ FLUENT_BASE_URL=https://api.fluentcommerce.com
73
+ FLUENT_CLIENT_ID=your-oauth2-client-id
74
+ FLUENT_CLIENT_SECRET=your-oauth2-client-secret
75
+ FLUENT_RETAILER_ID=your-retailer-id
76
+
77
+ # Sync Configuration
78
+ SYNC_INTERVAL_MINUTES=15
79
+ SLA_THRESHOLD_MINUTES=15
80
+ MAX_RECORDS_PER_SYNC=100000
81
+ DRY_RUN=false
82
+
83
+ # Amazon SP-API Credentials
84
+ AMAZON_ENABLED=true
85
+ AMAZON_MARKETPLACE_ID=ATVPDKIKX0DER
86
+ AMAZON_SELLER_ID=your-amazon-seller-id
87
+ AMAZON_REFRESH_TOKEN=your-amazon-refresh-token
88
+ AMAZON_CLIENT_ID=amzn1.application-oa2-client.xxxxx
89
+ AMAZON_CLIENT_SECRET=your-amazon-client-secret
90
+ AMAZON_AWS_ACCESS_KEY_ID=your-aws-access-key
91
+ AMAZON_AWS_SECRET_ACCESS_KEY=your-aws-secret-key
92
+ AMAZON_REGION=us-east-1
93
+ AMAZON_ROLE_ARN=arn:aws:iam::123456789:role/SellingPartnerAPI
94
+ AMAZON_BUFFER_STOCK=5
95
+ AMAZON_RATE_LIMIT=10
96
+
97
+ # eBay Trading API Credentials
98
+ EBAY_ENABLED=true
99
+ EBAY_APP_ID=your-ebay-app-id
100
+ EBAY_DEV_ID=your-ebay-dev-id
101
+ EBAY_CERT_ID=your-ebay-cert-id
102
+ EBAY_AUTH_TOKEN=your-ebay-auth-token
103
+ EBAY_SITE_ID=0
104
+ EBAY_SANDBOX=false
105
+ EBAY_BUFFER_STOCK=3
106
+ EBAY_RATE_LIMIT=5
107
+
108
+ # Walmart Seller API Credentials
109
+ WALMART_ENABLED=true
110
+ WALMART_CLIENT_ID=your-walmart-client-id
111
+ WALMART_CLIENT_SECRET=your-walmart-client-secret
112
+ WALMART_CHANNEL_TYPE=0a7d6c3e-e9a0-4a0c-8d6a-f6c6f1e7a5c7
113
+ WALMART_BUFFER_STOCK=10
114
+ WALMART_RATE_LIMIT=20
115
+
116
+ # Logging
117
+ LOG_LEVEL=info
118
+ METRICS_ENABLED=true
119
+ ```
120
+
121
+ ### 3. Package Configuration
122
+
123
+ Create `package.json`:
124
+
125
+ ```json
126
+ {
127
+ "name": "multi-channel-inventory-sync",
128
+ "version": "1.0.0",
129
+ "type": "module",
130
+ "description": "Real-time ATP inventory sync from Fluent Commerce to multiple marketplaces",
131
+ "main": "src/index.js",
132
+ "scripts": {
133
+ "start": "node src/index.js",
134
+ "sync:once": "node src/index.js --once",
135
+ "sync:continuous": "node src/index.js",
136
+ "sync:dry-run": "DRY_RUN=true node src/index.js --once",
137
+ "test": "node --test tests/**/*.test.js"
138
+ },
139
+ "dependencies": {
140
+ "@fluentcommerce/fc-connect-sdk": "^0.1.39",
141
+ "axios": "^1.6.0",
142
+ "dotenv": "^16.0.0",
143
+ "p-limit": "^5.0.0",
144
+ "p-retry": "^6.0.0"
145
+ },
146
+ "devDependencies": {
147
+ "@types/node": "^20.0.0"
148
+ },
149
+ "engines": {
150
+ "node": ">=18.0.0"
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### 4. TypeScript Configuration (tsconfig.json)
156
+
157
+ ```json
158
+ {
159
+ "compilerOptions": {
160
+ "module": "ES2022",
161
+ "target": "ES2024",
162
+ "moduleResolution": "node"
163
+ }
164
+ }
165
+ ```
166
+
167
+ ### 5. Main Script Implementation (src/multi-channel-sync.ts)
168
+
169
+ > **⚠️ RUNTIME COMPATIBILITY NOTE:**
170
+ > This template includes `import { Buffer } from 'node:buffer';` for Deno/Versori compatibility.
171
+ > While Buffer is globally available in Node.js and this import is optional for Node.js-only deployments,
172
+ > including it ensures the code works across all runtimes (Node.js, Deno, Versori) without modification.
173
+
174
+ ```typescript
175
+ import 'dotenv/config';
176
+ import { Buffer } from 'node:buffer'; // Required for Deno/Versori runtime compatibility
177
+
178
+ // FC Connect SDK+
179
+ // Install: npm install @fluentcommerce/fc-connect-sdk@latest
180
+ // Docs: https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk
181
+ // GitHub: https://github.com/fluentcommerce/fc-connect-sdk
182
+
183
+ import {
184
+ createClient,
185
+ type FluentClient,
186
+ type StructuredLogger,
187
+ createConsoleLogger,
188
+ toStructuredLogger
189
+ } from '@fluentcommerce/fc-connect-sdk';
190
+
191
+ import axios, { AxiosInstance } from 'axios';
192
+ import pLimit from 'p-limit';
193
+
194
+ // ============================================================================
195
+ // TYPES & INTERFACES
196
+ // ============================================================================
197
+
198
+ interface InventoryPosition {
199
+ productRef: string;
200
+ locationRef: string;
201
+ quantity: number;
202
+ onHand: number;
203
+ available: number;
204
+ reserved: number;
205
+ }
206
+
207
+ interface ChannelConfig {
208
+ enabled: boolean;
209
+ apiClient: AxiosInstance;
210
+ bufferStock: number;
211
+ rateLimit: number;
212
+ }
213
+
214
+ interface SyncMetrics {
215
+ startTime: Date;
216
+ endTime?: Date;
217
+ totalSKUs: number;
218
+ successfulUpdates: number;
219
+ failedUpdates: number;
220
+ skippedUpdates: number;
221
+ errors: Array<{ sku: string; channel: string; error: string }>;
222
+ rateLimitHits: number;
223
+ avgResponseTime: number;
224
+ }
225
+
226
+ // ============================================================================
227
+ // CONFIGURATION
228
+ // ============================================================================
229
+
230
+ const config = {
231
+ fluent: {
232
+ baseUrl: process.env.FLUENT_BASE_URL!,
233
+ clientId: process.env.FLUENT_CLIENT_ID!,
234
+ clientSecret: process.env.FLUENT_CLIENT_SECRET!,
235
+ retailerId: process.env.FLUENT_RETAILER_ID!,
236
+ },
237
+ amazon: {
238
+ enabled: process.env.AMAZON_ENABLED === 'true',
239
+ clientId: process.env.AMAZON_CLIENT_ID!,
240
+ clientSecret: process.env.AMAZON_CLIENT_SECRET!,
241
+ refreshToken: process.env.AMAZON_REFRESH_TOKEN!,
242
+ marketplaceId: process.env.AMAZON_MARKETPLACE_ID!,
243
+ sellerId: process.env.AMAZON_SELLER_ID!,
244
+ bufferStock: parseInt(process.env.AMAZON_BUFFER_STOCK || '5'),
245
+ rateLimit: parseInt(process.env.AMAZON_RATE_LIMIT || '10'),
246
+ },
247
+ ebay: {
248
+ enabled: process.env.EBAY_ENABLED === 'true',
249
+ appId: process.env.EBAY_APP_ID!,
250
+ certId: process.env.EBAY_CERT_ID!,
251
+ authToken: process.env.EBAY_AUTH_TOKEN!,
252
+ siteId: process.env.EBAY_SITE_ID || '0',
253
+ bufferStock: parseInt(process.env.EBAY_BUFFER_STOCK || '3'),
254
+ rateLimit: parseInt(process.env.EBAY_RATE_LIMIT || '5'),
255
+ },
256
+ walmart: {
257
+ enabled: process.env.WALMART_ENABLED === 'true',
258
+ clientId: process.env.WALMART_CLIENT_ID!,
259
+ clientSecret: process.env.WALMART_CLIENT_SECRET!,
260
+ channelType: process.env.WALMART_CHANNEL_TYPE!,
261
+ bufferStock: parseInt(process.env.WALMART_BUFFER_STOCK || '10'),
262
+ rateLimit: parseInt(process.env.WALMART_RATE_LIMIT || '20'),
263
+ },
264
+ processing: {
265
+ concurrency: parseInt(process.env.CONCURRENCY || '10'),
266
+ metricsEnabled: process.env.METRICS_ENABLED === 'true',
267
+ },
268
+ };
269
+
270
+ // ============================================================================
271
+ // MARKETPLACE API CLIENTS
272
+ // ============================================================================
273
+
274
+ class AmazonAPIClient {
275
+ private client: AxiosInstance;
276
+ private accessToken?: string;
277
+ private tokenExpiry?: Date;
278
+
279
+ constructor(
280
+ private config: typeof config.amazon,
281
+ private logger: StructuredLogger
282
+ ) {
283
+ this.client = axios.create({
284
+ baseURL: 'https://sellingpartnerapi-na.amazon.com',
285
+ timeout: 30000,
286
+ });
287
+ }
288
+
289
+ async ensureAuthenticated(): Promise<void> {
290
+ if (this.accessToken && this.tokenExpiry && new Date() < this.tokenExpiry) {
291
+ return; // Token still valid
292
+ }
293
+
294
+ this.logger.info('Refreshing Amazon SP-API access token');
295
+
296
+ const response = await axios.post('https://api.amazon.com/auth/o2/token', {
297
+ grant_type: 'refresh_token',
298
+ refresh_token: this.config.refreshToken,
299
+ client_id: this.config.clientId,
300
+ client_secret: this.config.clientSecret,
301
+ });
302
+
303
+ this.accessToken = response.data.access_token;
304
+ this.tokenExpiry = new Date(Date.now() + response.data.expires_in * 1000);
305
+
306
+ this.logger.info('Amazon SP-API token refreshed successfully');
307
+ }
308
+
309
+ async updateInventory(sku: string, quantity: number): Promise<void> {
310
+ await this.ensureAuthenticated();
311
+
312
+ const payload = {
313
+ marketplaceId: this.config.marketplaceId,
314
+ sellerId: this.config.sellerId,
315
+ feeds: [
316
+ {
317
+ feedType: 'POST_INVENTORY_AVAILABILITY_DATA',
318
+ feedOptions: {
319
+ encoding: 'UTF-8',
320
+ },
321
+ feedContent: this.buildInventoryFeedXml(sku, quantity),
322
+ },
323
+ ],
324
+ };
325
+
326
+ await this.client.post('/feeds/2021-06-30/feeds', payload, {
327
+ headers: {
328
+ 'x-amz-access-token': this.accessToken,
329
+ 'Content-Type': 'application/json',
330
+ },
331
+ });
332
+ }
333
+
334
+ private buildInventoryFeedXml(sku: string, quantity: number): string {
335
+ return `<?xml version="1.0" encoding="UTF-8"?>
336
+ <AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
337
+ <Header>
338
+ <DocumentVersion>1.01</DocumentVersion>
339
+ <MerchantIdentifier>${this.config.sellerId}</MerchantIdentifier>
340
+ </Header>
341
+ <MessageType>Inventory</MessageType>
342
+ <Message>
343
+ <MessageID>1</MessageID>
344
+ <OperationType>Update</OperationType>
345
+ <Inventory>
346
+ <SKU>${sku}</SKU>
347
+ <Quantity>${quantity}</Quantity>
348
+ <FulfillmentLatency>2</FulfillmentLatency>
349
+ </Inventory>
350
+ </Message>
351
+ </AmazonEnvelope>`;
352
+ }
353
+ }
354
+
355
+ class eBayAPIClient {
356
+ private client: AxiosInstance;
357
+
358
+ constructor(
359
+ private config: typeof config.ebay,
360
+ private logger: StructuredLogger
361
+ ) {
362
+ this.client = axios.create({
363
+ baseURL: 'https://api.ebay.com/ws/api.dll',
364
+ timeout: 30000,
365
+ });
366
+ }
367
+
368
+ async updateInventory(sku: string, quantity: number): Promise<void> {
369
+ const xmlRequest = `<?xml version="1.0" encoding="utf-8"?>
370
+ <ReviseInventoryStatusRequest xmlns="urn:ebay:apis:eBLBaseComponents">
371
+ <RequesterCredentials>
372
+ <eBayAuthToken>${this.config.authToken}</eBayAuthToken>
373
+ </RequesterCredentials>
374
+ <InventoryStatus>
375
+ <SKU>${sku}</SKU>
376
+ <Quantity>${quantity}</Quantity>
377
+ </InventoryStatus>
378
+ </ReviseInventoryStatusRequest>`;
379
+
380
+ await this.client.post('', xmlRequest, {
381
+ headers: {
382
+ 'X-EBAY-API-SITEID': this.config.siteId,
383
+ 'X-EBAY-API-COMPATIBILITY-LEVEL': '967',
384
+ 'X-EBAY-API-CALL-NAME': 'ReviseInventoryStatus',
385
+ 'Content-Type': 'text/xml',
386
+ },
387
+ });
388
+ }
389
+ }
390
+
391
+ class WalmartAPIClient {
392
+ private client: AxiosInstance;
393
+ private accessToken?: string;
394
+ private tokenExpiry?: Date;
395
+
396
+ constructor(
397
+ private config: typeof config.walmart,
398
+ private logger: StructuredLogger
399
+ ) {
400
+ this.client = axios.create({
401
+ baseURL: 'https://marketplace.walmartapis.com/v3',
402
+ timeout: 30000,
403
+ });
404
+ }
405
+
406
+ async ensureAuthenticated(): Promise<void> {
407
+ if (this.accessToken && this.tokenExpiry && new Date() < this.tokenExpiry) {
408
+ return;
409
+ }
410
+
411
+ this.logger.info('Refreshing Walmart Marketplace access token');
412
+
413
+ const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString(
414
+ 'base64'
415
+ );
416
+
417
+ const response = await axios.post(
418
+ 'https://marketplace.walmartapis.com/v3/token',
419
+ 'grant_type=client_credentials',
420
+ {
421
+ headers: {
422
+ Authorization: `Basic ${credentials}`,
423
+ 'Content-Type': 'application/x-www-form-urlencoded',
424
+ 'WM_SVC.NAME': 'Walmart Marketplace',
425
+ 'WM_QOS.CORRELATION_ID': Date.now().toString(),
426
+ },
427
+ }
428
+ );
429
+
430
+ this.accessToken = response.data.access_token;
431
+ this.tokenExpiry = new Date(Date.now() + response.data.expires_in * 1000);
432
+
433
+ this.logger.info('Walmart access token refreshed successfully');
434
+ }
435
+
436
+ async updateInventory(sku: string, quantity: number): Promise<void> {
437
+ await this.ensureAuthenticated();
438
+
439
+ const payload = {
440
+ sku,
441
+ quantity: {
442
+ unit: 'EACH',
443
+ amount: quantity,
444
+ },
445
+ };
446
+
447
+ await this.client.put(`/inventory?sku=${sku}`, payload, {
448
+ headers: {
449
+ 'WM_SEC.ACCESS_TOKEN': this.accessToken,
450
+ 'WM_SVC.NAME': 'Walmart Marketplace',
451
+ 'WM_QOS.CORRELATION_ID': Date.now().toString(),
452
+ 'Content-Type': 'application/json',
453
+ },
454
+ });
455
+ }
456
+ }
457
+
458
+ // ============================================================================
459
+ // MULTI-CHANNEL INVENTORY SYNCHRONIZER
460
+ // ============================================================================
461
+
462
+ class MultiChannelInventorySync {
463
+ private fluentClient: FluentClient;
464
+ private logger: StructuredLogger;
465
+ private channels: Map<string, ChannelConfig> = new Map();
466
+ private metrics: SyncMetrics;
467
+
468
+ constructor() {
469
+ this.logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
470
+
471
+ this.metrics = {
472
+ startTime: new Date(),
473
+ totalSKUs: 0,
474
+ successfulUpdates: 0,
475
+ failedUpdates: 0,
476
+ skippedUpdates: 0,
477
+ errors: [],
478
+ rateLimitHits: 0,
479
+ avgResponseTime: 0,
480
+ };
481
+ }
482
+
483
+ async initialize(): Promise<void> {
484
+ this.logger.info('Initializing Multi-Channel Inventory Sync');
485
+
486
+ // Initialize Fluent Commerce client
487
+ this.fluentClient = await createClient({ config: config.fluent });
488
+
489
+ // Initialize marketplace API clients
490
+ if (config.amazon.enabled) {
491
+ const amazonClient = new AmazonAPIClient(config.amazon, this.logger);
492
+ this.channels.set('amazon', {
493
+ enabled: true,
494
+ apiClient: amazonClient as any,
495
+ bufferStock: config.amazon.bufferStock,
496
+ rateLimit: config.amazon.rateLimit,
497
+ });
498
+ this.logger.info('Amazon SP-API client initialized');
499
+ }
500
+
501
+ if (config.ebay.enabled) {
502
+ const ebayClient = new eBayAPIClient(config.ebay, this.logger);
503
+ this.channels.set('ebay', {
504
+ enabled: true,
505
+ apiClient: ebayClient as any,
506
+ bufferStock: config.ebay.bufferStock,
507
+ rateLimit: config.ebay.rateLimit,
508
+ });
509
+ this.logger.info('eBay Trading API client initialized');
510
+ }
511
+
512
+ if (config.walmart.enabled) {
513
+ const walmartClient = new WalmartAPIClient(config.walmart, this.logger);
514
+ this.channels.set('walmart', {
515
+ enabled: true,
516
+ apiClient: walmartClient as any,
517
+ bufferStock: config.walmart.bufferStock,
518
+ rateLimit: config.walmart.rateLimit,
519
+ });
520
+ this.logger.info('Walmart Marketplace API client initialized');
521
+ }
522
+
523
+ this.logger.info(`Initialized ${this.channels.size} marketplace channels`);
524
+ }
525
+
526
+ async syncInventory(): Promise<void> {
527
+ this.logger.info('Starting multi-channel inventory sync');
528
+ this.metrics.startTime = new Date();
529
+
530
+ try {
531
+ // Step 1: Fetch all ATP inventory from Fluent Commerce
532
+ const inventory = await this.fetchFluentInventory();
533
+ this.metrics.totalSKUs = inventory.length;
534
+
535
+ this.logger.info(`Fetched ${inventory.length} inventory positions from Fluent`);
536
+
537
+ // Step 2: Calculate ATP for each channel with buffer stock
538
+ const channelInventory = this.calculateChannelInventory(inventory);
539
+
540
+ // Step 3: Update each marketplace in parallel with rate limiting
541
+ await this.updateMarketplaces(channelInventory);
542
+
543
+ this.metrics.endTime = new Date();
544
+ this.logMetrics();
545
+
546
+ this.logger.info('Multi-channel inventory sync completed successfully');
547
+ } catch (error: any) {
548
+ this.logger.error('Multi-channel inventory sync failed', error);
549
+ throw error;
550
+ }
551
+ }
552
+
553
+ private async fetchFluentInventory(): Promise<InventoryPosition[]> {
554
+ const query = `
555
+ query GetInventory($retailerId: ID!, $first: Int!, $after: String) {
556
+ inventoryQuantities(
557
+ first: $first
558
+ after: $after
559
+ retailerId: $retailerId
560
+ type: "AVAILABLE"
561
+ ) {
562
+ edges {
563
+ node {
564
+ productRef
565
+ locationRef
566
+ quantity
567
+ onHand
568
+ available
569
+ reserved
570
+ }
571
+ cursor
572
+ }
573
+ pageInfo {
574
+ hasNextPage
575
+ }
576
+ }
577
+ }
578
+ `;
579
+
580
+ const result = await this.fluentClient.graphql({
581
+ query,
582
+ variables: {
583
+ retailerId: config.fluent.retailerId,
584
+ first: 250,
585
+ },
586
+ pagination: {
587
+ maxPages: 500,
588
+ },
589
+ });
590
+
591
+ if (result.errors) {
592
+ throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`);
593
+ }
594
+
595
+ const edges = (result.data as any).inventoryQuantities?.edges || [];
596
+ return edges.map((edge: any) => edge.node);
597
+ }
598
+
599
+ private calculateChannelInventory(
600
+ inventory: InventoryPosition[]
601
+ ): Map<string, Map<string, number>> {
602
+ const channelInventory = new Map<string, Map<string, number>>();
603
+
604
+ for (const [channelName, channelConfig] of this.channels) {
605
+ const skuQuantities = new Map<string, number>();
606
+
607
+ for (const position of inventory) {
608
+ const atpQuantity = position.available || 0;
609
+ const channelQuantity = Math.max(0, atpQuantity - channelConfig.bufferStock);
610
+ skuQuantities.set(position.productRef, channelQuantity);
611
+ }
612
+
613
+ channelInventory.set(channelName, skuQuantities);
614
+ }
615
+
616
+ return channelInventory;
617
+ }
618
+
619
+ private async updateMarketplaces(
620
+ channelInventory: Map<string, Map<string, number>>
621
+ ): Promise<void> {
622
+ const updatePromises: Promise<void>[] = [];
623
+
624
+ for (const [channelName, skuQuantities] of channelInventory) {
625
+ const channelConfig = this.channels.get(channelName)!;
626
+ const limit = pLimit(channelConfig.rateLimit);
627
+
628
+ const channelPromises = Array.from(skuQuantities.entries()).map(([sku, quantity]) =>
629
+ limit(async () => {
630
+ try {
631
+ const startTime = Date.now();
632
+
633
+ if (channelName === 'amazon') {
634
+ await (channelConfig.apiClient as any).updateInventory(sku, quantity);
635
+ } else if (channelName === 'ebay') {
636
+ await (channelConfig.apiClient as any).updateInventory(sku, quantity);
637
+ } else if (channelName === 'walmart') {
638
+ await (channelConfig.apiClient as any).updateInventory(sku, quantity);
639
+ }
640
+
641
+ const duration = Date.now() - startTime;
642
+ this.metrics.successfulUpdates++;
643
+
644
+ this.logger.debug(`Updated ${channelName} inventory for ${sku}: ${quantity}`, {
645
+ duration,
646
+ });
647
+ } catch (error: any) {
648
+ this.metrics.failedUpdates++;
649
+ this.metrics.errors.push({
650
+ sku,
651
+ channel: channelName,
652
+ error: error.message,
653
+ });
654
+
655
+ if (error.response?.status === 429) {
656
+ this.metrics.rateLimitHits++;
657
+ }
658
+
659
+ this.logger.warn(`Failed to update ${channelName} inventory for ${sku}`, {
660
+ error: error.message,
661
+ status: error.response?.status,
662
+ });
663
+ }
664
+ })
665
+ );
666
+
667
+ updatePromises.push(...channelPromises);
668
+ }
669
+
670
+ await Promise.all(updatePromises);
671
+ }
672
+
673
+ private logMetrics(): void {
674
+ if (!config.processing.metricsEnabled) return;
675
+
676
+ const duration = this.metrics.endTime
677
+ ? (this.metrics.endTime.getTime() - this.metrics.startTime.getTime()) / 1000
678
+ : 0;
679
+
680
+ this.logger.info('='.repeat(80));
681
+ this.logger.info('SYNC METRICS', {
682
+ duration: `${duration.toFixed(2)}s`,
683
+ totalSKUs: this.metrics.totalSKUs,
684
+ successfulUpdates: this.metrics.successfulUpdates,
685
+ failedUpdates: this.metrics.failedUpdates,
686
+ skippedUpdates: this.metrics.skippedUpdates,
687
+ successRate: `${((this.metrics.successfulUpdates / (this.metrics.successfulUpdates + this.metrics.failedUpdates)) * 100).toFixed(2)}%`,
688
+ rateLimitHits: this.metrics.rateLimitHits,
689
+ errorCount: this.metrics.errors.length,
690
+ });
691
+
692
+ if (this.metrics.errors.length > 0) {
693
+ this.logger.warn('Error summary (first 10):', {
694
+ errors: this.metrics.errors.slice(0, 10),
695
+ });
696
+ }
697
+
698
+ this.logger.info('='.repeat(80));
699
+ }
700
+ }
701
+
702
+ // ============================================================================
703
+ // MAIN ENTRY POINT
704
+ // ============================================================================
705
+
706
+ async function main() {
707
+ const sync = new MultiChannelInventorySync();
708
+
709
+ try {
710
+ await sync.initialize();
711
+ await sync.syncInventory();
712
+
713
+ console.log('Multi-channel inventory sync completed successfully');
714
+ process.exit(0);
715
+ } catch (error: any) {
716
+ console.error('Fatal error:', error);
717
+ process.exit(1);
718
+ }
719
+ }
720
+
721
+ // Run if executed directly
722
+ if (require.main === module) {
723
+ main();
724
+ }
725
+
726
+ export { MultiChannelInventorySync };
727
+ ```
728
+
729
+ ---
730
+
731
+ ## Key Patterns Explained
732
+
733
+ ### Pattern 1: GraphQL Auto-Pagination for Large Datasets
734
+
735
+ **Challenge**: Efficiently fetch 10k-100k inventory positions without manual pagination logic
736
+
737
+ **Solution**: Use SDK's built-in auto-pagination with progress callbacks
738
+
739
+ ```javascript
740
+ const result = await fluentClient.graphql({
741
+ query,
742
+ variables: { retailerId, first: 200 },
743
+ pagination: {
744
+ maxRecords: 100000,
745
+ maxPages: 500,
746
+ },
747
+ });
748
+ ```
749
+
750
+ **Why This Works**:
751
+
752
+ - **Automatic**: No manual cursor tracking needed
753
+ - **Safe**: Built-in protections against infinite loops
754
+ - **Efficient**: Streams data as it's received
755
+ - **Observable**: Progress callbacks for monitoring
756
+
757
+ ### Pattern 2: ATP Aggregation with Location Rollup
758
+
759
+ **Challenge**: Calculate total Available-to-Promise across multiple warehouses/stores per SKU
760
+
761
+ **Solution**: Map-based aggregation with location tracking
762
+
763
+ ```javascript
764
+ function aggregateATP(inventoryPositions) {
765
+ const atpMap = new Map();
766
+ for (const position of inventoryPositions) {
767
+ const sku = position.productRef;
768
+ const availableQty = Math.max(0, position.availableQty || 0);
769
+
770
+ if (!atpMap.has(sku)) {
771
+ atpMap.set(sku, {
772
+ sku,
773
+ totalATP: 0,
774
+ locations: [],
775
+ lastUpdated: position.updatedOn,
776
+ });
777
+ }
778
+
779
+ const aggregated = atpMap.get(sku);
780
+ aggregated.totalATP += availableQty;
781
+ aggregated.locations.push({
782
+ locationRef: position.locationRef,
783
+ availableQty: availableQty,
784
+ });
785
+ }
786
+ return atpMap;
787
+ }
788
+ ```
789
+
790
+ **Why This Works**:
791
+
792
+ - **O(n) complexity**: Single pass through inventory
793
+ - **Location visibility**: Track which locations contribute to total
794
+ - **Negative protection**: `Math.max(0, ...)` prevents negative ATP
795
+ - **Timestamp tracking**: Know when inventory was last updated
796
+
797
+ ### Pattern 3: Marketplace-Specific Buffer Stock
798
+
799
+ **Challenge**: Different marketplaces need different safety buffers to prevent overselling
800
+
801
+ **Solution**: Configurable buffer per marketplace
802
+
803
+ ```javascript
804
+ // Configuration
805
+ const buffers = {
806
+ amazon: 5, // Lower buffer (fast fulfillment)
807
+ ebay: 3, // Moderate buffer
808
+ walmart: 10, // Higher buffer (longer fulfillment)
809
+ };
810
+
811
+ // Application
812
+ function applyBufferStock(totalATP, bufferStock) {
813
+ return Math.max(0, totalATP - bufferStock);
814
+ }
815
+
816
+ // Example: SKU with 50 ATP across all locations
817
+ const amazonQty = applyBufferStock(50, 5); // 45 available on Amazon
818
+ const ebayQty = applyBufferStock(50, 3); // 47 available on eBay
819
+ const walmartQty = applyBufferStock(50, 10); // 40 available on Walmart
820
+ ```
821
+
822
+ **Why This Works**:
823
+
824
+ - **Oversell prevention**: Accounts for sync delays and processing time
825
+ - **Marketplace flexibility**: Different risk profiles per marketplace
826
+ - **Safety floor**: `Math.max(0, ...)` ensures quantity never goes negative
827
+ - **Configurable**: Easy to adjust per marketplace requirements
828
+
829
+ ### Pattern 4: Parallel Marketplace Updates with Rate Limiting
830
+
831
+ **Challenge**: Update multiple marketplaces efficiently without exceeding API rate limits
832
+
833
+ **Solution**: Parallel execution with per-marketplace rate limiters
834
+
835
+ ```javascript
836
+ import pLimit from 'p-limit';
837
+
838
+ // Each marketplace has its own rate limiter
839
+ class AmazonMarketplace {
840
+ constructor(config) {
841
+ this.limiter = pLimit(config.rateLimit); // 10 req/sec
842
+ }
843
+
844
+ async updateInventory(sku, quantity) {
845
+ // Rate-limited execution
846
+ return this.limiter(() => this.makeApiCall(sku, quantity));
847
+ }
848
+ }
849
+
850
+ // Parallel sync across all marketplaces
851
+ const syncResults = await Promise.all(
852
+ marketplaces.map(marketplace => marketplace.syncInventory(atpMap))
853
+ );
854
+ ```
855
+
856
+ **Why This Works**:
857
+
858
+ - **Parallel execution**: All marketplaces sync simultaneously
859
+ - **Independent rate limits**: Each marketplace respects its own limits
860
+ - **Error isolation**: Failure in one marketplace doesn't affect others
861
+ - **Concurrency control**: p-limit prevents overwhelming APIs
862
+
863
+ ### Pattern 5: Exponential Backoff Retry Strategy
864
+
865
+ **Challenge**: Handle transient API failures (429 rate limits, 500 server errors)
866
+
867
+ **Solution**: p-retry with exponential backoff
868
+
869
+ ```javascript
870
+ import pRetry from 'p-retry';
871
+
872
+ async updateInventory(sku, quantity) {
873
+ return pRetry(
874
+ async () => {
875
+ // Attempt API call
876
+ const response = await axios.put(endpoint, payload);
877
+
878
+ // Check for retryable errors
879
+ if (response.status === 429) {
880
+ throw new Error('Rate limit exceeded'); // Will retry
881
+ }
882
+
883
+ return response.data;
884
+ },
885
+ {
886
+ retries: 3,
887
+ factor: 2, // Exponential backoff factor
888
+ minTimeout: 1000, // 1s, 2s, 4s delays
889
+ onFailedAttempt: error => {
890
+ logger.warn(`Retry attempt ${error.attemptNumber}`, {
891
+ retriesLeft: error.retriesLeft,
892
+ });
893
+ },
894
+ }
895
+ );
896
+ }
897
+ ```
898
+
899
+ **Why This Works**:
900
+
901
+ - **Transient failure recovery**: Handles temporary API issues
902
+ - **Exponential backoff**: Reduces load on overloaded APIs
903
+ - **Configurable retries**: 3 attempts is reasonable for most cases
904
+ - **Observable**: Logs each retry attempt for debugging
905
+
906
+ ### Pattern 6: SLA Tracking and Compliance
907
+
908
+ **Challenge**: Ensure sync completes within 15-minute SLA requirement
909
+
910
+ **Solution**: Duration tracking with SLA compliance check
911
+
912
+ ```javascript
913
+ function checkSLA(durationMs) {
914
+ const durationMinutes = durationMs / 60000;
915
+ const slaThreshold = 15; // 15-minute requirement
916
+ const slaMet = durationMinutes <= slaThreshold;
917
+
918
+ if (!slaMet) {
919
+ logger.warn('SLA BREACH: Sync exceeded threshold', {
920
+ durationMinutes: durationMinutes.toFixed(2),
921
+ threshold: slaThreshold,
922
+ });
923
+ metrics.increment('sla_breaches');
924
+ // Alert via PagerDuty, Slack, etc.
925
+ }
926
+
927
+ return slaMet;
928
+ }
929
+ ```
930
+
931
+ **Why This Works**:
932
+
933
+ - **Clear threshold**: 15 minutes is measurable and actionable
934
+ - **Automated detection**: No manual checking needed
935
+ - **Alerting hook**: Can trigger notifications on breach
936
+ - **Metrics tracking**: Historical SLA compliance data
937
+
938
+ ### Pattern 7: Dry-Run Mode for Safe Testing
939
+
940
+ **Challenge**: Test sync logic without actually updating marketplaces
941
+
942
+ **Solution**: Dry-run flag that short-circuits API calls
943
+
944
+ ```javascript
945
+ async updateInventory(sku, quantity, dryRun = false) {
946
+ if (dryRun) {
947
+ this.logger.info(`[DRY RUN] Would update inventory`, { sku, quantity });
948
+ return { success: true, sku, quantity, dryRun: true };
949
+ }
950
+
951
+ // Real API call
952
+ return this.makeApiCall(sku, quantity);
953
+ }
954
+
955
+ // Usage
956
+ npm run sync:dry-run
957
+ ```
958
+
959
+ **Why This Works**:
960
+
961
+ - **Safe testing**: Validate logic without side effects
962
+ - **End-to-end flow**: Tests everything except final API call
963
+ - **Easy toggle**: Environment variable or CLI flag
964
+ - **Visible logging**: Clear indication of dry-run mode
965
+
966
+ ---
967
+
968
+ ## Testing
969
+
970
+ ### Dry-Run Test
971
+
972
+ ```bash
973
+ # Test sync without updating marketplaces
974
+ DRY_RUN=true npm run sync:once
975
+
976
+ # Expected output:
977
+ # [DRY RUN] Would update Amazon inventory { sku: 'PROD-001', quantity: 45 }
978
+ # [DRY RUN] Would update eBay inventory { sku: 'PROD-001', quantity: 47 }
979
+ # [DRY RUN] Would update Walmart inventory { sku: 'PROD-001', quantity: 40 }
980
+ ```
981
+
982
+ ### Single Sync Execution
983
+
984
+ ```bash
985
+ # Run once and exit
986
+ npm run sync:once
987
+
988
+ # Check logs
989
+ cat logs/inventory-sync.log | grep "COMPLETE"
990
+ ```
991
+
992
+ ### Continuous Sync Mode
993
+
994
+ ```bash
995
+ # Run continuously (every 15 minutes)
996
+ npm run sync:continuous
997
+
998
+ # Check next sync time in logs
999
+ ```
1000
+
1001
+ ---
1002
+
1003
+ ## Deployment Options
1004
+
1005
+ ### Option 1: Docker Container
1006
+
1007
+ Create `Dockerfile`:
1008
+
1009
+ ```dockerfile
1010
+ FROM node:18-alpine
1011
+
1012
+ WORKDIR /app
1013
+
1014
+ # Copy package files
1015
+ COPY package*.json ./
1016
+
1017
+ # Install dependencies
1018
+ RUN npm ci --only=production
1019
+
1020
+ # Copy application code
1021
+ COPY src ./src
1022
+
1023
+ # Create state directory
1024
+ RUN mkdir -p /app/state
1025
+
1026
+ # Run continuous sync
1027
+ CMD ["node", "src/index.js"]
1028
+ ```
1029
+
1030
+ Build and run:
1031
+
1032
+ ```bash
1033
+ # Build image
1034
+ docker build -t multi-channel-sync .
1035
+
1036
+ # Run container
1037
+ docker run -d \
1038
+ --name inventory-sync \
1039
+ --env-file .env \
1040
+ --restart unless-stopped \
1041
+ --volume ./state:/app/state \
1042
+ multi-channel-sync
1043
+ ```
1044
+
1045
+ ### Option 2: AWS ECS Task
1046
+
1047
+ Create `ecs-task-definition.json`:
1048
+
1049
+ ```json
1050
+ {
1051
+ "family": "multi-channel-inventory-sync",
1052
+ "networkMode": "awsvpc",
1053
+ "requiresCompatibilities": ["FARGATE"],
1054
+ "cpu": "1024",
1055
+ "memory": "2048",
1056
+ "containerDefinitions": [
1057
+ {
1058
+ "name": "inventory-sync",
1059
+ "image": "your-registry/multi-channel-sync:latest",
1060
+ "essential": true,
1061
+ "environment": [
1062
+ { "name": "LOG_LEVEL", "value": "info" },
1063
+ { "name": "SYNC_INTERVAL_MINUTES", "value": "15" }
1064
+ ],
1065
+ "secrets": [
1066
+ {
1067
+ "name": "FLUENT_CLIENT_ID",
1068
+ "valueFrom": "arn:aws:secretsmanager:us-east-1:123:secret:fluent-client-id"
1069
+ }
1070
+ ],
1071
+ "logConfiguration": {
1072
+ "logDriver": "awslogs",
1073
+ "options": {
1074
+ "awslogs-group": "/ecs/inventory-sync",
1075
+ "awslogs-region": "us-east-1",
1076
+ "awslogs-stream-prefix": "ecs"
1077
+ }
1078
+ }
1079
+ }
1080
+ ]
1081
+ }
1082
+ ```
1083
+
1084
+ Deploy:
1085
+
1086
+ ```bash
1087
+ aws ecs register-task-definition --cli-input-json file://ecs-task-definition.json
1088
+ aws ecs create-service \
1089
+ --cluster production \
1090
+ --service-name inventory-sync \
1091
+ --task-definition multi-channel-inventory-sync \
1092
+ --desired-count 1 \
1093
+ --launch-type FARGATE
1094
+ ```
1095
+
1096
+ ---
1097
+
1098
+ ## Common Issues & Solutions
1099
+
1100
+ ### Issue 1: SLA Breach (Sync Takes >15 Minutes)
1101
+
1102
+ **Symptoms**:
1103
+
1104
+ - Log shows "SLA BREACH" warning
1105
+ - Sync duration exceeds 15 minutes
1106
+
1107
+ **Solutions**:
1108
+
1109
+ 1. **Reduce page size** (faster initial response):
1110
+
1111
+ ```javascript
1112
+ variables: {
1113
+ first: 100;
1114
+ } // Instead of 200
1115
+ ```
1116
+
1117
+ 2. **Increase parallelism**:
1118
+
1119
+ ```javascript
1120
+ const limiter = pLimit(20); // Increase from 10
1121
+ ```
1122
+
1123
+ 3. **Optimize marketplace rate limits** (if APIs allow):
1124
+
1125
+ ```bash
1126
+ AMAZON_RATE_LIMIT=20 # Increase from 10
1127
+ ```
1128
+
1129
+ 4. **Split sync by marketplace** (run separately):
1130
+
1131
+ ```bash
1132
+ AMAZON_ENABLED=true EBAY_ENABLED=false WALMART_ENABLED=false npm run sync:once
1133
+ ```
1134
+
1135
+ ---
1136
+
1137
+ ## Related Guides
1138
+
1139
+ - **GraphQL Query Export**: [`./graphql-query-export.md`](./graphql-query-export.md) - GraphQL pagination patterns
1140
+ - **Multi-Source Aggregation**: `./04-multi-source-aggregation.md` - Data aggregation strategies
1141
+ - **Error Handling Patterns**: `../../03-PATTERN-GUIDES/error-handling/readme.md` - Retry and error handling
1142
+ - **Universal Mapping Guide**: `../../02-CORE-GUIDES/mapping/readme.md` - Field transformations
1143
+ - **SDK API Reference**: `../../readme.md` - Core SDK documentation
1144
+
1145
+ ---
1146
+
1147
+ ## Production Checklist
1148
+
1149
+ Before deploying to production:
1150
+
1151
+ - [ ] All marketplace credentials secured (AWS Secrets Manager, Vault)
1152
+ - [ ] Rate limits configured per marketplace API documentation
1153
+ - [ ] Buffer stock values tested and approved by business
1154
+ - [ ] SLA threshold aligned with business requirements
1155
+ - [ ] Monitoring dashboards created (sync duration, SLA compliance, error rates)
1156
+ - [ ] Alerting configured (PagerDuty, Slack, email)
1157
+ - [ ] Dry-run testing completed with production data
1158
+ - [ ] Load testing with 100k+ SKUs
1159
+ - [ ] State management enabled to prevent duplicate processing
1160
+ - [ ] Logging configured (CloudWatch, Datadog, Splunk)
1161
+ - [ ] Error tracking integrated (Sentry, Rollbar)
1162
+ - [ ] Documentation updated with runbooks
1163
+ - [ ] On-call team trained on troubleshooting
1164
+ - [ ] Disaster recovery plan documented
1165
+ - [ ] Metrics baseline established (average sync duration, success rate)
1166
+
1167
+ ---
1168
+
1169
+ **Next Steps**:
1170
+
1171
+ 1. Customize buffer stock values per marketplace and product category
1172
+ 2. Implement incremental sync (only process changed inventory)
1173
+ 3. Add webhook integration for real-time inventory updates
1174
+ 4. Set up monitoring dashboards (Grafana, Datadog)
1175
+ 5. Integrate with incident management (PagerDuty)
1176
+ 6. Add marketplace-specific SKU mapping (Fluent SKU → Marketplace SKU)
1177
+ 7. Implement A/B testing for buffer stock optimization
1178
+
1179
+ **Support**:
1180
+
1181
+ - SDK Issues: https://github.com/fluentcommerce/fc-connect-sdk/issues
1182
+ - Fluent Commerce API: https://docs.fluentcommerce.com
1183
+ - Amazon SP-API: https://developer-docs.amazon.com/sp-api/
1184
+ - eBay Trading API: https://developer.ebay.com/devzone/xml/docs/reference/ebay/
1185
+ - Walmart Seller API: https://developer.walmart.com/