@fluentcommerce/fc-connect-sdk 0.1.53 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -2
- package/README.md +39 -0
- package/dist/cjs/auth/index.d.ts +3 -0
- package/dist/cjs/auth/index.js +13 -0
- package/dist/cjs/auth/profile-loader.d.ts +18 -0
- package/dist/cjs/auth/profile-loader.js +208 -0
- package/dist/cjs/client-factory.d.ts +4 -0
- package/dist/cjs/client-factory.js +10 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/auth/index.d.ts +3 -0
- package/dist/esm/auth/index.js +2 -0
- package/dist/esm/auth/profile-loader.d.ts +18 -0
- package/dist/esm/auth/profile-loader.js +169 -0
- package/dist/esm/client-factory.d.ts +4 -0
- package/dist/esm/client-factory.js +9 -0
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/auth/index.d.ts +3 -0
- package/dist/types/auth/profile-loader.d.ts +18 -0
- package/dist/types/client-factory.d.ts +4 -0
- package/dist/types/index.d.ts +3 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -482
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
|
@@ -1,991 +1,991 @@
|
|
|
1
|
-
# Module 1: Real-Time Processing
|
|
2
|
-
|
|
3
|
-
> **Learning Objective:** Understand real-time event processing patterns, when to use them, and how to implement immediate event handling with the Fluent Connect SDK.
|
|
4
|
-
>
|
|
5
|
-
> **Level:** Beginner
|
|
6
|
-
|
|
7
|
-
## Table of Contents
|
|
8
|
-
|
|
9
|
-
1. [What is Real-Time Processing?](#what-is-real-time-processing)
|
|
10
|
-
2. [When to Use Real-Time Processing](#when-to-use-real-time-processing)
|
|
11
|
-
3. [Real-Time vs Batch: The Decision](#real-time-vs-batch-the-decision)
|
|
12
|
-
4. [Common Real-Time Use Cases](#common-real-time-use-cases)
|
|
13
|
-
5. [SDK Components for Real-Time Processing](#sdk-components-for-real-time-processing)
|
|
14
|
-
6. [Basic Real-Time Workflow](#basic-real-time-workflow)
|
|
15
|
-
7. [Real-Time Pattern: Webhook to GraphQL](#real-time-pattern-webhook-to-graphql)
|
|
16
|
-
8. [Error Handling in Real-Time](#error-handling-in-real-time)
|
|
17
|
-
9. [Next Steps](#next-steps)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## What is Real-Time Processing?
|
|
22
|
-
|
|
23
|
-
**Real-time processing** means handling events as they occur, with minimal latency between event trigger and completion.
|
|
24
|
-
|
|
25
|
-
### Key Characteristics
|
|
26
|
-
|
|
27
|
-
| Characteristic | Description | Example |
|
|
28
|
-
| ------------------------ | ----------------------------------- | ------------------------------ |
|
|
29
|
-
| **Immediate Trigger** | Event triggers processing instantly | HTTP webhook receives order |
|
|
30
|
-
| **Low Latency** | Processing completes in seconds | Order created within 5 seconds |
|
|
31
|
-
| **Event-Driven** | External events drive execution | SFCC order placement |
|
|
32
|
-
| **Synchronous Response** | Caller waits for result | Webhook returns success/error |
|
|
33
|
-
|
|
34
|
-
### How It Works
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
External Event → Webhook Endpoint → Process Data → Call Fluent API → Return Response
|
|
38
|
-
↓ ↓ ↓ ↓ ↓
|
|
39
|
-
<1 second Parse payload Transform data Create order Success/error
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Visual Flow
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
┌─────────────┐
|
|
46
|
-
│ SFCC Order │ ──① HTTP POST──> ┌──────────────────┐
|
|
47
|
-
│ Placed │ │ Versori Webhook │
|
|
48
|
-
└─────────────┘ │ (Your code) │
|
|
49
|
-
└────────┬─────────┘
|
|
50
|
-
│
|
|
51
|
-
②Parse XML/JSON
|
|
52
|
-
│
|
|
53
|
-
▼
|
|
54
|
-
┌──────────────────┐
|
|
55
|
-
│ GraphQLMutation │
|
|
56
|
-
│ Mapper │
|
|
57
|
-
└────────┬─────────┘
|
|
58
|
-
│
|
|
59
|
-
③Apply field mapping
|
|
60
|
-
│
|
|
61
|
-
▼
|
|
62
|
-
┌──────────────────┐
|
|
63
|
-
│ Fluent Client │
|
|
64
|
-
│ createOrder() │
|
|
65
|
-
└────────┬─────────┘
|
|
66
|
-
│
|
|
67
|
-
④GraphQL mutation
|
|
68
|
-
│
|
|
69
|
-
▼
|
|
70
|
-
┌──────────────────┐
|
|
71
|
-
│ Fluent Commerce │
|
|
72
|
-
│ Order Created │
|
|
73
|
-
└────────┬─────────┘
|
|
74
|
-
│
|
|
75
|
-
⑤Return response
|
|
76
|
-
│
|
|
77
|
-
▼
|
|
78
|
-
┌──────────────────┐
|
|
79
|
-
│ 200 OK │
|
|
80
|
-
│ { orderId } │
|
|
81
|
-
└──────────────────┘
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Total latency**: 2-5 seconds from webhook receipt to Fluent order creation.
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## When to Use Real-Time Processing
|
|
89
|
-
|
|
90
|
-
### ✅ Use Real-Time When:
|
|
91
|
-
|
|
92
|
-
| Scenario | Why Real-Time? | SDK Pattern |
|
|
93
|
-
| --------------------- | --------------------------------------- | ------------------------------ |
|
|
94
|
-
| **Order Webhooks** | Customers expect immediate confirmation | Webhook → GraphQL mutation |
|
|
95
|
-
| **Inventory Updates** | Stock levels must be accurate instantly | Webhook → Batch API (single) |
|
|
96
|
-
| **Low Volume** | < 100 events/hour | Simple webhook handler |
|
|
97
|
-
| **Critical Events** | Payment, shipment, cancellation | Immediate processing + logging |
|
|
98
|
-
| **External Triggers** | Third-party systems push data | HTTP endpoint required |
|
|
99
|
-
|
|
100
|
-
### ❌ Avoid Real-Time When:
|
|
101
|
-
|
|
102
|
-
| Scenario | Why Not Real-Time? | Use Instead |
|
|
103
|
-
| ------------------- | -------------------- | --------------------------- |
|
|
104
|
-
| **Large Files** | 10K+ records | Batch processing (Module 2) |
|
|
105
|
-
| **High Volume** | > 1,000 events/hour | Scheduled batch (Module 2) |
|
|
106
|
-
| **Long Processing** | > 30 seconds | Async job queue |
|
|
107
|
-
| **Bulk Operations** | Daily inventory sync | Batch API (Module 2) |
|
|
108
|
-
| **Non-Critical** | Reports, analytics | Scheduled extraction |
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## Real-Time vs Batch: The Decision
|
|
113
|
-
|
|
114
|
-
### Volume-Based Decision Matrix
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
Events/Hour │ Pattern
|
|
118
|
-
────────────┼────────────────────────────────
|
|
119
|
-
< 10 │ Real-Time (Webhook)
|
|
120
|
-
10-100 │ Real-Time (Webhook)
|
|
121
|
-
100-500 │ Real-Time OR Micro-batch
|
|
122
|
-
500-1K │ Micro-batch (5-minute windows)
|
|
123
|
-
1K-10K │ Batch (hourly)
|
|
124
|
-
> 10K │ Batch (daily)
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Latency Requirements
|
|
128
|
-
|
|
129
|
-
| Requirement | Pattern | Example |
|
|
130
|
-
| --------------- | ------------ | -------------------- |
|
|
131
|
-
| **< 5 seconds** | Real-Time | Order confirmation |
|
|
132
|
-
| **< 5 minutes** | Micro-batch | Inventory updates |
|
|
133
|
-
| **< 1 hour** | Hourly batch | Product catalog sync |
|
|
134
|
-
| **< 24 hours** | Daily batch | Full inventory sync |
|
|
135
|
-
|
|
136
|
-
### Example Decisions
|
|
137
|
-
|
|
138
|
-
#### ✅ GOOD: Real-Time for Order Webhooks
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
// Scenario: SFCC sends 20-50 orders/hour
|
|
142
|
-
// Requirement: Orders visible in Fluent within 5 seconds
|
|
143
|
-
// Volume: Low (<100/hour)
|
|
144
|
-
// Pattern: Real-time webhook
|
|
145
|
-
|
|
146
|
-
export default async function processOrder(ctx) {
|
|
147
|
-
const orderData = ctx.activation.body;
|
|
148
|
-
const client = await createClient(ctx); // Auto-detects Versori context
|
|
149
|
-
|
|
150
|
-
// Immediate processing
|
|
151
|
-
const result = await client.graphql({
|
|
152
|
-
query: CREATE_ORDER_MUTATION,
|
|
153
|
-
variables: { input: mapOrderData(orderData) },
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
return { status: 200, body: { orderId: result.id } };
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Why this works**: Low volume + low latency requirement = perfect for real-time.
|
|
161
|
-
|
|
162
|
-
#### ❌ WRONG: Real-Time for Bulk Inventory
|
|
163
|
-
|
|
164
|
-
```typescript
|
|
165
|
-
// ❌ BAD: Trying to process 50K inventory records via webhooks
|
|
166
|
-
export default async function processInventory(activation, log, connections) {
|
|
167
|
-
const inventoryFile = activation.body.fileUrl; // 50K records
|
|
168
|
-
|
|
169
|
-
// This will timeout! Each webhook has 30-second limit
|
|
170
|
-
for (const record of records) {
|
|
171
|
-
await client.graphql({ ... }); // 50K sequential API calls = HOURS
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Why this fails**:
|
|
177
|
-
|
|
178
|
-
- Webhook timeout (30-60 seconds)
|
|
179
|
-
- 50K sequential API calls = 1-2 hours
|
|
180
|
-
- No progress tracking
|
|
181
|
-
- No error recovery
|
|
182
|
-
|
|
183
|
-
**✅ Better approach**: Use Batch API (Module 2)
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
// Process 50K records in 5-10 minutes via Batch API
|
|
187
|
-
const job = await client.createJob({ name: 'inventory-update' });
|
|
188
|
-
const batch = await client.sendBatch(job.id, { entities: records });
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## Common Real-Time Use Cases
|
|
194
|
-
|
|
195
|
-
### Use Case 1: SFCC Order Creation
|
|
196
|
-
|
|
197
|
-
**Trigger**: Salesforce Commerce Cloud sends order XML via webhook
|
|
198
|
-
**Processing Time**: 3-5 seconds
|
|
199
|
-
**Volume**: 10-100 orders/hour
|
|
200
|
-
**SDK Pattern**: `GraphQLMutationMapper` + `createClient`
|
|
201
|
-
|
|
202
|
-
**Complete implementation**: [XML Order Ingestion Guide](../../../01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md)
|
|
203
|
-
|
|
204
|
-
### Use Case 2: Inventory Adjustment (Single SKU)
|
|
205
|
-
|
|
206
|
-
**Trigger**: Warehouse system reports damage/theft
|
|
207
|
-
**Processing Time**: 1-2 seconds
|
|
208
|
-
**Volume**: < 10 events/hour
|
|
209
|
-
**SDK Pattern**: Direct GraphQL mutation
|
|
210
|
-
|
|
211
|
-
**Example**:
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
215
|
-
|
|
216
|
-
export default async function adjustInventory(activation: any, log: any, connections: any) {
|
|
217
|
-
const { sku, location, quantity, reason } = activation.body;
|
|
218
|
-
|
|
219
|
-
const client = await createClient({
|
|
220
|
-
connection: connections.fluent_commerce,
|
|
221
|
-
logger: log,
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const result = await client.graphql({
|
|
225
|
-
query: `
|
|
226
|
-
mutation UpdateInventory($input: UpdateInventoryQuantityInput!) {
|
|
227
|
-
updateInventoryQuantity(input: $input) {
|
|
228
|
-
id
|
|
229
|
-
ref
|
|
230
|
-
quantity
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
`,
|
|
234
|
-
variables: {
|
|
235
|
-
input: {
|
|
236
|
-
ref: `${sku}-${location}`,
|
|
237
|
-
quantity: quantity,
|
|
238
|
-
attributes: [{ name: 'adjustmentReason', type: 'String', value: reason }],
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
log.info('Inventory adjusted', { sku, location, newQuantity: result.quantity });
|
|
244
|
-
|
|
245
|
-
return {
|
|
246
|
-
status: 200,
|
|
247
|
-
body: { success: true, inventoryId: result.id },
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Use Case 3: Order Status Update (External System → Fluent)
|
|
253
|
-
|
|
254
|
-
**Trigger**: Shipping carrier sends delivery confirmation
|
|
255
|
-
**Processing Time**: 2-3 seconds
|
|
256
|
-
**Volume**: 50-200 events/hour
|
|
257
|
-
**SDK Pattern**: GraphQL mutation with event
|
|
258
|
-
|
|
259
|
-
**Example**:
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
263
|
-
|
|
264
|
-
export default async function updateOrderStatus(activation: any, log: any, connections: any) {
|
|
265
|
-
const { orderRef, status, trackingNumber, carrier } = activation.body;
|
|
266
|
-
|
|
267
|
-
const client = await createClient({
|
|
268
|
-
connection: connections.fluent_commerce,
|
|
269
|
-
logger: log,
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// Send event to Fluent workflow
|
|
273
|
-
const result = await client.graphql({
|
|
274
|
-
query: `
|
|
275
|
-
mutation SendEvent($input: EventInput!) {
|
|
276
|
-
sendEvent(input: $input) {
|
|
277
|
-
id
|
|
278
|
-
status
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
`,
|
|
282
|
-
variables: {
|
|
283
|
-
input: {
|
|
284
|
-
entityRef: orderRef,
|
|
285
|
-
entityType: 'ORDER',
|
|
286
|
-
name: 'carrier.tracking.update',
|
|
287
|
-
attributes: [
|
|
288
|
-
{ name: 'trackingNumber', type: 'String', value: trackingNumber },
|
|
289
|
-
{ name: 'carrier', type: 'String', value: carrier },
|
|
290
|
-
{ name: 'status', type: 'String', value: status },
|
|
291
|
-
],
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
return {
|
|
297
|
-
status: 200,
|
|
298
|
-
body: { success: true, eventId: result.id },
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## SDK Components for Real-Time Processing
|
|
306
|
-
|
|
307
|
-
### Component 1: `createClient()`
|
|
308
|
-
|
|
309
|
-
**Purpose**: Create authenticated Fluent API client
|
|
310
|
-
|
|
311
|
-
**Usage**:
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
315
|
-
|
|
316
|
-
// Versori platform (recommended)
|
|
317
|
-
const client = await createClient({
|
|
318
|
-
connection: connections.fluent_commerce,
|
|
319
|
-
logger: log,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// Standalone (Node.js/Deno)
|
|
323
|
-
const client = await createClient({
|
|
324
|
-
config: {
|
|
325
|
-
baseUrl: 'https://api.fluentcommerce.com',
|
|
326
|
-
clientId: process.env.FLUENT_CLIENT_ID,
|
|
327
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET,
|
|
328
|
-
retailerId: process.env.FLUENT_RETAILER_ID,
|
|
329
|
-
},
|
|
330
|
-
});
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
**What it does**:
|
|
334
|
-
|
|
335
|
-
- Extracts OAuth2 credentials from connection
|
|
336
|
-
- Manages token refresh automatically
|
|
337
|
-
- Returns ready-to-use `FluentClient` instance
|
|
338
|
-
|
|
339
|
-
### Component 2: `GraphQLMutationMapper`
|
|
340
|
-
|
|
341
|
-
**Purpose**: Transform external data (XML/JSON) to Fluent GraphQL mutations
|
|
342
|
-
|
|
343
|
-
**Usage**:
|
|
344
|
-
|
|
345
|
-
```typescript
|
|
346
|
-
import { GraphQLMutationMapper } from '@fluentcommerce/fc-connect-sdk';
|
|
347
|
-
|
|
348
|
-
const mapper = new GraphQLMutationMapper(mappingConfig, logger, { fluentClient: client });
|
|
349
|
-
|
|
350
|
-
// Process with nodes (for nested/escaped XML)
|
|
351
|
-
const result = await mapper.mapWithNodes(orderData, customResolvers, context);
|
|
352
|
-
|
|
353
|
-
// Check success (errors are returned, not thrown)
|
|
354
|
-
if (!result.success) {
|
|
355
|
-
console.error('Mapping failed:', result.errors);
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Execute (query is auto-generated in result)
|
|
360
|
-
const mutationResult = await client.graphql({
|
|
361
|
-
query: result.query,
|
|
362
|
-
variables: result.variables, // ✅ Use variables (wrapped if fields pattern)
|
|
363
|
-
});
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
**Key features**:
|
|
367
|
-
|
|
368
|
-
- **Nodes**: Extract and parse nested XML/JSON
|
|
369
|
-
- **Field Mapping**: Transform source fields to target schema
|
|
370
|
-
- **Custom Resolvers**: Apply business logic during transformation
|
|
371
|
-
- **Validation**: Checks required fields and types
|
|
372
|
-
|
|
373
|
-
**Complete guide**: [GraphQL Mutation Mapper](../../../02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md)
|
|
374
|
-
|
|
375
|
-
### Component 3: `FluentClient` Methods
|
|
376
|
-
|
|
377
|
-
**Available methods**:
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
// Query (returns data only)
|
|
381
|
-
const orders = await client.graphql({
|
|
382
|
-
query: GET_ORDERS_QUERY,
|
|
383
|
-
variables: { status: 'PENDING' },
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Mutation (returns data only)
|
|
387
|
-
const created = await client.graphql({
|
|
388
|
-
query: CREATE_ORDER_MUTATION,
|
|
389
|
-
variables: { input: orderData },
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Advanced (with pagination, progress, extensions)
|
|
393
|
-
const result = await client.graphql({
|
|
394
|
-
query: GET_ALL_ORDERS,
|
|
395
|
-
variables: { first: 100 },
|
|
396
|
-
pagination: {
|
|
397
|
-
maxPages: 50,
|
|
398
|
-
onProgress: (page, total) => log.info(`Page ${page}/${total}`),
|
|
399
|
-
},
|
|
400
|
-
});
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
**When to use each**:
|
|
404
|
-
|
|
405
|
-
- `query()` - Simple queries without pagination
|
|
406
|
-
- `mutate()` - Create/update operations
|
|
407
|
-
- `graphql()` - Auto-pagination, progress tracking, extensions
|
|
408
|
-
|
|
409
|
-
### Component 4: `UniversalMapper`
|
|
410
|
-
|
|
411
|
-
**Purpose**: Field-level transformation for any data format (CSV, JSON, XML, Parquet)
|
|
412
|
-
|
|
413
|
-
**Usage**:
|
|
414
|
-
|
|
415
|
-
```typescript
|
|
416
|
-
import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
|
|
417
|
-
|
|
418
|
-
const mappingConfig = {
|
|
419
|
-
fields: {
|
|
420
|
-
skuRef: { source: 'sku_id', required: true },
|
|
421
|
-
qty: { source: 'quantity', resolver: 'sdk.parseInt' },
|
|
422
|
-
expectedOn: { source: 'date', resolver: 'sdk.formatDate' },
|
|
423
|
-
},
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
const mapper = new UniversalMapper(mappingConfig);
|
|
427
|
-
const result = await mapper.map(sourceData);
|
|
428
|
-
|
|
429
|
-
if (result.success) {
|
|
430
|
-
console.log('Mapped data:', result.data);
|
|
431
|
-
} else {
|
|
432
|
-
console.error('Mapping errors:', result.errors);
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
**Built-in resolvers**:
|
|
437
|
-
|
|
438
|
-
- `sdk.parseInt`, `sdk.parseFloat` - Type conversion
|
|
439
|
-
- `sdk.formatDate`, `sdk.parseDate` - Date handling
|
|
440
|
-
- `sdk.uppercase`, `sdk.lowercase`, `sdk.trim` - String manipulation
|
|
441
|
-
- `sdk.boolean`, `sdk.toJson`, `sdk.parseJson` - Type casting
|
|
442
|
-
|
|
443
|
-
**Complete guide**: [Universal Mapping](../../../02-CORE-GUIDES/mapping/mapping-readme.md)
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
## Basic Real-Time Workflow
|
|
448
|
-
|
|
449
|
-
### Workflow Pattern
|
|
450
|
-
|
|
451
|
-
```typescript
|
|
452
|
-
/**
|
|
453
|
-
* Basic Real-Time Webhook Pattern
|
|
454
|
-
*
|
|
455
|
-
* Steps:
|
|
456
|
-
* 1. Receive webhook payload
|
|
457
|
-
* 2. Validate and parse data
|
|
458
|
-
* 3. Transform to Fluent schema
|
|
459
|
-
* 4. Execute GraphQL mutation
|
|
460
|
-
* 5. Return response
|
|
461
|
-
*/
|
|
462
|
-
|
|
463
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
464
|
-
|
|
465
|
-
export default async function webhookHandler(activation: any, log: any, connections: any) {
|
|
466
|
-
try {
|
|
467
|
-
// Step 1: Extract payload
|
|
468
|
-
const payload = activation.body;
|
|
469
|
-
log.info('Received webhook', { payload });
|
|
470
|
-
|
|
471
|
-
// Step 2: Validate required fields
|
|
472
|
-
if (!payload.orderRef) {
|
|
473
|
-
throw new Error('Missing required field: orderRef');
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Step 3: Create Fluent client
|
|
477
|
-
const client = await createClient({
|
|
478
|
-
connection: connections.fluent_commerce,
|
|
479
|
-
logger: log,
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
// Step 4: Transform data
|
|
483
|
-
const fluentInput = {
|
|
484
|
-
ref: payload.orderRef,
|
|
485
|
-
type: 'HD',
|
|
486
|
-
totalPrice: parseFloat(payload.total),
|
|
487
|
-
currency: payload.currency || 'USD',
|
|
488
|
-
retailer: { id: '2' },
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
// Step 5: Execute mutation
|
|
492
|
-
const result = await client.graphql({
|
|
493
|
-
query: `
|
|
494
|
-
mutation CreateOrder($input: CreateOrderInput!) {
|
|
495
|
-
createOrder(input: $input) {
|
|
496
|
-
id
|
|
497
|
-
ref
|
|
498
|
-
status
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
`,
|
|
502
|
-
variables: { input: fluentInput },
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
log.info('Order created', { orderId: result.id });
|
|
506
|
-
|
|
507
|
-
// Step 6: Return success
|
|
508
|
-
return {
|
|
509
|
-
status: 200,
|
|
510
|
-
body: {
|
|
511
|
-
success: true,
|
|
512
|
-
orderId: result.id,
|
|
513
|
-
orderRef: result.ref,
|
|
514
|
-
},
|
|
515
|
-
};
|
|
516
|
-
} catch (error: any) {
|
|
517
|
-
log.error('Webhook processing failed', error);
|
|
518
|
-
|
|
519
|
-
// Step 7: Return error
|
|
520
|
-
return {
|
|
521
|
-
status: 500,
|
|
522
|
-
body: {
|
|
523
|
-
success: false,
|
|
524
|
-
error: error.message,
|
|
525
|
-
},
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
### Key Steps Explained
|
|
532
|
-
|
|
533
|
-
#### Step 1: Extract Payload
|
|
534
|
-
|
|
535
|
-
```typescript
|
|
536
|
-
// Versori automatically parses JSON/XML
|
|
537
|
-
const payload = activation.body;
|
|
538
|
-
|
|
539
|
-
// For raw strings, use parsers
|
|
540
|
-
import { XMLParserService } from '@fluentcommerce/fc-connect-sdk';
|
|
541
|
-
const parser = new XMLParserService();
|
|
542
|
-
const payload = await parser.parse(activation.body);
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
#### Step 2: Validation
|
|
546
|
-
|
|
547
|
-
```typescript
|
|
548
|
-
// Required field validation
|
|
549
|
-
const requiredFields = ['orderRef', 'total', 'items'];
|
|
550
|
-
for (const field of requiredFields) {
|
|
551
|
-
if (!payload[field]) {
|
|
552
|
-
throw new Error(`Missing required field: ${field}`);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// Type validation
|
|
557
|
-
if (typeof payload.total !== 'number') {
|
|
558
|
-
throw new Error('total must be a number');
|
|
559
|
-
}
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
#### Step 3: Client Creation
|
|
563
|
-
|
|
564
|
-
```typescript
|
|
565
|
-
// ALWAYS use createClient() - it auto-detects Versori vs standalone
|
|
566
|
-
const client = await createClient({
|
|
567
|
-
connection: connections.fluent_commerce,
|
|
568
|
-
logger: log,
|
|
569
|
-
});
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
#### Step 4: Data Transformation
|
|
573
|
-
|
|
574
|
-
```typescript
|
|
575
|
-
// Simple mapping
|
|
576
|
-
const fluentInput = {
|
|
577
|
-
ref: payload.orderRef,
|
|
578
|
-
type: mapOrderType(payload.orderType),
|
|
579
|
-
totalPrice: parseFloat(payload.total),
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
// Complex mapping (use UniversalMapper or GraphQLMutationMapper)
|
|
583
|
-
const mapper = new UniversalMapper(mappingConfig);
|
|
584
|
-
const result = await mapper.map(payload);
|
|
585
|
-
const fluentInput = result.data;
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
#### Step 5: Execute Mutation
|
|
589
|
-
|
|
590
|
-
```typescript
|
|
591
|
-
// Use mutate() for simple operations
|
|
592
|
-
const result = await client.graphql({
|
|
593
|
-
query: mutation,
|
|
594
|
-
variables: { input: fluentInput },
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
// Check for errors
|
|
598
|
-
if (!result || !result.id) {
|
|
599
|
-
throw new Error('Mutation failed: No ID returned');
|
|
600
|
-
}
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
#### Step 6-7: Return Response
|
|
604
|
-
|
|
605
|
-
```typescript
|
|
606
|
-
// Versori expects { status, body }
|
|
607
|
-
return {
|
|
608
|
-
status: 200,
|
|
609
|
-
body: { success: true, orderId: result.id },
|
|
610
|
-
};
|
|
611
|
-
|
|
612
|
-
// Error response
|
|
613
|
-
return {
|
|
614
|
-
status: 500,
|
|
615
|
-
body: { success: false, error: error.message },
|
|
616
|
-
};
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
---
|
|
620
|
-
|
|
621
|
-
## Real-Time Pattern: Webhook to GraphQL
|
|
622
|
-
|
|
623
|
-
### Pattern Overview
|
|
624
|
-
|
|
625
|
-
**Purpose**: Transform external webhook data to Fluent GraphQL mutations
|
|
626
|
-
|
|
627
|
-
**Flow**:
|
|
628
|
-
|
|
629
|
-
```
|
|
630
|
-
Webhook Payload → Parse → Map → Validate → Execute → Response
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
### Complete Implementation
|
|
634
|
-
|
|
635
|
-
See **[XML Order Ingestion](../../../01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md)** for production-ready implementation.
|
|
636
|
-
|
|
637
|
-
### Quick Example: JSON Order Webhook
|
|
638
|
-
|
|
639
|
-
```typescript
|
|
640
|
-
/**
|
|
641
|
-
* JSON Order Webhook → Fluent Order
|
|
642
|
-
*
|
|
643
|
-
* External system sends JSON order data via POST
|
|
644
|
-
*/
|
|
645
|
-
|
|
646
|
-
import { createClient, UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
|
|
647
|
-
|
|
648
|
-
// Mapping configuration
|
|
649
|
-
const ORDER_MAPPING = {
|
|
650
|
-
fields: {
|
|
651
|
-
ref: { source: 'order_id', required: true },
|
|
652
|
-
type: { source: 'order_type', resolver: 'custom.mapOrderType' },
|
|
653
|
-
totalPrice: { source: 'total', resolver: 'sdk.parseFloat' },
|
|
654
|
-
currency: { source: 'currency', defaultValue: 'USD' },
|
|
655
|
-
'retailer.id': { value: '2' },
|
|
656
|
-
'customer.id': { resolver: 'custom.lookupCustomer' },
|
|
657
|
-
'items[]': {
|
|
658
|
-
source: 'line_items',
|
|
659
|
-
fields: {
|
|
660
|
-
ref: { source: '$.item_id', resolver: 'sdk.toString' },
|
|
661
|
-
productRef: { source: '$.sku', required: true },
|
|
662
|
-
quantity: { source: '$.qty', resolver: 'sdk.parseInt' },
|
|
663
|
-
price: { source: '$.price', resolver: 'sdk.parseFloat' },
|
|
664
|
-
currency: { source: '^.currency' }, // Inherit from parent
|
|
665
|
-
},
|
|
666
|
-
},
|
|
667
|
-
},
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
// Custom resolvers
|
|
671
|
-
const customResolvers = {
|
|
672
|
-
'custom.mapOrderType': (value: any) => {
|
|
673
|
-
const mapping: Record<string, string> = {
|
|
674
|
-
online: 'HD',
|
|
675
|
-
store: 'CC',
|
|
676
|
-
};
|
|
677
|
-
return mapping[value] || 'HD';
|
|
678
|
-
},
|
|
679
|
-
|
|
680
|
-
'custom.lookupCustomer': async (value: any, data: any, config: any, helpers: any) => {
|
|
681
|
-
const email = data.customer_email;
|
|
682
|
-
|
|
683
|
-
// Query for existing customer
|
|
684
|
-
const result = await helpers.fluentClient.graphql({
|
|
685
|
-
query: `query GetCustomer($email: String) {
|
|
686
|
-
customers(primaryEmail: $email, first: 1) {
|
|
687
|
-
edges { node { id } }
|
|
688
|
-
}
|
|
689
|
-
}`,
|
|
690
|
-
variables: { email },
|
|
691
|
-
});
|
|
692
|
-
|
|
693
|
-
const existingCustomer = result?.customers?.edges?.[0]?.node;
|
|
694
|
-
|
|
695
|
-
if (existingCustomer) {
|
|
696
|
-
return existingCustomer.id;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// Create new customer
|
|
700
|
-
const createResult = await helpers.fluentClient.graphql({
|
|
701
|
-
query: `mutation CreateCustomer($input: CreateCustomerInput!) {
|
|
702
|
-
createCustomer(input: $input) { id }
|
|
703
|
-
}`,
|
|
704
|
-
variables: {
|
|
705
|
-
input: {
|
|
706
|
-
username: email,
|
|
707
|
-
primaryEmail: email,
|
|
708
|
-
firstName: data.customer_first_name || 'Guest',
|
|
709
|
-
lastName: data.customer_last_name || 'Customer',
|
|
710
|
-
retailer: { id: '2' },
|
|
711
|
-
},
|
|
712
|
-
},
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
return createResult.id;
|
|
716
|
-
},
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
// Webhook handler
|
|
720
|
-
export default async function processJsonOrder(activation: any, log: any, connections: any) {
|
|
721
|
-
try {
|
|
722
|
-
const orderData = activation.body;
|
|
723
|
-
|
|
724
|
-
// Create client
|
|
725
|
-
const client = await createClient({
|
|
726
|
-
connection: connections.fluent_commerce,
|
|
727
|
-
logger: log,
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
// Map data
|
|
731
|
-
const mapper = new UniversalMapper(ORDER_MAPPING, {
|
|
732
|
-
customResolvers,
|
|
733
|
-
});
|
|
734
|
-
|
|
735
|
-
const mapResult = await mapper.map(orderData, {
|
|
736
|
-
fluentClient: client,
|
|
737
|
-
});
|
|
738
|
-
|
|
739
|
-
if (!mapResult.success) {
|
|
740
|
-
throw new Error(`Mapping failed: ${mapResult.errors?.join(', ')}`);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// Execute mutation
|
|
744
|
-
const result = await client.graphql({
|
|
745
|
-
query: `
|
|
746
|
-
mutation CreateOrder($input: CreateOrderInput!) {
|
|
747
|
-
createOrder(input: $input) {
|
|
748
|
-
id
|
|
749
|
-
ref
|
|
750
|
-
status
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
`,
|
|
754
|
-
variables: { input: mapResult.data },
|
|
755
|
-
});
|
|
756
|
-
|
|
757
|
-
log.info('Order created', { orderId: result.id });
|
|
758
|
-
|
|
759
|
-
return {
|
|
760
|
-
status: 200,
|
|
761
|
-
body: {
|
|
762
|
-
success: true,
|
|
763
|
-
orderId: result.id,
|
|
764
|
-
orderRef: result.ref,
|
|
765
|
-
},
|
|
766
|
-
};
|
|
767
|
-
} catch (error: any) {
|
|
768
|
-
log.error('Order processing failed', error);
|
|
769
|
-
|
|
770
|
-
return {
|
|
771
|
-
status: 500,
|
|
772
|
-
body: {
|
|
773
|
-
success: false,
|
|
774
|
-
error: error.message,
|
|
775
|
-
},
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
### Example Payload
|
|
782
|
-
|
|
783
|
-
**Input** (JSON from external system):
|
|
784
|
-
|
|
785
|
-
```json
|
|
786
|
-
{
|
|
787
|
-
"order_id": "ORD-12345",
|
|
788
|
-
"order_type": "online",
|
|
789
|
-
"total": 159.98,
|
|
790
|
-
"currency": "USD",
|
|
791
|
-
"customer_email": "john@example.com",
|
|
792
|
-
"customer_first_name": "John",
|
|
793
|
-
"customer_last_name": "Doe",
|
|
794
|
-
"line_items": [
|
|
795
|
-
{
|
|
796
|
-
"item_id": "1",
|
|
797
|
-
"sku": "SKU-001",
|
|
798
|
-
"qty": 2,
|
|
799
|
-
"price": 79.99
|
|
800
|
-
}
|
|
801
|
-
]
|
|
802
|
-
}
|
|
803
|
-
```
|
|
804
|
-
|
|
805
|
-
**Output** (Fluent GraphQL variables):
|
|
806
|
-
|
|
807
|
-
```json
|
|
808
|
-
{
|
|
809
|
-
"input": {
|
|
810
|
-
"ref": "ORD-12345",
|
|
811
|
-
"type": "HD",
|
|
812
|
-
"totalPrice": 159.98,
|
|
813
|
-
"currency": "USD",
|
|
814
|
-
"retailer": { "id": "2" },
|
|
815
|
-
"customer": { "id": "123456" },
|
|
816
|
-
"items": [
|
|
817
|
-
{
|
|
818
|
-
"ref": "1",
|
|
819
|
-
"productRef": "SKU-001",
|
|
820
|
-
"quantity": 2,
|
|
821
|
-
"price": 79.99,
|
|
822
|
-
"currency": "USD"
|
|
823
|
-
}
|
|
824
|
-
]
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
```
|
|
828
|
-
|
|
829
|
-
---
|
|
830
|
-
|
|
831
|
-
## Error Handling in Real-Time
|
|
832
|
-
|
|
833
|
-
### Error Categories
|
|
834
|
-
|
|
835
|
-
| Error Type | Cause | HTTP Status | Retry? |
|
|
836
|
-
| ------------------------ | -------------------- | ----------- | ------------- |
|
|
837
|
-
| **Validation Error** | Missing/invalid data | 400 | No |
|
|
838
|
-
| **Authentication Error** | Invalid credentials | 401 | No |
|
|
839
|
-
| **Rate Limit** | Too many requests | 429 | Yes (backoff) |
|
|
840
|
-
| **Server Error** | Fluent API down | 500 | Yes |
|
|
841
|
-
| **Timeout** | Processing > 30s | 504 | Yes |
|
|
842
|
-
|
|
843
|
-
### Error Handling Pattern
|
|
844
|
-
|
|
845
|
-
```typescript
|
|
846
|
-
export default async function webhookHandler(activation: any, log: any, connections: any) {
|
|
847
|
-
try {
|
|
848
|
-
// Processing logic...
|
|
849
|
-
} catch (error: any) {
|
|
850
|
-
// Categorize error
|
|
851
|
-
if (error.message?.includes('required field')) {
|
|
852
|
-
// Validation error - don't retry
|
|
853
|
-
log.error('Validation error', { error: error.message });
|
|
854
|
-
return {
|
|
855
|
-
status: 400,
|
|
856
|
-
body: {
|
|
857
|
-
success: false,
|
|
858
|
-
error: 'Validation failed',
|
|
859
|
-
details: error.message,
|
|
860
|
-
},
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
if (error.message?.includes('rate limit')) {
|
|
865
|
-
// Rate limit - retry with backoff
|
|
866
|
-
log.warn('Rate limit hit', { error: error.message });
|
|
867
|
-
return {
|
|
868
|
-
status: 429,
|
|
869
|
-
body: {
|
|
870
|
-
success: false,
|
|
871
|
-
error: 'Rate limit exceeded',
|
|
872
|
-
retryAfter: 60,
|
|
873
|
-
},
|
|
874
|
-
};
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
if (error.message?.includes('timeout')) {
|
|
878
|
-
// Timeout - log and retry
|
|
879
|
-
log.error('Request timeout', { error: error.message });
|
|
880
|
-
return {
|
|
881
|
-
status: 504,
|
|
882
|
-
body: {
|
|
883
|
-
success: false,
|
|
884
|
-
error: 'Request timeout',
|
|
885
|
-
retryable: true,
|
|
886
|
-
},
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
// Unknown error
|
|
891
|
-
log.error('Unexpected error', error);
|
|
892
|
-
return {
|
|
893
|
-
status: 500,
|
|
894
|
-
body: {
|
|
895
|
-
success: false,
|
|
896
|
-
error: 'Internal server error',
|
|
897
|
-
},
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
```
|
|
902
|
-
|
|
903
|
-
### Retry Strategy
|
|
904
|
-
|
|
905
|
-
```typescript
|
|
906
|
-
/**
|
|
907
|
-
* Exponential backoff retry wrapper
|
|
908
|
-
*/
|
|
909
|
-
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3, initialDelay = 1000): Promise<T> {
|
|
910
|
-
let lastError: Error;
|
|
911
|
-
|
|
912
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
913
|
-
try {
|
|
914
|
-
return await fn();
|
|
915
|
-
} catch (error: any) {
|
|
916
|
-
lastError = error;
|
|
917
|
-
|
|
918
|
-
// Don't retry validation errors
|
|
919
|
-
if (error.message?.includes('required field')) {
|
|
920
|
-
throw error;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
// Calculate backoff delay
|
|
924
|
-
const delay = initialDelay * Math.pow(2, attempt);
|
|
925
|
-
|
|
926
|
-
console.log(`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`);
|
|
927
|
-
|
|
928
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
throw lastError!;
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
// Usage
|
|
936
|
-
const result = await withRetry(() => client.graphql({ query, variables }));
|
|
937
|
-
```
|
|
938
|
-
|
|
939
|
-
### Logging for Debugging
|
|
940
|
-
|
|
941
|
-
```typescript
|
|
942
|
-
// Structured logging pattern
|
|
943
|
-
try {
|
|
944
|
-
log.info('Processing webhook', {
|
|
945
|
-
eventType: activation.body.type,
|
|
946
|
-
orderRef: activation.body.order_id,
|
|
947
|
-
});
|
|
948
|
-
|
|
949
|
-
const result = await client.graphql({ query, variables });
|
|
950
|
-
|
|
951
|
-
log.info('Order created successfully', {
|
|
952
|
-
orderId: result.id,
|
|
953
|
-
orderRef: result.ref,
|
|
954
|
-
processingTime: Date.now() - startTime,
|
|
955
|
-
});
|
|
956
|
-
} catch (error: any) {
|
|
957
|
-
log.error('Order creation failed', {
|
|
958
|
-
error: error.message,
|
|
959
|
-
stack: error.stack,
|
|
960
|
-
orderRef: activation.body.order_id,
|
|
961
|
-
input: JSON.stringify(variables), // Be careful with PII
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
```
|
|
965
|
-
|
|
966
|
-
---
|
|
967
|
-
|
|
968
|
-
## Next Steps
|
|
969
|
-
|
|
970
|
-
Now that you understand real-time processing fundamentals, you're ready to learn about batch processing for high-volume scenarios!
|
|
971
|
-
|
|
972
|
-
**Continue to:** [Module 2: Batch Processing →](./integration-patterns-02-batch-processing.md)
|
|
973
|
-
|
|
974
|
-
Or explore:
|
|
975
|
-
|
|
976
|
-
- [Module 4: Webhook Patterns](./integration-patterns-04-webhook-patterns.md) - Advanced webhook handling
|
|
977
|
-
- [Module 5: Error Handling](./integration-patterns-05-error-handling.md) - Resilience strategies
|
|
978
|
-
- [Complete Example: XML Order Ingestion](../../../01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md)
|
|
979
|
-
|
|
980
|
-
---
|
|
981
|
-
|
|
982
|
-
## Additional Resources
|
|
983
|
-
|
|
984
|
-
- [Fluent GraphQL API Documentation](https://docs.fluentcommerce.com/)
|
|
985
|
-
- [Universal Mapping Guide](../../../02-CORE-GUIDES/mapping/mapping-readme.md)
|
|
986
|
-
- [GraphQL Mutation Mapper API](../../../02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md)
|
|
987
|
-
- [Versori Webhook Patterns](../../../04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md)
|
|
988
|
-
|
|
989
|
-
---
|
|
990
|
-
|
|
991
|
-
[← Back to Index](../integration-patterns-readme.md) | [Next: Batch Processing →](./integration-patterns-02-batch-processing.md)
|
|
1
|
+
# Module 1: Real-Time Processing
|
|
2
|
+
|
|
3
|
+
> **Learning Objective:** Understand real-time event processing patterns, when to use them, and how to implement immediate event handling with the Fluent Connect SDK.
|
|
4
|
+
>
|
|
5
|
+
> **Level:** Beginner
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [What is Real-Time Processing?](#what-is-real-time-processing)
|
|
10
|
+
2. [When to Use Real-Time Processing](#when-to-use-real-time-processing)
|
|
11
|
+
3. [Real-Time vs Batch: The Decision](#real-time-vs-batch-the-decision)
|
|
12
|
+
4. [Common Real-Time Use Cases](#common-real-time-use-cases)
|
|
13
|
+
5. [SDK Components for Real-Time Processing](#sdk-components-for-real-time-processing)
|
|
14
|
+
6. [Basic Real-Time Workflow](#basic-real-time-workflow)
|
|
15
|
+
7. [Real-Time Pattern: Webhook to GraphQL](#real-time-pattern-webhook-to-graphql)
|
|
16
|
+
8. [Error Handling in Real-Time](#error-handling-in-real-time)
|
|
17
|
+
9. [Next Steps](#next-steps)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What is Real-Time Processing?
|
|
22
|
+
|
|
23
|
+
**Real-time processing** means handling events as they occur, with minimal latency between event trigger and completion.
|
|
24
|
+
|
|
25
|
+
### Key Characteristics
|
|
26
|
+
|
|
27
|
+
| Characteristic | Description | Example |
|
|
28
|
+
| ------------------------ | ----------------------------------- | ------------------------------ |
|
|
29
|
+
| **Immediate Trigger** | Event triggers processing instantly | HTTP webhook receives order |
|
|
30
|
+
| **Low Latency** | Processing completes in seconds | Order created within 5 seconds |
|
|
31
|
+
| **Event-Driven** | External events drive execution | SFCC order placement |
|
|
32
|
+
| **Synchronous Response** | Caller waits for result | Webhook returns success/error |
|
|
33
|
+
|
|
34
|
+
### How It Works
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
External Event → Webhook Endpoint → Process Data → Call Fluent API → Return Response
|
|
38
|
+
↓ ↓ ↓ ↓ ↓
|
|
39
|
+
<1 second Parse payload Transform data Create order Success/error
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Visual Flow
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
┌─────────────┐
|
|
46
|
+
│ SFCC Order │ ──① HTTP POST──> ┌──────────────────┐
|
|
47
|
+
│ Placed │ │ Versori Webhook │
|
|
48
|
+
└─────────────┘ │ (Your code) │
|
|
49
|
+
└────────┬─────────┘
|
|
50
|
+
│
|
|
51
|
+
②Parse XML/JSON
|
|
52
|
+
│
|
|
53
|
+
▼
|
|
54
|
+
┌──────────────────┐
|
|
55
|
+
│ GraphQLMutation │
|
|
56
|
+
│ Mapper │
|
|
57
|
+
└────────┬─────────┘
|
|
58
|
+
│
|
|
59
|
+
③Apply field mapping
|
|
60
|
+
│
|
|
61
|
+
▼
|
|
62
|
+
┌──────────────────┐
|
|
63
|
+
│ Fluent Client │
|
|
64
|
+
│ createOrder() │
|
|
65
|
+
└────────┬─────────┘
|
|
66
|
+
│
|
|
67
|
+
④GraphQL mutation
|
|
68
|
+
│
|
|
69
|
+
▼
|
|
70
|
+
┌──────────────────┐
|
|
71
|
+
│ Fluent Commerce │
|
|
72
|
+
│ Order Created │
|
|
73
|
+
└────────┬─────────┘
|
|
74
|
+
│
|
|
75
|
+
⑤Return response
|
|
76
|
+
│
|
|
77
|
+
▼
|
|
78
|
+
┌──────────────────┐
|
|
79
|
+
│ 200 OK │
|
|
80
|
+
│ { orderId } │
|
|
81
|
+
└──────────────────┘
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Total latency**: 2-5 seconds from webhook receipt to Fluent order creation.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## When to Use Real-Time Processing
|
|
89
|
+
|
|
90
|
+
### ✅ Use Real-Time When:
|
|
91
|
+
|
|
92
|
+
| Scenario | Why Real-Time? | SDK Pattern |
|
|
93
|
+
| --------------------- | --------------------------------------- | ------------------------------ |
|
|
94
|
+
| **Order Webhooks** | Customers expect immediate confirmation | Webhook → GraphQL mutation |
|
|
95
|
+
| **Inventory Updates** | Stock levels must be accurate instantly | Webhook → Batch API (single) |
|
|
96
|
+
| **Low Volume** | < 100 events/hour | Simple webhook handler |
|
|
97
|
+
| **Critical Events** | Payment, shipment, cancellation | Immediate processing + logging |
|
|
98
|
+
| **External Triggers** | Third-party systems push data | HTTP endpoint required |
|
|
99
|
+
|
|
100
|
+
### ❌ Avoid Real-Time When:
|
|
101
|
+
|
|
102
|
+
| Scenario | Why Not Real-Time? | Use Instead |
|
|
103
|
+
| ------------------- | -------------------- | --------------------------- |
|
|
104
|
+
| **Large Files** | 10K+ records | Batch processing (Module 2) |
|
|
105
|
+
| **High Volume** | > 1,000 events/hour | Scheduled batch (Module 2) |
|
|
106
|
+
| **Long Processing** | > 30 seconds | Async job queue |
|
|
107
|
+
| **Bulk Operations** | Daily inventory sync | Batch API (Module 2) |
|
|
108
|
+
| **Non-Critical** | Reports, analytics | Scheduled extraction |
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Real-Time vs Batch: The Decision
|
|
113
|
+
|
|
114
|
+
### Volume-Based Decision Matrix
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
Events/Hour │ Pattern
|
|
118
|
+
────────────┼────────────────────────────────
|
|
119
|
+
< 10 │ Real-Time (Webhook)
|
|
120
|
+
10-100 │ Real-Time (Webhook)
|
|
121
|
+
100-500 │ Real-Time OR Micro-batch
|
|
122
|
+
500-1K │ Micro-batch (5-minute windows)
|
|
123
|
+
1K-10K │ Batch (hourly)
|
|
124
|
+
> 10K │ Batch (daily)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Latency Requirements
|
|
128
|
+
|
|
129
|
+
| Requirement | Pattern | Example |
|
|
130
|
+
| --------------- | ------------ | -------------------- |
|
|
131
|
+
| **< 5 seconds** | Real-Time | Order confirmation |
|
|
132
|
+
| **< 5 minutes** | Micro-batch | Inventory updates |
|
|
133
|
+
| **< 1 hour** | Hourly batch | Product catalog sync |
|
|
134
|
+
| **< 24 hours** | Daily batch | Full inventory sync |
|
|
135
|
+
|
|
136
|
+
### Example Decisions
|
|
137
|
+
|
|
138
|
+
#### ✅ GOOD: Real-Time for Order Webhooks
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// Scenario: SFCC sends 20-50 orders/hour
|
|
142
|
+
// Requirement: Orders visible in Fluent within 5 seconds
|
|
143
|
+
// Volume: Low (<100/hour)
|
|
144
|
+
// Pattern: Real-time webhook
|
|
145
|
+
|
|
146
|
+
export default async function processOrder(ctx) {
|
|
147
|
+
const orderData = ctx.activation.body;
|
|
148
|
+
const client = await createClient(ctx); // Auto-detects Versori context
|
|
149
|
+
|
|
150
|
+
// Immediate processing
|
|
151
|
+
const result = await client.graphql({
|
|
152
|
+
query: CREATE_ORDER_MUTATION,
|
|
153
|
+
variables: { input: mapOrderData(orderData) },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return { status: 200, body: { orderId: result.id } };
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Why this works**: Low volume + low latency requirement = perfect for real-time.
|
|
161
|
+
|
|
162
|
+
#### ❌ WRONG: Real-Time for Bulk Inventory
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// ❌ BAD: Trying to process 50K inventory records via webhooks
|
|
166
|
+
export default async function processInventory(activation, log, connections) {
|
|
167
|
+
const inventoryFile = activation.body.fileUrl; // 50K records
|
|
168
|
+
|
|
169
|
+
// This will timeout! Each webhook has 30-second limit
|
|
170
|
+
for (const record of records) {
|
|
171
|
+
await client.graphql({ ... }); // 50K sequential API calls = HOURS
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Why this fails**:
|
|
177
|
+
|
|
178
|
+
- Webhook timeout (30-60 seconds)
|
|
179
|
+
- 50K sequential API calls = 1-2 hours
|
|
180
|
+
- No progress tracking
|
|
181
|
+
- No error recovery
|
|
182
|
+
|
|
183
|
+
**✅ Better approach**: Use Batch API (Module 2)
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Process 50K records in 5-10 minutes via Batch API
|
|
187
|
+
const job = await client.createJob({ name: 'inventory-update' });
|
|
188
|
+
const batch = await client.sendBatch(job.id, { entities: records });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Common Real-Time Use Cases
|
|
194
|
+
|
|
195
|
+
### Use Case 1: SFCC Order Creation
|
|
196
|
+
|
|
197
|
+
**Trigger**: Salesforce Commerce Cloud sends order XML via webhook
|
|
198
|
+
**Processing Time**: 3-5 seconds
|
|
199
|
+
**Volume**: 10-100 orders/hour
|
|
200
|
+
**SDK Pattern**: `GraphQLMutationMapper` + `createClient`
|
|
201
|
+
|
|
202
|
+
**Complete implementation**: [XML Order Ingestion Guide](../../../01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md)
|
|
203
|
+
|
|
204
|
+
### Use Case 2: Inventory Adjustment (Single SKU)
|
|
205
|
+
|
|
206
|
+
**Trigger**: Warehouse system reports damage/theft
|
|
207
|
+
**Processing Time**: 1-2 seconds
|
|
208
|
+
**Volume**: < 10 events/hour
|
|
209
|
+
**SDK Pattern**: Direct GraphQL mutation
|
|
210
|
+
|
|
211
|
+
**Example**:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
215
|
+
|
|
216
|
+
export default async function adjustInventory(activation: any, log: any, connections: any) {
|
|
217
|
+
const { sku, location, quantity, reason } = activation.body;
|
|
218
|
+
|
|
219
|
+
const client = await createClient({
|
|
220
|
+
connection: connections.fluent_commerce,
|
|
221
|
+
logger: log,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const result = await client.graphql({
|
|
225
|
+
query: `
|
|
226
|
+
mutation UpdateInventory($input: UpdateInventoryQuantityInput!) {
|
|
227
|
+
updateInventoryQuantity(input: $input) {
|
|
228
|
+
id
|
|
229
|
+
ref
|
|
230
|
+
quantity
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
`,
|
|
234
|
+
variables: {
|
|
235
|
+
input: {
|
|
236
|
+
ref: `${sku}-${location}`,
|
|
237
|
+
quantity: quantity,
|
|
238
|
+
attributes: [{ name: 'adjustmentReason', type: 'String', value: reason }],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
log.info('Inventory adjusted', { sku, location, newQuantity: result.quantity });
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
status: 200,
|
|
247
|
+
body: { success: true, inventoryId: result.id },
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Use Case 3: Order Status Update (External System → Fluent)
|
|
253
|
+
|
|
254
|
+
**Trigger**: Shipping carrier sends delivery confirmation
|
|
255
|
+
**Processing Time**: 2-3 seconds
|
|
256
|
+
**Volume**: 50-200 events/hour
|
|
257
|
+
**SDK Pattern**: GraphQL mutation with event
|
|
258
|
+
|
|
259
|
+
**Example**:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
263
|
+
|
|
264
|
+
export default async function updateOrderStatus(activation: any, log: any, connections: any) {
|
|
265
|
+
const { orderRef, status, trackingNumber, carrier } = activation.body;
|
|
266
|
+
|
|
267
|
+
const client = await createClient({
|
|
268
|
+
connection: connections.fluent_commerce,
|
|
269
|
+
logger: log,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Send event to Fluent workflow
|
|
273
|
+
const result = await client.graphql({
|
|
274
|
+
query: `
|
|
275
|
+
mutation SendEvent($input: EventInput!) {
|
|
276
|
+
sendEvent(input: $input) {
|
|
277
|
+
id
|
|
278
|
+
status
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
`,
|
|
282
|
+
variables: {
|
|
283
|
+
input: {
|
|
284
|
+
entityRef: orderRef,
|
|
285
|
+
entityType: 'ORDER',
|
|
286
|
+
name: 'carrier.tracking.update',
|
|
287
|
+
attributes: [
|
|
288
|
+
{ name: 'trackingNumber', type: 'String', value: trackingNumber },
|
|
289
|
+
{ name: 'carrier', type: 'String', value: carrier },
|
|
290
|
+
{ name: 'status', type: 'String', value: status },
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
status: 200,
|
|
298
|
+
body: { success: true, eventId: result.id },
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## SDK Components for Real-Time Processing
|
|
306
|
+
|
|
307
|
+
### Component 1: `createClient()`
|
|
308
|
+
|
|
309
|
+
**Purpose**: Create authenticated Fluent API client
|
|
310
|
+
|
|
311
|
+
**Usage**:
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
315
|
+
|
|
316
|
+
// Versori platform (recommended)
|
|
317
|
+
const client = await createClient({
|
|
318
|
+
connection: connections.fluent_commerce,
|
|
319
|
+
logger: log,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Standalone (Node.js/Deno)
|
|
323
|
+
const client = await createClient({
|
|
324
|
+
config: {
|
|
325
|
+
baseUrl: 'https://api.fluentcommerce.com',
|
|
326
|
+
clientId: process.env.FLUENT_CLIENT_ID,
|
|
327
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET,
|
|
328
|
+
retailerId: process.env.FLUENT_RETAILER_ID,
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**What it does**:
|
|
334
|
+
|
|
335
|
+
- Extracts OAuth2 credentials from connection
|
|
336
|
+
- Manages token refresh automatically
|
|
337
|
+
- Returns ready-to-use `FluentClient` instance
|
|
338
|
+
|
|
339
|
+
### Component 2: `GraphQLMutationMapper`
|
|
340
|
+
|
|
341
|
+
**Purpose**: Transform external data (XML/JSON) to Fluent GraphQL mutations
|
|
342
|
+
|
|
343
|
+
**Usage**:
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { GraphQLMutationMapper } from '@fluentcommerce/fc-connect-sdk';
|
|
347
|
+
|
|
348
|
+
const mapper = new GraphQLMutationMapper(mappingConfig, logger, { fluentClient: client });
|
|
349
|
+
|
|
350
|
+
// Process with nodes (for nested/escaped XML)
|
|
351
|
+
const result = await mapper.mapWithNodes(orderData, customResolvers, context);
|
|
352
|
+
|
|
353
|
+
// Check success (errors are returned, not thrown)
|
|
354
|
+
if (!result.success) {
|
|
355
|
+
console.error('Mapping failed:', result.errors);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Execute (query is auto-generated in result)
|
|
360
|
+
const mutationResult = await client.graphql({
|
|
361
|
+
query: result.query,
|
|
362
|
+
variables: result.variables, // ✅ Use variables (wrapped if fields pattern)
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Key features**:
|
|
367
|
+
|
|
368
|
+
- **Nodes**: Extract and parse nested XML/JSON
|
|
369
|
+
- **Field Mapping**: Transform source fields to target schema
|
|
370
|
+
- **Custom Resolvers**: Apply business logic during transformation
|
|
371
|
+
- **Validation**: Checks required fields and types
|
|
372
|
+
|
|
373
|
+
**Complete guide**: [GraphQL Mutation Mapper](../../../02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md)
|
|
374
|
+
|
|
375
|
+
### Component 3: `FluentClient` Methods
|
|
376
|
+
|
|
377
|
+
**Available methods**:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Query (returns data only)
|
|
381
|
+
const orders = await client.graphql({
|
|
382
|
+
query: GET_ORDERS_QUERY,
|
|
383
|
+
variables: { status: 'PENDING' },
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Mutation (returns data only)
|
|
387
|
+
const created = await client.graphql({
|
|
388
|
+
query: CREATE_ORDER_MUTATION,
|
|
389
|
+
variables: { input: orderData },
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Advanced (with pagination, progress, extensions)
|
|
393
|
+
const result = await client.graphql({
|
|
394
|
+
query: GET_ALL_ORDERS,
|
|
395
|
+
variables: { first: 100 },
|
|
396
|
+
pagination: {
|
|
397
|
+
maxPages: 50,
|
|
398
|
+
onProgress: (page, total) => log.info(`Page ${page}/${total}`),
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**When to use each**:
|
|
404
|
+
|
|
405
|
+
- `query()` - Simple queries without pagination
|
|
406
|
+
- `mutate()` - Create/update operations
|
|
407
|
+
- `graphql()` - Auto-pagination, progress tracking, extensions
|
|
408
|
+
|
|
409
|
+
### Component 4: `UniversalMapper`
|
|
410
|
+
|
|
411
|
+
**Purpose**: Field-level transformation for any data format (CSV, JSON, XML, Parquet)
|
|
412
|
+
|
|
413
|
+
**Usage**:
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
|
|
417
|
+
|
|
418
|
+
const mappingConfig = {
|
|
419
|
+
fields: {
|
|
420
|
+
skuRef: { source: 'sku_id', required: true },
|
|
421
|
+
qty: { source: 'quantity', resolver: 'sdk.parseInt' },
|
|
422
|
+
expectedOn: { source: 'date', resolver: 'sdk.formatDate' },
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const mapper = new UniversalMapper(mappingConfig);
|
|
427
|
+
const result = await mapper.map(sourceData);
|
|
428
|
+
|
|
429
|
+
if (result.success) {
|
|
430
|
+
console.log('Mapped data:', result.data);
|
|
431
|
+
} else {
|
|
432
|
+
console.error('Mapping errors:', result.errors);
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Built-in resolvers**:
|
|
437
|
+
|
|
438
|
+
- `sdk.parseInt`, `sdk.parseFloat` - Type conversion
|
|
439
|
+
- `sdk.formatDate`, `sdk.parseDate` - Date handling
|
|
440
|
+
- `sdk.uppercase`, `sdk.lowercase`, `sdk.trim` - String manipulation
|
|
441
|
+
- `sdk.boolean`, `sdk.toJson`, `sdk.parseJson` - Type casting
|
|
442
|
+
|
|
443
|
+
**Complete guide**: [Universal Mapping](../../../02-CORE-GUIDES/mapping/mapping-readme.md)
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Basic Real-Time Workflow
|
|
448
|
+
|
|
449
|
+
### Workflow Pattern
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
/**
|
|
453
|
+
* Basic Real-Time Webhook Pattern
|
|
454
|
+
*
|
|
455
|
+
* Steps:
|
|
456
|
+
* 1. Receive webhook payload
|
|
457
|
+
* 2. Validate and parse data
|
|
458
|
+
* 3. Transform to Fluent schema
|
|
459
|
+
* 4. Execute GraphQL mutation
|
|
460
|
+
* 5. Return response
|
|
461
|
+
*/
|
|
462
|
+
|
|
463
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
464
|
+
|
|
465
|
+
export default async function webhookHandler(activation: any, log: any, connections: any) {
|
|
466
|
+
try {
|
|
467
|
+
// Step 1: Extract payload
|
|
468
|
+
const payload = activation.body;
|
|
469
|
+
log.info('Received webhook', { payload });
|
|
470
|
+
|
|
471
|
+
// Step 2: Validate required fields
|
|
472
|
+
if (!payload.orderRef) {
|
|
473
|
+
throw new Error('Missing required field: orderRef');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Step 3: Create Fluent client
|
|
477
|
+
const client = await createClient({
|
|
478
|
+
connection: connections.fluent_commerce,
|
|
479
|
+
logger: log,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Step 4: Transform data
|
|
483
|
+
const fluentInput = {
|
|
484
|
+
ref: payload.orderRef,
|
|
485
|
+
type: 'HD',
|
|
486
|
+
totalPrice: parseFloat(payload.total),
|
|
487
|
+
currency: payload.currency || 'USD',
|
|
488
|
+
retailer: { id: '2' },
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
// Step 5: Execute mutation
|
|
492
|
+
const result = await client.graphql({
|
|
493
|
+
query: `
|
|
494
|
+
mutation CreateOrder($input: CreateOrderInput!) {
|
|
495
|
+
createOrder(input: $input) {
|
|
496
|
+
id
|
|
497
|
+
ref
|
|
498
|
+
status
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
`,
|
|
502
|
+
variables: { input: fluentInput },
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
log.info('Order created', { orderId: result.id });
|
|
506
|
+
|
|
507
|
+
// Step 6: Return success
|
|
508
|
+
return {
|
|
509
|
+
status: 200,
|
|
510
|
+
body: {
|
|
511
|
+
success: true,
|
|
512
|
+
orderId: result.id,
|
|
513
|
+
orderRef: result.ref,
|
|
514
|
+
},
|
|
515
|
+
};
|
|
516
|
+
} catch (error: any) {
|
|
517
|
+
log.error('Webhook processing failed', error);
|
|
518
|
+
|
|
519
|
+
// Step 7: Return error
|
|
520
|
+
return {
|
|
521
|
+
status: 500,
|
|
522
|
+
body: {
|
|
523
|
+
success: false,
|
|
524
|
+
error: error.message,
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Key Steps Explained
|
|
532
|
+
|
|
533
|
+
#### Step 1: Extract Payload
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
// Versori automatically parses JSON/XML
|
|
537
|
+
const payload = activation.body;
|
|
538
|
+
|
|
539
|
+
// For raw strings, use parsers
|
|
540
|
+
import { XMLParserService } from '@fluentcommerce/fc-connect-sdk';
|
|
541
|
+
const parser = new XMLParserService();
|
|
542
|
+
const payload = await parser.parse(activation.body);
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### Step 2: Validation
|
|
546
|
+
|
|
547
|
+
```typescript
|
|
548
|
+
// Required field validation
|
|
549
|
+
const requiredFields = ['orderRef', 'total', 'items'];
|
|
550
|
+
for (const field of requiredFields) {
|
|
551
|
+
if (!payload[field]) {
|
|
552
|
+
throw new Error(`Missing required field: ${field}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Type validation
|
|
557
|
+
if (typeof payload.total !== 'number') {
|
|
558
|
+
throw new Error('total must be a number');
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
#### Step 3: Client Creation
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
// ALWAYS use createClient() - it auto-detects Versori vs standalone
|
|
566
|
+
const client = await createClient({
|
|
567
|
+
connection: connections.fluent_commerce,
|
|
568
|
+
logger: log,
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
#### Step 4: Data Transformation
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
// Simple mapping
|
|
576
|
+
const fluentInput = {
|
|
577
|
+
ref: payload.orderRef,
|
|
578
|
+
type: mapOrderType(payload.orderType),
|
|
579
|
+
totalPrice: parseFloat(payload.total),
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
// Complex mapping (use UniversalMapper or GraphQLMutationMapper)
|
|
583
|
+
const mapper = new UniversalMapper(mappingConfig);
|
|
584
|
+
const result = await mapper.map(payload);
|
|
585
|
+
const fluentInput = result.data;
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
#### Step 5: Execute Mutation
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
// Use mutate() for simple operations
|
|
592
|
+
const result = await client.graphql({
|
|
593
|
+
query: mutation,
|
|
594
|
+
variables: { input: fluentInput },
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// Check for errors
|
|
598
|
+
if (!result || !result.id) {
|
|
599
|
+
throw new Error('Mutation failed: No ID returned');
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
#### Step 6-7: Return Response
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
// Versori expects { status, body }
|
|
607
|
+
return {
|
|
608
|
+
status: 200,
|
|
609
|
+
body: { success: true, orderId: result.id },
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// Error response
|
|
613
|
+
return {
|
|
614
|
+
status: 500,
|
|
615
|
+
body: { success: false, error: error.message },
|
|
616
|
+
};
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## Real-Time Pattern: Webhook to GraphQL
|
|
622
|
+
|
|
623
|
+
### Pattern Overview
|
|
624
|
+
|
|
625
|
+
**Purpose**: Transform external webhook data to Fluent GraphQL mutations
|
|
626
|
+
|
|
627
|
+
**Flow**:
|
|
628
|
+
|
|
629
|
+
```
|
|
630
|
+
Webhook Payload → Parse → Map → Validate → Execute → Response
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Complete Implementation
|
|
634
|
+
|
|
635
|
+
See **[XML Order Ingestion](../../../01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md)** for production-ready implementation.
|
|
636
|
+
|
|
637
|
+
### Quick Example: JSON Order Webhook
|
|
638
|
+
|
|
639
|
+
```typescript
|
|
640
|
+
/**
|
|
641
|
+
* JSON Order Webhook → Fluent Order
|
|
642
|
+
*
|
|
643
|
+
* External system sends JSON order data via POST
|
|
644
|
+
*/
|
|
645
|
+
|
|
646
|
+
import { createClient, UniversalMapper } from '@fluentcommerce/fc-connect-sdk';
|
|
647
|
+
|
|
648
|
+
// Mapping configuration
|
|
649
|
+
const ORDER_MAPPING = {
|
|
650
|
+
fields: {
|
|
651
|
+
ref: { source: 'order_id', required: true },
|
|
652
|
+
type: { source: 'order_type', resolver: 'custom.mapOrderType' },
|
|
653
|
+
totalPrice: { source: 'total', resolver: 'sdk.parseFloat' },
|
|
654
|
+
currency: { source: 'currency', defaultValue: 'USD' },
|
|
655
|
+
'retailer.id': { value: '2' },
|
|
656
|
+
'customer.id': { resolver: 'custom.lookupCustomer' },
|
|
657
|
+
'items[]': {
|
|
658
|
+
source: 'line_items',
|
|
659
|
+
fields: {
|
|
660
|
+
ref: { source: '$.item_id', resolver: 'sdk.toString' },
|
|
661
|
+
productRef: { source: '$.sku', required: true },
|
|
662
|
+
quantity: { source: '$.qty', resolver: 'sdk.parseInt' },
|
|
663
|
+
price: { source: '$.price', resolver: 'sdk.parseFloat' },
|
|
664
|
+
currency: { source: '^.currency' }, // Inherit from parent
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
// Custom resolvers
|
|
671
|
+
const customResolvers = {
|
|
672
|
+
'custom.mapOrderType': (value: any) => {
|
|
673
|
+
const mapping: Record<string, string> = {
|
|
674
|
+
online: 'HD',
|
|
675
|
+
store: 'CC',
|
|
676
|
+
};
|
|
677
|
+
return mapping[value] || 'HD';
|
|
678
|
+
},
|
|
679
|
+
|
|
680
|
+
'custom.lookupCustomer': async (value: any, data: any, config: any, helpers: any) => {
|
|
681
|
+
const email = data.customer_email;
|
|
682
|
+
|
|
683
|
+
// Query for existing customer
|
|
684
|
+
const result = await helpers.fluentClient.graphql({
|
|
685
|
+
query: `query GetCustomer($email: String) {
|
|
686
|
+
customers(primaryEmail: $email, first: 1) {
|
|
687
|
+
edges { node { id } }
|
|
688
|
+
}
|
|
689
|
+
}`,
|
|
690
|
+
variables: { email },
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
const existingCustomer = result?.customers?.edges?.[0]?.node;
|
|
694
|
+
|
|
695
|
+
if (existingCustomer) {
|
|
696
|
+
return existingCustomer.id;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Create new customer
|
|
700
|
+
const createResult = await helpers.fluentClient.graphql({
|
|
701
|
+
query: `mutation CreateCustomer($input: CreateCustomerInput!) {
|
|
702
|
+
createCustomer(input: $input) { id }
|
|
703
|
+
}`,
|
|
704
|
+
variables: {
|
|
705
|
+
input: {
|
|
706
|
+
username: email,
|
|
707
|
+
primaryEmail: email,
|
|
708
|
+
firstName: data.customer_first_name || 'Guest',
|
|
709
|
+
lastName: data.customer_last_name || 'Customer',
|
|
710
|
+
retailer: { id: '2' },
|
|
711
|
+
},
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
return createResult.id;
|
|
716
|
+
},
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
// Webhook handler
|
|
720
|
+
export default async function processJsonOrder(activation: any, log: any, connections: any) {
|
|
721
|
+
try {
|
|
722
|
+
const orderData = activation.body;
|
|
723
|
+
|
|
724
|
+
// Create client
|
|
725
|
+
const client = await createClient({
|
|
726
|
+
connection: connections.fluent_commerce,
|
|
727
|
+
logger: log,
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
// Map data
|
|
731
|
+
const mapper = new UniversalMapper(ORDER_MAPPING, {
|
|
732
|
+
customResolvers,
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
const mapResult = await mapper.map(orderData, {
|
|
736
|
+
fluentClient: client,
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
if (!mapResult.success) {
|
|
740
|
+
throw new Error(`Mapping failed: ${mapResult.errors?.join(', ')}`);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// Execute mutation
|
|
744
|
+
const result = await client.graphql({
|
|
745
|
+
query: `
|
|
746
|
+
mutation CreateOrder($input: CreateOrderInput!) {
|
|
747
|
+
createOrder(input: $input) {
|
|
748
|
+
id
|
|
749
|
+
ref
|
|
750
|
+
status
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
`,
|
|
754
|
+
variables: { input: mapResult.data },
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
log.info('Order created', { orderId: result.id });
|
|
758
|
+
|
|
759
|
+
return {
|
|
760
|
+
status: 200,
|
|
761
|
+
body: {
|
|
762
|
+
success: true,
|
|
763
|
+
orderId: result.id,
|
|
764
|
+
orderRef: result.ref,
|
|
765
|
+
},
|
|
766
|
+
};
|
|
767
|
+
} catch (error: any) {
|
|
768
|
+
log.error('Order processing failed', error);
|
|
769
|
+
|
|
770
|
+
return {
|
|
771
|
+
status: 500,
|
|
772
|
+
body: {
|
|
773
|
+
success: false,
|
|
774
|
+
error: error.message,
|
|
775
|
+
},
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### Example Payload
|
|
782
|
+
|
|
783
|
+
**Input** (JSON from external system):
|
|
784
|
+
|
|
785
|
+
```json
|
|
786
|
+
{
|
|
787
|
+
"order_id": "ORD-12345",
|
|
788
|
+
"order_type": "online",
|
|
789
|
+
"total": 159.98,
|
|
790
|
+
"currency": "USD",
|
|
791
|
+
"customer_email": "john@example.com",
|
|
792
|
+
"customer_first_name": "John",
|
|
793
|
+
"customer_last_name": "Doe",
|
|
794
|
+
"line_items": [
|
|
795
|
+
{
|
|
796
|
+
"item_id": "1",
|
|
797
|
+
"sku": "SKU-001",
|
|
798
|
+
"qty": 2,
|
|
799
|
+
"price": 79.99
|
|
800
|
+
}
|
|
801
|
+
]
|
|
802
|
+
}
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
**Output** (Fluent GraphQL variables):
|
|
806
|
+
|
|
807
|
+
```json
|
|
808
|
+
{
|
|
809
|
+
"input": {
|
|
810
|
+
"ref": "ORD-12345",
|
|
811
|
+
"type": "HD",
|
|
812
|
+
"totalPrice": 159.98,
|
|
813
|
+
"currency": "USD",
|
|
814
|
+
"retailer": { "id": "2" },
|
|
815
|
+
"customer": { "id": "123456" },
|
|
816
|
+
"items": [
|
|
817
|
+
{
|
|
818
|
+
"ref": "1",
|
|
819
|
+
"productRef": "SKU-001",
|
|
820
|
+
"quantity": 2,
|
|
821
|
+
"price": 79.99,
|
|
822
|
+
"currency": "USD"
|
|
823
|
+
}
|
|
824
|
+
]
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## Error Handling in Real-Time
|
|
832
|
+
|
|
833
|
+
### Error Categories
|
|
834
|
+
|
|
835
|
+
| Error Type | Cause | HTTP Status | Retry? |
|
|
836
|
+
| ------------------------ | -------------------- | ----------- | ------------- |
|
|
837
|
+
| **Validation Error** | Missing/invalid data | 400 | No |
|
|
838
|
+
| **Authentication Error** | Invalid credentials | 401 | No |
|
|
839
|
+
| **Rate Limit** | Too many requests | 429 | Yes (backoff) |
|
|
840
|
+
| **Server Error** | Fluent API down | 500 | Yes |
|
|
841
|
+
| **Timeout** | Processing > 30s | 504 | Yes |
|
|
842
|
+
|
|
843
|
+
### Error Handling Pattern
|
|
844
|
+
|
|
845
|
+
```typescript
|
|
846
|
+
export default async function webhookHandler(activation: any, log: any, connections: any) {
|
|
847
|
+
try {
|
|
848
|
+
// Processing logic...
|
|
849
|
+
} catch (error: any) {
|
|
850
|
+
// Categorize error
|
|
851
|
+
if (error.message?.includes('required field')) {
|
|
852
|
+
// Validation error - don't retry
|
|
853
|
+
log.error('Validation error', { error: error.message });
|
|
854
|
+
return {
|
|
855
|
+
status: 400,
|
|
856
|
+
body: {
|
|
857
|
+
success: false,
|
|
858
|
+
error: 'Validation failed',
|
|
859
|
+
details: error.message,
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (error.message?.includes('rate limit')) {
|
|
865
|
+
// Rate limit - retry with backoff
|
|
866
|
+
log.warn('Rate limit hit', { error: error.message });
|
|
867
|
+
return {
|
|
868
|
+
status: 429,
|
|
869
|
+
body: {
|
|
870
|
+
success: false,
|
|
871
|
+
error: 'Rate limit exceeded',
|
|
872
|
+
retryAfter: 60,
|
|
873
|
+
},
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (error.message?.includes('timeout')) {
|
|
878
|
+
// Timeout - log and retry
|
|
879
|
+
log.error('Request timeout', { error: error.message });
|
|
880
|
+
return {
|
|
881
|
+
status: 504,
|
|
882
|
+
body: {
|
|
883
|
+
success: false,
|
|
884
|
+
error: 'Request timeout',
|
|
885
|
+
retryable: true,
|
|
886
|
+
},
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Unknown error
|
|
891
|
+
log.error('Unexpected error', error);
|
|
892
|
+
return {
|
|
893
|
+
status: 500,
|
|
894
|
+
body: {
|
|
895
|
+
success: false,
|
|
896
|
+
error: 'Internal server error',
|
|
897
|
+
},
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
### Retry Strategy
|
|
904
|
+
|
|
905
|
+
```typescript
|
|
906
|
+
/**
|
|
907
|
+
* Exponential backoff retry wrapper
|
|
908
|
+
*/
|
|
909
|
+
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3, initialDelay = 1000): Promise<T> {
|
|
910
|
+
let lastError: Error;
|
|
911
|
+
|
|
912
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
913
|
+
try {
|
|
914
|
+
return await fn();
|
|
915
|
+
} catch (error: any) {
|
|
916
|
+
lastError = error;
|
|
917
|
+
|
|
918
|
+
// Don't retry validation errors
|
|
919
|
+
if (error.message?.includes('required field')) {
|
|
920
|
+
throw error;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Calculate backoff delay
|
|
924
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
925
|
+
|
|
926
|
+
console.log(`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`);
|
|
927
|
+
|
|
928
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
throw lastError!;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Usage
|
|
936
|
+
const result = await withRetry(() => client.graphql({ query, variables }));
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
### Logging for Debugging
|
|
940
|
+
|
|
941
|
+
```typescript
|
|
942
|
+
// Structured logging pattern
|
|
943
|
+
try {
|
|
944
|
+
log.info('Processing webhook', {
|
|
945
|
+
eventType: activation.body.type,
|
|
946
|
+
orderRef: activation.body.order_id,
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
const result = await client.graphql({ query, variables });
|
|
950
|
+
|
|
951
|
+
log.info('Order created successfully', {
|
|
952
|
+
orderId: result.id,
|
|
953
|
+
orderRef: result.ref,
|
|
954
|
+
processingTime: Date.now() - startTime,
|
|
955
|
+
});
|
|
956
|
+
} catch (error: any) {
|
|
957
|
+
log.error('Order creation failed', {
|
|
958
|
+
error: error.message,
|
|
959
|
+
stack: error.stack,
|
|
960
|
+
orderRef: activation.body.order_id,
|
|
961
|
+
input: JSON.stringify(variables), // Be careful with PII
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
---
|
|
967
|
+
|
|
968
|
+
## Next Steps
|
|
969
|
+
|
|
970
|
+
Now that you understand real-time processing fundamentals, you're ready to learn about batch processing for high-volume scenarios!
|
|
971
|
+
|
|
972
|
+
**Continue to:** [Module 2: Batch Processing →](./integration-patterns-02-batch-processing.md)
|
|
973
|
+
|
|
974
|
+
Or explore:
|
|
975
|
+
|
|
976
|
+
- [Module 4: Webhook Patterns](./integration-patterns-04-webhook-patterns.md) - Advanced webhook handling
|
|
977
|
+
- [Module 5: Error Handling](./integration-patterns-05-error-handling.md) - Resilience strategies
|
|
978
|
+
- [Complete Example: XML Order Ingestion](../../../01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md)
|
|
979
|
+
|
|
980
|
+
---
|
|
981
|
+
|
|
982
|
+
## Additional Resources
|
|
983
|
+
|
|
984
|
+
- [Fluent GraphQL API Documentation](https://docs.fluentcommerce.com/)
|
|
985
|
+
- [Universal Mapping Guide](../../../02-CORE-GUIDES/mapping/mapping-readme.md)
|
|
986
|
+
- [GraphQL Mutation Mapper API](../../../02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md)
|
|
987
|
+
- [Versori Webhook Patterns](../../../04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md)
|
|
988
|
+
|
|
989
|
+
---
|
|
990
|
+
|
|
991
|
+
[← Back to Index](../integration-patterns-readme.md) | [Next: Batch Processing →](./integration-patterns-02-batch-processing.md)
|