@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +11 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/clients/fluent-client.js +13 -6
- 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/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 -520
- 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
- package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
|
@@ -1,1170 +1,1170 @@
|
|
|
1
|
-
---
|
|
2
|
-
template_id: tpl-ingest-payload-xml-to-order-cancel-event
|
|
3
|
-
canonical_filename: template-ingestion-payload-xml-order-cancel-event.md
|
|
4
|
-
sdk_version: latest
|
|
5
|
-
runtime: versori
|
|
6
|
-
direction: ingestion
|
|
7
|
-
source: payload-xml
|
|
8
|
-
destination: fluent-event-api
|
|
9
|
-
entity: order
|
|
10
|
-
format: xml
|
|
11
|
-
logging: versori
|
|
12
|
-
status: stable
|
|
13
|
-
features:
|
|
14
|
-
- direct-payload-processing
|
|
15
|
-
- xml-parsing
|
|
16
|
-
- event-api-integration
|
|
17
|
-
- error-handling
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
# Template: Ingestion - Payload XML to Order Cancel Event
|
|
21
|
-
|
|
22
|
-
**SDK Version:** @fluentcommerce/fc-connect-sdk@latest
|
|
23
|
-
**Last Updated:** 2025-01-24
|
|
24
|
-
**Deployment Target:** Versori Platform
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 📋 Implementation Prompt
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
I need a Versori webhook ingestion that:
|
|
32
|
-
|
|
33
|
-
1) Receives XML payload directly in webhook request body
|
|
34
|
-
2) Parses XML to extract order reference (handles Versori $ format for attributes)
|
|
35
|
-
3) Builds OrderCancel event payload with retailerId, name, entityRef, entityType
|
|
36
|
-
4) Sends event to Fluent Commerce Event API (async)
|
|
37
|
-
5) Returns success/error response
|
|
38
|
-
6) Uses native Versori log from context
|
|
39
|
-
|
|
40
|
-
Use the loaded docs to fill in SDK specifics and best practices.
|
|
41
|
-
Keep the structure identical to the template; only adapt where needed.
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## 📋 Template Overview
|
|
47
|
-
|
|
48
|
-
This connector runs on the Versori platform. It receives XML payloads directly via webhook, extracts the order reference, and sends OrderCancel events to Fluent Commerce Event API. Most operational settings (Fluent account/connection) are configured via activation variables.
|
|
49
|
-
|
|
50
|
-
### What This Template Does
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
┌────────────────────────────────────────────────────────────────┐
|
|
54
|
-
│ INGESTION WORKFLOW │
|
|
55
|
-
└────────────────────────────────────────────────────────────────┘
|
|
56
|
-
|
|
57
|
-
1. TRIGGER
|
|
58
|
-
└─ Webhook: HTTP POST endpoint receives XML payload
|
|
59
|
-
|
|
60
|
-
2. RECEIVE PAYLOAD
|
|
61
|
-
├─ Extract XML from request body (ctx.data or ctx.request)
|
|
62
|
-
├─ Validate payload structure
|
|
63
|
-
└─ Log incoming request
|
|
64
|
-
|
|
65
|
-
3. PARSE XML
|
|
66
|
-
├─ Parse XML payload (Versori auto-parses with $ format)
|
|
67
|
-
├─ Extract order reference (handles $ for attributes, _ for text)
|
|
68
|
-
└─ Validate required fields
|
|
69
|
-
|
|
70
|
-
4. BUILD EVENT
|
|
71
|
-
├─ Construct OrderCancel event payload
|
|
72
|
-
├─ Set retailerId (from config or payload)
|
|
73
|
-
├─ Set name: "OrderCancel"
|
|
74
|
-
├─ Set entityRef: order reference
|
|
75
|
-
└─ Set entityType: "ORDER"
|
|
76
|
-
|
|
77
|
-
5. SEND EVENT (Event API)
|
|
78
|
-
├─ Send event to Fluent Commerce Event API (async)
|
|
79
|
-
├─ Handle success/error responses
|
|
80
|
-
└─ Log event result
|
|
81
|
-
|
|
82
|
-
6. RETURN RESPONSE
|
|
83
|
-
├─ Return success with event details
|
|
84
|
-
└─ Return error with details if failed
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Key Features
|
|
88
|
-
|
|
89
|
-
- **Direct Payload Processing**: Receives XML payload directly in webhook request body
|
|
90
|
-
- **XML Parsing**: Handles Versori auto-parsed XML format ($ for attributes, _ for text)
|
|
91
|
-
- **Event API Integration**: Sends OrderCancel events to Fluent Commerce
|
|
92
|
-
- **Error Handling**: Comprehensive error handling with detailed logging
|
|
93
|
-
- **Native Versori Logging**: Uses Versori log from context
|
|
94
|
-
- **Flexible Order Reference Extraction**: Supports multiple XML element patterns
|
|
95
|
-
|
|
96
|
-
### 📦 Package Information
|
|
97
|
-
|
|
98
|
-
**SDK:** [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk) `latest`
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
npm install @fluentcommerce/fc-connect-sdk@latest
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
**Templates are designed for direct deployment; customize via activation variables.**
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## 📦 SDK Imports (Verified - Versori Optimized)
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
// ✅ VERIFIED IMPORTS - These match actual SDK exports
|
|
114
|
-
import { Buffer } from 'node:buffer'; // Required for Versori/Deno runtime
|
|
115
|
-
import {
|
|
116
|
-
createClient, // Universal client factory
|
|
117
|
-
XMLParserService, // XML parsing utility
|
|
118
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
119
|
-
|
|
120
|
-
import type { FluentClient } from '@fluentcommerce/fc-connect-sdk';
|
|
121
|
-
|
|
122
|
-
// Versori platform imports
|
|
123
|
-
import { webhook, http } from '@versori/run';
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
**Note:** All imports are from actual SDK exports - this code compiles and runs as-is.
|
|
127
|
-
|
|
128
|
-
**⚠️ CRITICAL - Buffer Import Required:**
|
|
129
|
-
|
|
130
|
-
The `Buffer` import from `node:buffer` is **required** for Versori/Deno runtime compatibility:
|
|
131
|
-
- Versori and Deno do NOT have `Buffer` as a global (unlike Node.js)
|
|
132
|
-
- Without this import, code will crash with `ReferenceError: Buffer is not defined`
|
|
133
|
-
- Always include this import in Versori templates, even if not directly used in the template code
|
|
134
|
-
- Required for SDK internal operations and any Buffer usage in your code
|
|
135
|
-
|
|
136
|
-
**✅ VERSORI PLATFORM - Use Native Logs:**
|
|
137
|
-
|
|
138
|
-
- Use `log` from context: `const { log } = ctx;`
|
|
139
|
-
- Native Versori logs are simpler and automatically integrated with platform monitoring
|
|
140
|
-
|
|
141
|
-
**✅ VERSORI XML PARSING:**
|
|
142
|
-
|
|
143
|
-
Versori automatically parses XML payloads when `Content-Type: application/xml` is set:
|
|
144
|
-
- Attributes accessed via `$` (e.g., `element.$?.attributeName`)
|
|
145
|
-
- Text content accessed via `_` (e.g., `element._`)
|
|
146
|
-
- Nested elements accessed directly (e.g., `element.childElement`)
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## 🔐 Fluent Commerce Connection Setup
|
|
151
|
-
|
|
152
|
-
**✅ BEST PRACTICE:** Store Fluent Commerce credentials in a Versori connection object:
|
|
153
|
-
|
|
154
|
-
**Connection Configuration:**
|
|
155
|
-
|
|
156
|
-
1. **Create Connection in Versori:**
|
|
157
|
-
- Name: `fluent_commerce`
|
|
158
|
-
- Type: HTTP Basic Auth or OAuth2
|
|
159
|
-
- Credentials: Fluent Commerce API credentials
|
|
160
|
-
|
|
161
|
-
2. **Connection Variables:**
|
|
162
|
-
- `FLUENT_BASE_URL` - Fluent Commerce API base URL (e.g., `https://api.fluentcommerce.com`)
|
|
163
|
-
- `FLUENT_RETAILER_ID` - Your retailer ID
|
|
164
|
-
- `FLUENT_CLIENT_ID` - OAuth client ID (if using OAuth2)
|
|
165
|
-
- `FLUENT_CLIENT_SECRET` - OAuth client secret (if using OAuth2)
|
|
166
|
-
|
|
167
|
-
**Benefits:**
|
|
168
|
-
- ✅ Credentials stored securely in Versori vault
|
|
169
|
-
- ✅ Connection can be reused across workflows
|
|
170
|
-
- ✅ No sensitive data in activation variables
|
|
171
|
-
- ✅ Easier credential rotation
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## 📄 Expected XML Payload Format
|
|
176
|
-
|
|
177
|
-
The webhook accepts XML payloads with order reference information. Multiple formats are supported:
|
|
178
|
-
|
|
179
|
-
### Format 1: Simple Order Reference
|
|
180
|
-
|
|
181
|
-
```xml
|
|
182
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
183
|
-
<orderCancel>
|
|
184
|
-
<orderRef>ORD-12345</orderRef>
|
|
185
|
-
</orderCancel>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Format 2: With Attributes
|
|
189
|
-
|
|
190
|
-
```xml
|
|
191
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
192
|
-
<orderCancel>
|
|
193
|
-
<order ref="ORD-12345"/>
|
|
194
|
-
</orderCancel>
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Format 3: Nested Structure
|
|
198
|
-
|
|
199
|
-
```xml
|
|
200
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
201
|
-
<orderCancel>
|
|
202
|
-
<order>
|
|
203
|
-
<reference>ORD-12345</reference>
|
|
204
|
-
<reason>Customer requested cancellation</reason>
|
|
205
|
-
</order>
|
|
206
|
-
</orderCancel>
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Format 4: Root Element with Attributes
|
|
210
|
-
|
|
211
|
-
```xml
|
|
212
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
213
|
-
<orderCancel orderRef="ORD-12345">
|
|
214
|
-
<reason>Customer requested cancellation</reason>
|
|
215
|
-
</orderCancel>
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
**Note:** The template extracts order reference from various XML patterns. Customize the extraction logic in the service if your payload uses different element names.
|
|
219
|
-
|
|
220
|
-
**Versori XML Parsing Format (CRITICAL):**
|
|
221
|
-
|
|
222
|
-
When Versori receives XML with `Content-Type: application/xml`, it **automatically parses** the XML into a JavaScript object. You do NOT need to manually parse XML - Versori handles it automatically.
|
|
223
|
-
|
|
224
|
-
**Access Patterns:**
|
|
225
|
-
- **Attributes**: `element.$?.attributeName` (e.g., `<order ref="ORD-12345"/>` → `order.$?.ref`)
|
|
226
|
-
- **Text content**: `element._` or direct property access (e.g., `<orderRef>ORD-12345</orderRef>` → `orderRef._` or `orderRef`)
|
|
227
|
-
- **Nested elements**: Direct property access (e.g., `<orderCancel><orderRef>...</orderRef></orderCancel>` → `orderCancel.orderRef`)
|
|
228
|
-
|
|
229
|
-
**Examples:**
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
// XML: <order ref="ORD-12345"/>
|
|
233
|
-
// Versori auto-parsed: { order: { $: { ref: "ORD-12345" } } }
|
|
234
|
-
const orderRef = parsed.order?.$?.ref; // ✅ "ORD-12345"
|
|
235
|
-
|
|
236
|
-
// XML: <orderRef>ORD-12345</orderRef>
|
|
237
|
-
// Versori auto-parsed: { orderRef: { _: "ORD-12345" } } OR { orderRef: "ORD-12345" }
|
|
238
|
-
const orderRef = parsed.orderRef?._ || parsed.orderRef; // ✅ "ORD-12345"
|
|
239
|
-
|
|
240
|
-
// XML: <orderCancel><order ref="ORD-12345"/></orderCancel>
|
|
241
|
-
// Versori auto-parsed: { orderCancel: { order: { $: { ref: "ORD-12345" } } } }
|
|
242
|
-
const orderRef = parsed.orderCancel?.order?.$?.ref; // ✅ "ORD-12345"
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
**Key Point:** Versori automatically parses XML when `Content-Type: application/xml` is set. Your webhook receives `ctx.data` as a pre-parsed JavaScript object - no manual XML parsing needed!
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
## Event Payload Structure
|
|
250
|
-
|
|
251
|
-
The template builds and sends this event structure:
|
|
252
|
-
|
|
253
|
-
```json
|
|
254
|
-
{
|
|
255
|
-
"retailerId": "{{retailer_id}}",
|
|
256
|
-
"name": "OrderCancel",
|
|
257
|
-
"entityRef": "{{order_ref}}",
|
|
258
|
-
"entityType": "ORDER"
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
**Fields:**
|
|
263
|
-
- `retailerId`: Retrieved from Fluent Commerce connection or activation variable
|
|
264
|
-
- `name`: Fixed as "OrderCancel"
|
|
265
|
-
- `entityRef`: Extracted from incoming XML payload
|
|
266
|
-
- `entityType`: Fixed as "ORDER"
|
|
267
|
-
|
|
268
|
-
---
|
|
269
|
-
|
|
270
|
-
## 🔧 Complete Production Code
|
|
271
|
-
|
|
272
|
-
### Versori Workflows Structure
|
|
273
|
-
|
|
274
|
-
**Key Concept**: Versori workflows are organized by **trigger type** at the first level, then by **specific workflow** with descriptive file names.
|
|
275
|
-
|
|
276
|
-
**Trigger Types:**
|
|
277
|
-
- **`webhook()`** → HTTP-based triggers (event-driven) - Creates HTTP endpoints
|
|
278
|
-
|
|
279
|
-
**Execution Steps (chained to triggers):**
|
|
280
|
-
- **`http()`** → External API calls (chained from webhook)
|
|
281
|
-
|
|
282
|
-
### Recommended Project Structure
|
|
283
|
-
|
|
284
|
-
```
|
|
285
|
-
order-cancel-webhook/
|
|
286
|
-
├── index.ts # Entry point - exports all workflows
|
|
287
|
-
└── src/
|
|
288
|
-
├── workflows/
|
|
289
|
-
│ └── webhook/
|
|
290
|
-
│ └── order-cancel.ts # Webhook: Order cancel handler
|
|
291
|
-
│
|
|
292
|
-
├── services/
|
|
293
|
-
│ └── order-cancel.service.ts # Shared orchestration logic
|
|
294
|
-
│
|
|
295
|
-
└── types/
|
|
296
|
-
└── order-cancel.types.ts # Type definitions
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
**Benefits:**
|
|
300
|
-
- ✅ Clear structure (webhook handlers in `webhook/`)
|
|
301
|
-
- ✅ Descriptive file names (easy to browse and understand)
|
|
302
|
-
- ✅ Reusable code in `services/` (DRY principle)
|
|
303
|
-
- ✅ Centralized type definitions
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## Workflow Files
|
|
308
|
-
|
|
309
|
-
### 1. Webhook Workflow (`src/workflows/webhook/order-cancel.ts`)
|
|
310
|
-
|
|
311
|
-
**Purpose**: Handle order cancel requests via webhook
|
|
312
|
-
**Trigger**: HTTP POST
|
|
313
|
-
**Endpoint**: `POST https://{workspace}.versori.run/order-cancel`
|
|
314
|
-
**Use Cases**: Order cancellation from external systems, manual cancellations
|
|
315
|
-
|
|
316
|
-
```typescript
|
|
317
|
-
import { webhook, http } from '@versori/run';
|
|
318
|
-
import { executeOrderCancel } from '../../services/order-cancel.service';
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Webhook: Order Cancel Handler
|
|
322
|
-
*
|
|
323
|
-
* Endpoint: POST https://{workspace}.versori.run/order-cancel
|
|
324
|
-
* Request body: XML payload with order reference
|
|
325
|
-
* Content-Type: application/xml
|
|
326
|
-
*
|
|
327
|
-
* Pattern: webhook().then(http()) - needs Fluent API access
|
|
328
|
-
* Uses shared service: order-cancel.service.ts
|
|
329
|
-
*
|
|
330
|
-
* SECURITY: Authentication handled via connection parameter
|
|
331
|
-
* No manual API key validation needed - Versori manages this via connection auth
|
|
332
|
-
*/
|
|
333
|
-
export const orderCancelWebhook = webhook('order-cancel', {
|
|
334
|
-
// ✅ Webhook response mode: 'sync'
|
|
335
|
-
// - HTTP response sent when handler completes
|
|
336
|
-
// - Returns event ID and success status immediately after Fluent accepts event
|
|
337
|
-
// - Alternative: 'async' mode would return immediately (before processing)
|
|
338
|
-
response: { mode: 'sync' },
|
|
339
|
-
connection: 'order-cancel-webhook', // Versori validates API key
|
|
340
|
-
}).then(
|
|
341
|
-
http('process-order-cancel', { connection: 'fluent_commerce' }, async ctx => {
|
|
342
|
-
const { log, data } = ctx;
|
|
343
|
-
|
|
344
|
-
log.info('🚀 [WEBHOOK] Order cancel request received', {
|
|
345
|
-
timestamp: new Date().toISOString(),
|
|
346
|
-
hasPayload: !!data,
|
|
347
|
-
contentType: ctx.request?.headers?.get('content-type'),
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
// Reuse shared orchestration logic
|
|
352
|
-
const result = await executeOrderCancel(ctx);
|
|
353
|
-
|
|
354
|
-
log.info('✅ [WEBHOOK] Order cancel completed successfully', {
|
|
355
|
-
orderRef: result.orderRef,
|
|
356
|
-
eventId: result.eventId,
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
return {
|
|
360
|
-
success: true,
|
|
361
|
-
orderRef: result.orderRef,
|
|
362
|
-
eventId: result.eventId,
|
|
363
|
-
message: 'Order cancel event sent successfully',
|
|
364
|
-
};
|
|
365
|
-
} catch (e: any) {
|
|
366
|
-
log.error('❌ [WEBHOOK] Order cancel failed', {
|
|
367
|
-
message: e?.message,
|
|
368
|
-
stack: e?.stack,
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
return {
|
|
372
|
-
success: false,
|
|
373
|
-
error: e?.message || 'Unknown error occurred',
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
})
|
|
377
|
-
);
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
---
|
|
381
|
-
|
|
382
|
-
### 2. Entry Point (`index.ts`)
|
|
383
|
-
|
|
384
|
-
**Purpose**: Register all workflows with Versori platform
|
|
385
|
-
|
|
386
|
-
```typescript
|
|
387
|
-
/**
|
|
388
|
-
* Entry Point - Registers all workflows with Versori platform
|
|
389
|
-
*
|
|
390
|
-
* Versori automatically discovers and registers exported workflows
|
|
391
|
-
*
|
|
392
|
-
* File Structure:
|
|
393
|
-
* - src/workflows/webhook/ → HTTP-based triggers (webhooks)
|
|
394
|
-
* - src/services/ → Shared service logic (reusable across workflows)
|
|
395
|
-
*/
|
|
396
|
-
|
|
397
|
-
// Import webhook workflows
|
|
398
|
-
import { orderCancelWebhook } from './src/workflows/webhook/order-cancel';
|
|
399
|
-
|
|
400
|
-
// Register all workflows with Versori platform
|
|
401
|
-
export {
|
|
402
|
-
// Webhooks (HTTP-based triggers)
|
|
403
|
-
orderCancelWebhook,
|
|
404
|
-
};
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
**What Gets Exposed:**
|
|
408
|
-
- ✅ `orderCancelWebhook` → `https://{workspace}.versori.run/order-cancel`
|
|
409
|
-
|
|
410
|
-
---
|
|
411
|
-
|
|
412
|
-
## 3. Type Definitions (`src/types/order-cancel.types.ts`)
|
|
413
|
-
|
|
414
|
-
```typescript
|
|
415
|
-
/**
|
|
416
|
-
* Type Definitions for Order Cancel Ingestion
|
|
417
|
-
*
|
|
418
|
-
* Centralized type definitions for order cancel workflow
|
|
419
|
-
*/
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Versori XML parsed format
|
|
423
|
-
* Attributes accessed via $, text content via _
|
|
424
|
-
*/
|
|
425
|
-
export interface VersoriXMLParsed {
|
|
426
|
-
[key: string]: unknown;
|
|
427
|
-
$?: Record<string, unknown>; // Attributes
|
|
428
|
-
_?: string; // Text content
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Order cancel request payload (XML parsed format)
|
|
433
|
-
*/
|
|
434
|
-
export interface OrderCancelPayload {
|
|
435
|
-
orderCancel?: {
|
|
436
|
-
orderRef?: VersoriXMLParsed | string;
|
|
437
|
-
order?: {
|
|
438
|
-
$?: {
|
|
439
|
-
ref?: string;
|
|
440
|
-
};
|
|
441
|
-
reference?: VersoriXMLParsed | string;
|
|
442
|
-
ref?: VersoriXMLParsed | string;
|
|
443
|
-
};
|
|
444
|
-
$?: {
|
|
445
|
-
orderRef?: string;
|
|
446
|
-
};
|
|
447
|
-
};
|
|
448
|
-
order?: {
|
|
449
|
-
$?: {
|
|
450
|
-
ref?: string;
|
|
451
|
-
};
|
|
452
|
-
reference?: VersoriXMLParsed | string;
|
|
453
|
-
ref?: VersoriXMLParsed | string;
|
|
454
|
-
};
|
|
455
|
-
[key: string]: unknown; // Allow additional fields
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Order cancel event payload
|
|
460
|
-
*/
|
|
461
|
-
export interface OrderCancelEvent {
|
|
462
|
-
retailerId: string;
|
|
463
|
-
name: 'OrderCancel';
|
|
464
|
-
entityRef: string;
|
|
465
|
-
entityType: 'ORDER';
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Order cancel result
|
|
470
|
-
*/
|
|
471
|
-
export interface OrderCancelResult {
|
|
472
|
-
success: boolean;
|
|
473
|
-
orderRef: string;
|
|
474
|
-
eventId?: string;
|
|
475
|
-
error?: string;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* Versori Context Interface
|
|
480
|
-
* Represents the Versori runtime context passed to workflow functions
|
|
481
|
-
*/
|
|
482
|
-
export interface VersoriContext {
|
|
483
|
-
log: {
|
|
484
|
-
info: (message: string, data?: Record<string, unknown>) => void;
|
|
485
|
-
warn: (message: string, data?: Record<string, unknown>) => void;
|
|
486
|
-
error: (message: string, data?: Record<string, unknown>) => void;
|
|
487
|
-
debug?: (message: string, data?: Record<string, unknown>) => void;
|
|
488
|
-
};
|
|
489
|
-
data?: unknown;
|
|
490
|
-
request?: Request;
|
|
491
|
-
activation: {
|
|
492
|
-
getVariable: (name: string) => string | undefined;
|
|
493
|
-
connections?: Record<string, unknown>;
|
|
494
|
-
};
|
|
495
|
-
connections?: Record<string, unknown>;
|
|
496
|
-
}
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
---
|
|
500
|
-
|
|
501
|
-
## 4. Service: Order Cancel Processor (`src/services/order-cancel.service.ts`)
|
|
502
|
-
|
|
503
|
-
```typescript
|
|
504
|
-
/**
|
|
505
|
-
* Order Cancel Service
|
|
506
|
-
*
|
|
507
|
-
* Processes order cancel requests: extracts order reference from XML payload,
|
|
508
|
-
* builds OrderCancel event, and sends to Fluent Commerce Event API.
|
|
509
|
-
* Handles Versori XML parsing format ($ for attributes, _ for text).
|
|
510
|
-
*/
|
|
511
|
-
|
|
512
|
-
import {
|
|
513
|
-
createClient,
|
|
514
|
-
XMLParserService,
|
|
515
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
516
|
-
import type { FluentClient } from '@fluentcommerce/fc-connect-sdk';
|
|
517
|
-
import type {
|
|
518
|
-
OrderCancelPayload,
|
|
519
|
-
OrderCancelResult,
|
|
520
|
-
VersoriContext,
|
|
521
|
-
VersoriXMLParsed,
|
|
522
|
-
} from '../types/order-cancel.types';
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Extract text content from Versori XML parsed format
|
|
526
|
-
* Handles both object format ({ _: "text" }) and direct string
|
|
527
|
-
*/
|
|
528
|
-
function extractTextContent(value: VersoriXMLParsed | string | undefined): string | null {
|
|
529
|
-
if (!value) {
|
|
530
|
-
return null;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
if (typeof value === 'string') {
|
|
534
|
-
return value;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (typeof value === 'object' && '_' in value) {
|
|
538
|
-
const text = value._;
|
|
539
|
-
return typeof text === 'string' ? text : null;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Extract order reference from XML payload
|
|
547
|
-
*
|
|
548
|
-
* Supports multiple XML formats:
|
|
549
|
-
* - <orderCancel><orderRef>ORD-12345</orderRef></orderCancel>
|
|
550
|
-
* - <orderCancel><order ref="ORD-12345"/></orderCancel>
|
|
551
|
-
* - <orderCancel><order><reference>ORD-12345</reference></order></orderCancel>
|
|
552
|
-
* - <orderCancel orderRef="ORD-12345"/>
|
|
553
|
-
*/
|
|
554
|
-
function extractOrderRef(payload: OrderCancelPayload): string | null {
|
|
555
|
-
// Try orderCancel.orderRef (text content)
|
|
556
|
-
if (payload.orderCancel) {
|
|
557
|
-
const orderCancel = payload.orderCancel;
|
|
558
|
-
|
|
559
|
-
// Try orderCancel.orderRef as text
|
|
560
|
-
if (orderCancel.orderRef) {
|
|
561
|
-
const ref = extractTextContent(orderCancel.orderRef);
|
|
562
|
-
if (ref) {
|
|
563
|
-
return ref;
|
|
564
|
-
}
|
|
565
|
-
// Try as direct string
|
|
566
|
-
if (typeof orderCancel.orderRef === 'string') {
|
|
567
|
-
return orderCancel.orderRef;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// Try orderCancel.order.$?.ref (attribute)
|
|
572
|
-
if (
|
|
573
|
-
orderCancel.order &&
|
|
574
|
-
typeof orderCancel.order === 'object' &&
|
|
575
|
-
'$' in orderCancel.order
|
|
576
|
-
) {
|
|
577
|
-
const attrs = orderCancel.order.$ as Record<string, unknown>;
|
|
578
|
-
if (attrs && typeof attrs.ref === 'string') {
|
|
579
|
-
return attrs.ref;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// Try orderCancel.order.reference (text content)
|
|
584
|
-
if (
|
|
585
|
-
orderCancel.order &&
|
|
586
|
-
typeof orderCancel.order === 'object' &&
|
|
587
|
-
'reference' in orderCancel.order
|
|
588
|
-
) {
|
|
589
|
-
const ref = extractTextContent(orderCancel.order.reference as VersoriXMLParsed);
|
|
590
|
-
if (ref) {
|
|
591
|
-
return ref;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// Try orderCancel.order.ref (text content)
|
|
596
|
-
if (
|
|
597
|
-
orderCancel.order &&
|
|
598
|
-
typeof orderCancel.order === 'object' &&
|
|
599
|
-
'ref' in orderCancel.order
|
|
600
|
-
) {
|
|
601
|
-
const ref = extractTextContent(orderCancel.order.ref as VersoriXMLParsed);
|
|
602
|
-
if (ref) {
|
|
603
|
-
return ref;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
// Try orderCancel.$?.orderRef (root attribute)
|
|
608
|
-
if ('$' in orderCancel && orderCancel.$) {
|
|
609
|
-
const attrs = orderCancel.$ as Record<string, unknown>;
|
|
610
|
-
if (attrs && typeof attrs.orderRef === 'string') {
|
|
611
|
-
return attrs.orderRef;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// Try direct order element
|
|
617
|
-
if (payload.order) {
|
|
618
|
-
const order = payload.order;
|
|
619
|
-
|
|
620
|
-
// Try order.$?.ref (attribute)
|
|
621
|
-
if (typeof order === 'object' && '$' in order && order.$) {
|
|
622
|
-
const attrs = order.$ as Record<string, unknown>;
|
|
623
|
-
if (attrs && typeof attrs.ref === 'string') {
|
|
624
|
-
return attrs.ref;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// Try order.reference (text content)
|
|
629
|
-
if (typeof order === 'object' && 'reference' in order) {
|
|
630
|
-
const ref = extractTextContent(order.reference as VersoriXMLParsed);
|
|
631
|
-
if (ref) {
|
|
632
|
-
return ref;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// Try order.ref (text content)
|
|
637
|
-
if (typeof order === 'object' && 'ref' in order) {
|
|
638
|
-
const ref = extractTextContent(order.ref as VersoriXMLParsed);
|
|
639
|
-
if (ref) {
|
|
640
|
-
return ref;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
return null;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* Parse webhook payload from Versori context
|
|
650
|
-
*
|
|
651
|
-
* CRITICAL: Versori automatically parses XML when Content-Type: application/xml is set.
|
|
652
|
-
* The ctx.data will be a pre-parsed JavaScript object - no manual parsing needed!
|
|
653
|
-
*
|
|
654
|
-
* Handles both pre-parsed XML (ctx.data) and raw request body (ctx.request) as fallback
|
|
655
|
-
*/
|
|
656
|
-
async function parseWebhookPayload(
|
|
657
|
-
ctx: VersoriContext
|
|
658
|
-
): Promise<OrderCancelPayload | null> {
|
|
659
|
-
const { log, data, request } = ctx;
|
|
660
|
-
|
|
661
|
-
// ✅ Scenario 1: Pre-parsed XML (Versori auto-parsed when Content-Type: application/xml)
|
|
662
|
-
// This is the PRIMARY path - Versori handles XML parsing automatically
|
|
663
|
-
if (data && typeof data === 'object' && data !== null) {
|
|
664
|
-
log.info('📥 [PARSE] Using Versori auto-parsed XML payload', {
|
|
665
|
-
hasData: true,
|
|
666
|
-
dataKeys: Object.keys(data),
|
|
667
|
-
contentType: request?.headers?.get('content-type'),
|
|
668
|
-
});
|
|
669
|
-
return data as OrderCancelPayload;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// ⚠️ Scenario 2: Raw request body (fallback - should rarely be needed)
|
|
673
|
-
// Only used if Versori didn't auto-parse (e.g., wrong Content-Type header)
|
|
674
|
-
if (request && typeof request.text === 'function') {
|
|
675
|
-
log.warn('📥 [PARSE] Falling back to manual XML parsing (Content-Type may be incorrect)');
|
|
676
|
-
try {
|
|
677
|
-
const rawBody = await request.text();
|
|
678
|
-
if (!rawBody || rawBody.trim() === '') {
|
|
679
|
-
log.error('❌ [PARSE] Request body is empty');
|
|
680
|
-
return null;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const parser = new XMLParserService(log);
|
|
684
|
-
const parsed = await parser.parse(rawBody);
|
|
685
|
-
|
|
686
|
-
log.info('📥 [PARSE] Successfully parsed XML payload', {
|
|
687
|
-
parsedKeys: Object.keys(parsed),
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
return parsed as OrderCancelPayload;
|
|
691
|
-
} catch (parseError: unknown) {
|
|
692
|
-
const errorMessage =
|
|
693
|
-
parseError instanceof Error ? parseError.message : String(parseError);
|
|
694
|
-
log.error('❌ [PARSE] Failed to parse XML payload', {
|
|
695
|
-
error: errorMessage,
|
|
696
|
-
});
|
|
697
|
-
return null;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
log.error('❌ [PARSE] No valid payload found in context');
|
|
702
|
-
return null;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Build OrderCancel event payload
|
|
707
|
-
*/
|
|
708
|
-
function buildOrderCancelEvent(
|
|
709
|
-
orderRef: string,
|
|
710
|
-
retailerId: string
|
|
711
|
-
): {
|
|
712
|
-
retailerId: string;
|
|
713
|
-
name: 'OrderCancel';
|
|
714
|
-
entityRef: string;
|
|
715
|
-
entityType: 'ORDER';
|
|
716
|
-
} {
|
|
717
|
-
return {
|
|
718
|
-
retailerId,
|
|
719
|
-
name: 'OrderCancel',
|
|
720
|
-
entityRef: orderRef,
|
|
721
|
-
entityType: 'ORDER',
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Execute order cancel workflow
|
|
727
|
-
*
|
|
728
|
-
* Main orchestration function:
|
|
729
|
-
* 1. Parse webhook payload
|
|
730
|
-
* 2. Extract order reference
|
|
731
|
-
* 3. Create Fluent client
|
|
732
|
-
* 4. Build event payload
|
|
733
|
-
* 5. Send event to Fluent Commerce
|
|
734
|
-
*/
|
|
735
|
-
export async function executeOrderCancel(
|
|
736
|
-
ctx: VersoriContext
|
|
737
|
-
): Promise<OrderCancelResult> {
|
|
738
|
-
const { log, activation } = ctx;
|
|
739
|
-
|
|
740
|
-
log.info('🚀 [SERVICE] Starting order cancel processing');
|
|
741
|
-
|
|
742
|
-
// STEP 1: Parse webhook payload
|
|
743
|
-
// ✅ Versori automatically parses XML when Content-Type: application/xml is set
|
|
744
|
-
// ctx.data will be a pre-parsed JavaScript object - no manual parsing needed!
|
|
745
|
-
const payload = await parseWebhookPayload(ctx);
|
|
746
|
-
if (!payload) {
|
|
747
|
-
throw new Error(
|
|
748
|
-
'Failed to parse webhook payload. Ensure Content-Type: application/xml is set in request headers.'
|
|
749
|
-
);
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
log.info('📥 [SERVICE] Payload parsed successfully (Versori auto-parsed XML)', {
|
|
753
|
-
payloadKeys: Object.keys(payload),
|
|
754
|
-
note: 'Versori automatically parses XML when Content-Type: application/xml is set',
|
|
755
|
-
});
|
|
756
|
-
|
|
757
|
-
// STEP 2: Extract order reference
|
|
758
|
-
const orderRef = extractOrderRef(payload);
|
|
759
|
-
if (!orderRef) {
|
|
760
|
-
log.error('❌ [SERVICE] Order reference not found in XML payload', {
|
|
761
|
-
payloadKeys: Object.keys(payload),
|
|
762
|
-
expectedPatterns: [
|
|
763
|
-
'orderCancel.orderRef',
|
|
764
|
-
'orderCancel.order[@ref]',
|
|
765
|
-
'orderCancel.order.reference',
|
|
766
|
-
'orderCancel[@orderRef]',
|
|
767
|
-
],
|
|
768
|
-
});
|
|
769
|
-
throw new Error(
|
|
770
|
-
'Order reference not found in XML payload. Expected patterns: orderCancel.orderRef, orderCancel.order[@ref], orderCancel.order.reference, or orderCancel[@orderRef]'
|
|
771
|
-
);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
log.info('✅ [SERVICE] Order reference extracted', { orderRef });
|
|
775
|
-
|
|
776
|
-
// STEP 3: Get retailer ID from activation variable or connection
|
|
777
|
-
const retailerId =
|
|
778
|
-
activation.getVariable('FLUENT_RETAILER_ID') ||
|
|
779
|
-
(activation.connections?.fluent_commerce as any)?.retailerId;
|
|
780
|
-
|
|
781
|
-
if (!retailerId) {
|
|
782
|
-
log.error('❌ [SERVICE] Retailer ID not found', {
|
|
783
|
-
checkedVariables: ['FLUENT_RETAILER_ID'],
|
|
784
|
-
hasConnection: !!activation.connections?.fluent_commerce,
|
|
785
|
-
});
|
|
786
|
-
throw new Error(
|
|
787
|
-
'Retailer ID not found. Set FLUENT_RETAILER_ID activation variable or configure in connection.'
|
|
788
|
-
);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
log.info('✅ [SERVICE] Retailer ID retrieved', { retailerId });
|
|
792
|
-
|
|
793
|
-
// STEP 4: Create Fluent client
|
|
794
|
-
// ✅ Pass ctx directly - createClient auto-detects Versori context
|
|
795
|
-
const client = await createClient(ctx);
|
|
796
|
-
|
|
797
|
-
log.info('✅ [SERVICE] Fluent client created');
|
|
798
|
-
|
|
799
|
-
// STEP 5: Build event payload
|
|
800
|
-
const eventPayload = buildOrderCancelEvent(orderRef, retailerId);
|
|
801
|
-
|
|
802
|
-
log.info('📤 [SERVICE] Sending OrderCancel event', {
|
|
803
|
-
orderRef,
|
|
804
|
-
retailerId,
|
|
805
|
-
});
|
|
806
|
-
|
|
807
|
-
// STEP 6: Send event to Fluent Commerce
|
|
808
|
-
// ✅ Using 'async' mode (recommended):
|
|
809
|
-
// - Fluent accepts event immediately and processes in background
|
|
810
|
-
// - Returns event ID quickly (non-blocking)
|
|
811
|
-
// - Better performance for webhook responses
|
|
812
|
-
// - Alternative: 'sync' mode waits for event processing (slower, blocking)
|
|
813
|
-
// - Sync mode success: { eventId: "...", eventStatus: "COMPLETE" }
|
|
814
|
-
// - Sync mode failure: { eventStatus: "FAILED" }
|
|
815
|
-
// - Sync mode no match: { eventId: "...", eventStatus: "NO_MATCH" }
|
|
816
|
-
const response = await client.sendEvent(eventPayload, 'async');
|
|
817
|
-
|
|
818
|
-
// Extract event ID from Fluent response
|
|
819
|
-
// Async mode response format: { id: "evt_abc123", ... }
|
|
820
|
-
// Sync mode response format (success): { eventId: "...", eventStatus: "COMPLETE" }
|
|
821
|
-
// Sync mode response format (failure): { eventStatus: "FAILED" }
|
|
822
|
-
// Sync mode response format (no match): { eventId: "...", eventStatus: "NO_MATCH" }
|
|
823
|
-
let eventId: string | undefined;
|
|
824
|
-
|
|
825
|
-
if (response && typeof response === 'object') {
|
|
826
|
-
// Extract event ID first (needed for error messages)
|
|
827
|
-
if ('id' in response) {
|
|
828
|
-
eventId = response.id as string;
|
|
829
|
-
} else if ('eventId' in response) {
|
|
830
|
-
eventId = response.eventId as string;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// Check for sync mode failure statuses
|
|
834
|
-
if ('eventStatus' in response) {
|
|
835
|
-
const eventStatus = response.eventStatus as string;
|
|
836
|
-
|
|
837
|
-
if (eventStatus === 'FAILED') {
|
|
838
|
-
log.error('❌ [SERVICE] OrderCancel event failed (sync mode)', {
|
|
839
|
-
orderRef,
|
|
840
|
-
eventId,
|
|
841
|
-
eventStatus,
|
|
842
|
-
response,
|
|
843
|
-
});
|
|
844
|
-
throw new Error('Order cancel event failed. Event status: FAILED');
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
if (eventStatus === 'NO_MATCH') {
|
|
848
|
-
log.error('❌ [SERVICE] OrderCancel event no match (sync mode)', {
|
|
849
|
-
orderRef,
|
|
850
|
-
eventId,
|
|
851
|
-
eventStatus,
|
|
852
|
-
response,
|
|
853
|
-
});
|
|
854
|
-
throw new Error(
|
|
855
|
-
'Order cancel event did not match any workflow. Possible causes: incorrect event name, status mismatch, or entity not found. Event status: NO_MATCH'
|
|
856
|
-
);
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
if (eventStatus === 'COMPLETE') {
|
|
860
|
-
log.info('✅ [SERVICE] OrderCancel event completed (sync mode)', {
|
|
861
|
-
orderRef,
|
|
862
|
-
eventId,
|
|
863
|
-
eventStatus,
|
|
864
|
-
});
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
log.info('✅ [SERVICE] OrderCancel event sent successfully', {
|
|
870
|
-
orderRef,
|
|
871
|
-
eventId,
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
return {
|
|
875
|
-
success: true,
|
|
876
|
-
orderRef,
|
|
877
|
-
eventId,
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
```
|
|
881
|
-
|
|
882
|
-
---
|
|
883
|
-
|
|
884
|
-
## 5. Configuration
|
|
885
|
-
|
|
886
|
-
### Activation Variables
|
|
887
|
-
|
|
888
|
-
Configure these variables in Versori activation settings:
|
|
889
|
-
|
|
890
|
-
```json
|
|
891
|
-
{
|
|
892
|
-
"FLUENT_RETAILER_ID": "your-retailer-id"
|
|
893
|
-
}
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
**Note:** If using Versori connection for Fluent Commerce, retailer ID can also be configured in the connection settings.
|
|
897
|
-
|
|
898
|
-
### Webhook Connection
|
|
899
|
-
|
|
900
|
-
Create a Versori connection for webhook authentication:
|
|
901
|
-
|
|
902
|
-
1. **Connection Name:** `order-cancel-webhook`
|
|
903
|
-
2. **Type:** API Key or Basic Auth
|
|
904
|
-
3. **Purpose:** Authenticate incoming webhook requests
|
|
905
|
-
|
|
906
|
-
**Example webhook call:**
|
|
907
|
-
|
|
908
|
-
```bash
|
|
909
|
-
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
910
|
-
-H "Content-Type: application/xml" \
|
|
911
|
-
-H "X-API-Key: your-api-key" \
|
|
912
|
-
--data-binary @order-cancel.xml
|
|
913
|
-
```
|
|
914
|
-
|
|
915
|
-
**Example XML file (`order-cancel.xml`):**
|
|
916
|
-
|
|
917
|
-
```xml
|
|
918
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
919
|
-
<orderCancel>
|
|
920
|
-
<orderRef>ORD-12345</orderRef>
|
|
921
|
-
</orderCancel>
|
|
922
|
-
```
|
|
923
|
-
|
|
924
|
-
**CRITICAL: Content-Type Header**
|
|
925
|
-
|
|
926
|
-
The `Content-Type: application/xml` header is **required** for Versori to automatically parse the XML. Without this header, Versori will not parse the XML and you'll need to manually parse using `XMLParserService`.
|
|
927
|
-
|
|
928
|
-
**✅ CORRECT:**
|
|
929
|
-
```bash
|
|
930
|
-
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
931
|
-
-H "Content-Type: application/xml" \ # ✅ Required!
|
|
932
|
-
-H "X-API-Key: your-api-key" \
|
|
933
|
-
--data-binary @order-cancel.xml
|
|
934
|
-
```
|
|
935
|
-
|
|
936
|
-
**❌ WRONG:**
|
|
937
|
-
```bash
|
|
938
|
-
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
939
|
-
-H "Content-Type: text/plain" \ # ❌ Wrong Content-Type
|
|
940
|
-
-H "X-API-Key: your-api-key" \
|
|
941
|
-
--data-binary @order-cancel.xml
|
|
942
|
-
```
|
|
943
|
-
|
|
944
|
-
---
|
|
945
|
-
|
|
946
|
-
## 6. Error Handling
|
|
947
|
-
|
|
948
|
-
The template includes comprehensive error handling:
|
|
949
|
-
|
|
950
|
-
### Payload Parsing Errors
|
|
951
|
-
|
|
952
|
-
- **Empty payload:** Returns error response
|
|
953
|
-
- **Invalid XML:** Returns error with parse details
|
|
954
|
-
- **Missing order reference:** Returns error with expected patterns
|
|
955
|
-
|
|
956
|
-
### Event Sending Errors
|
|
957
|
-
|
|
958
|
-
- **Network errors:** Logged and returned in error response
|
|
959
|
-
- **API errors:** Logged with full error details
|
|
960
|
-
- **Validation errors:** Logged with validation message
|
|
961
|
-
|
|
962
|
-
### Error Response Format
|
|
963
|
-
|
|
964
|
-
```json
|
|
965
|
-
{
|
|
966
|
-
"success": false,
|
|
967
|
-
"error": "Order reference not found in XML payload. Expected patterns: orderCancel.orderRef, orderCancel.order[@ref], orderCancel.order.reference, or orderCancel[@orderRef]"
|
|
968
|
-
}
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
---
|
|
972
|
-
|
|
973
|
-
## 7. Testing
|
|
974
|
-
|
|
975
|
-
### Test with cURL
|
|
976
|
-
|
|
977
|
-
```bash
|
|
978
|
-
# Test order cancel webhook with XML file
|
|
979
|
-
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
980
|
-
-H "Content-Type: application/xml" \
|
|
981
|
-
-H "X-API-Key: your-api-key" \
|
|
982
|
-
--data-binary @order-cancel.xml
|
|
983
|
-
```
|
|
984
|
-
|
|
985
|
-
### Test with Inline XML
|
|
986
|
-
|
|
987
|
-
```bash
|
|
988
|
-
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
989
|
-
-H "Content-Type: application/xml" \
|
|
990
|
-
-H "X-API-Key: your-api-key" \
|
|
991
|
-
-d '<?xml version="1.0" encoding="UTF-8"?><orderCancel><orderRef>ORD-12345</orderRef></orderCancel>'
|
|
992
|
-
```
|
|
993
|
-
|
|
994
|
-
### Expected Success Response
|
|
995
|
-
|
|
996
|
-
```json
|
|
997
|
-
{
|
|
998
|
-
"success": true,
|
|
999
|
-
"orderRef": "ORD-12345",
|
|
1000
|
-
"eventId": "evt_abc123",
|
|
1001
|
-
"message": "Order cancel event sent successfully"
|
|
1002
|
-
}
|
|
1003
|
-
```
|
|
1004
|
-
|
|
1005
|
-
**Response Details:**
|
|
1006
|
-
- `success`: `true` indicates webhook processed successfully
|
|
1007
|
-
- `orderRef`: The order reference that was cancelled
|
|
1008
|
-
- `eventId`: Fluent Commerce event ID (returned from Event API async endpoint)
|
|
1009
|
-
- `message`: Human-readable success message
|
|
1010
|
-
|
|
1011
|
-
**Event API Mode: `async` (recommended)**
|
|
1012
|
-
- Fluent accepts the event immediately and returns an event ID
|
|
1013
|
-
- Event processing happens in the background
|
|
1014
|
-
- Webhook response includes the event ID for tracking
|
|
1015
|
-
- Response format: `{ id: "evt_abc123" }`
|
|
1016
|
-
|
|
1017
|
-
**Alternative: `sync` mode**
|
|
1018
|
-
- Fluent processes the event synchronously before responding
|
|
1019
|
-
- Slower response time (waits for event processing)
|
|
1020
|
-
- Success response: `{ eventId: "...", eventStatus: "COMPLETE" }`
|
|
1021
|
-
- Failure response: `{ eventStatus: "FAILED" }`
|
|
1022
|
-
- No match response: `{ eventId: "...", eventStatus: "NO_MATCH" }` (incorrect event name, status mismatch, or entity not found)
|
|
1023
|
-
- Use only if you need immediate confirmation of event processing
|
|
1024
|
-
|
|
1025
|
-
### Expected Error Response
|
|
1026
|
-
|
|
1027
|
-
**Webhook Processing Errors:**
|
|
1028
|
-
```json
|
|
1029
|
-
{
|
|
1030
|
-
"success": false,
|
|
1031
|
-
"error": "Order reference not found in XML payload"
|
|
1032
|
-
}
|
|
1033
|
-
```
|
|
1034
|
-
|
|
1035
|
-
**Event API Sync Mode Responses:**
|
|
1036
|
-
|
|
1037
|
-
**Success (sync mode):**
|
|
1038
|
-
```json
|
|
1039
|
-
{
|
|
1040
|
-
"eventId": "421d1709-d0af-4d8a-b7b6-75e40c5fc038",
|
|
1041
|
-
"eventStatus": "COMPLETE"
|
|
1042
|
-
}
|
|
1043
|
-
```
|
|
1044
|
-
|
|
1045
|
-
**Failure (sync mode):**
|
|
1046
|
-
```json
|
|
1047
|
-
{
|
|
1048
|
-
"eventStatus": "FAILED"
|
|
1049
|
-
}
|
|
1050
|
-
```
|
|
1051
|
-
|
|
1052
|
-
**No Match (sync mode):**
|
|
1053
|
-
Occurs when event name is incorrect, status mismatch, or entity not found:
|
|
1054
|
-
```json
|
|
1055
|
-
{
|
|
1056
|
-
"eventId": "9782c552-033c-47c7-89ea-2b0068fbdd0a",
|
|
1057
|
-
"eventStatus": "NO_MATCH"
|
|
1058
|
-
}
|
|
1059
|
-
```
|
|
1060
|
-
|
|
1061
|
-
The webhook will catch failures and return:
|
|
1062
|
-
```json
|
|
1063
|
-
{
|
|
1064
|
-
"success": false,
|
|
1065
|
-
"error": "Order cancel event failed. Event status: FAILED"
|
|
1066
|
-
}
|
|
1067
|
-
```
|
|
1068
|
-
|
|
1069
|
-
Or for NO_MATCH:
|
|
1070
|
-
```json
|
|
1071
|
-
{
|
|
1072
|
-
"success": false,
|
|
1073
|
-
"error": "Order cancel event did not match any workflow. Possible causes: incorrect event name, status mismatch, or entity not found. Event status: NO_MATCH"
|
|
1074
|
-
}
|
|
1075
|
-
```
|
|
1076
|
-
|
|
1077
|
-
---
|
|
1078
|
-
|
|
1079
|
-
## 8. Customization
|
|
1080
|
-
|
|
1081
|
-
### Custom Order Reference Element
|
|
1082
|
-
|
|
1083
|
-
If your XML uses different element names, modify `extractOrderRef()` in `order-cancel.service.ts`:
|
|
1084
|
-
|
|
1085
|
-
```typescript
|
|
1086
|
-
function extractOrderRef(payload: OrderCancelPayload): string | null {
|
|
1087
|
-
// Add your custom element extraction logic
|
|
1088
|
-
if (payload.customCancel && typeof payload.customCancel === 'object') {
|
|
1089
|
-
const cancel = payload.customCancel;
|
|
1090
|
-
if ('$' in cancel && cancel.$) {
|
|
1091
|
-
const attrs = cancel.$ as Record<string, unknown>;
|
|
1092
|
-
if (attrs && typeof attrs.orderId === 'string') {
|
|
1093
|
-
return attrs.orderId;
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
// ... existing logic
|
|
1098
|
-
}
|
|
1099
|
-
```
|
|
1100
|
-
|
|
1101
|
-
### Custom Event Name
|
|
1102
|
-
|
|
1103
|
-
To use a different event name, modify `buildOrderCancelEvent()`:
|
|
1104
|
-
|
|
1105
|
-
```typescript
|
|
1106
|
-
function buildOrderCancelEvent(
|
|
1107
|
-
orderRef: string,
|
|
1108
|
-
retailerId: string
|
|
1109
|
-
) {
|
|
1110
|
-
return {
|
|
1111
|
-
retailerId,
|
|
1112
|
-
name: 'CustomOrderCancel', // Change event name
|
|
1113
|
-
entityRef: orderRef,
|
|
1114
|
-
entityType: 'ORDER',
|
|
1115
|
-
};
|
|
1116
|
-
}
|
|
1117
|
-
```
|
|
1118
|
-
|
|
1119
|
-
### Additional Event Data
|
|
1120
|
-
|
|
1121
|
-
To include additional data in the event:
|
|
1122
|
-
|
|
1123
|
-
```typescript
|
|
1124
|
-
function buildOrderCancelEvent(
|
|
1125
|
-
orderRef: string,
|
|
1126
|
-
retailerId: string,
|
|
1127
|
-
additionalData?: Record<string, unknown>
|
|
1128
|
-
) {
|
|
1129
|
-
return {
|
|
1130
|
-
retailerId,
|
|
1131
|
-
name: 'OrderCancel',
|
|
1132
|
-
entityRef: orderRef,
|
|
1133
|
-
entityType: 'ORDER',
|
|
1134
|
-
data: additionalData, // Add custom data
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
```
|
|
1138
|
-
|
|
1139
|
-
---
|
|
1140
|
-
|
|
1141
|
-
## Summary
|
|
1142
|
-
|
|
1143
|
-
✅ **DO:**
|
|
1144
|
-
- Use Versori connection for Fluent Commerce credentials
|
|
1145
|
-
- Handle both pre-parsed and raw XML payloads
|
|
1146
|
-
- Extract order reference with multiple fallback patterns
|
|
1147
|
-
- Handle Versori XML format ($ for attributes, _ for text)
|
|
1148
|
-
- Log all steps for debugging
|
|
1149
|
-
- Return clear error messages
|
|
1150
|
-
|
|
1151
|
-
❌ **DON'T:**
|
|
1152
|
-
- Hardcode credentials in code
|
|
1153
|
-
- Assume payload format without validation
|
|
1154
|
-
- Skip error handling
|
|
1155
|
-
- Use `sync` mode for Event API (use `async` for better performance and faster webhook responses)
|
|
1156
|
-
- Ignore Versori XML parsing format ($ and _)
|
|
1157
|
-
|
|
1158
|
-
---
|
|
1159
|
-
|
|
1160
|
-
## Next Steps
|
|
1161
|
-
|
|
1162
|
-
1. **Deploy:** Copy code to your Versori project
|
|
1163
|
-
2. **Configure:** Set up Fluent Commerce connection and activation variables
|
|
1164
|
-
3. **Test:** Test webhook with sample XML payloads
|
|
1165
|
-
4. **Monitor:** Check Versori logs for event processing
|
|
1166
|
-
|
|
1167
|
-
For more templates, see:
|
|
1168
|
-
- [JSON Payload Template](./template-ingestion-payload-json-order-cancel-event.md)
|
|
1169
|
-
- [Other Event API Templates](./event-api-guide.md)
|
|
1170
|
-
|
|
1
|
+
---
|
|
2
|
+
template_id: tpl-ingest-payload-xml-to-order-cancel-event
|
|
3
|
+
canonical_filename: template-ingestion-payload-xml-order-cancel-event.md
|
|
4
|
+
sdk_version: latest
|
|
5
|
+
runtime: versori
|
|
6
|
+
direction: ingestion
|
|
7
|
+
source: payload-xml
|
|
8
|
+
destination: fluent-event-api
|
|
9
|
+
entity: order
|
|
10
|
+
format: xml
|
|
11
|
+
logging: versori
|
|
12
|
+
status: stable
|
|
13
|
+
features:
|
|
14
|
+
- direct-payload-processing
|
|
15
|
+
- xml-parsing
|
|
16
|
+
- event-api-integration
|
|
17
|
+
- error-handling
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Template: Ingestion - Payload XML to Order Cancel Event
|
|
21
|
+
|
|
22
|
+
**SDK Version:** @fluentcommerce/fc-connect-sdk@latest
|
|
23
|
+
**Last Updated:** 2025-01-24
|
|
24
|
+
**Deployment Target:** Versori Platform
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 📋 Implementation Prompt
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
I need a Versori webhook ingestion that:
|
|
32
|
+
|
|
33
|
+
1) Receives XML payload directly in webhook request body
|
|
34
|
+
2) Parses XML to extract order reference (handles Versori $ format for attributes)
|
|
35
|
+
3) Builds OrderCancel event payload with retailerId, name, entityRef, entityType
|
|
36
|
+
4) Sends event to Fluent Commerce Event API (async)
|
|
37
|
+
5) Returns success/error response
|
|
38
|
+
6) Uses native Versori log from context
|
|
39
|
+
|
|
40
|
+
Use the loaded docs to fill in SDK specifics and best practices.
|
|
41
|
+
Keep the structure identical to the template; only adapt where needed.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 📋 Template Overview
|
|
47
|
+
|
|
48
|
+
This connector runs on the Versori platform. It receives XML payloads directly via webhook, extracts the order reference, and sends OrderCancel events to Fluent Commerce Event API. Most operational settings (Fluent account/connection) are configured via activation variables.
|
|
49
|
+
|
|
50
|
+
### What This Template Does
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
54
|
+
│ INGESTION WORKFLOW │
|
|
55
|
+
└────────────────────────────────────────────────────────────────┘
|
|
56
|
+
|
|
57
|
+
1. TRIGGER
|
|
58
|
+
└─ Webhook: HTTP POST endpoint receives XML payload
|
|
59
|
+
|
|
60
|
+
2. RECEIVE PAYLOAD
|
|
61
|
+
├─ Extract XML from request body (ctx.data or ctx.request)
|
|
62
|
+
├─ Validate payload structure
|
|
63
|
+
└─ Log incoming request
|
|
64
|
+
|
|
65
|
+
3. PARSE XML
|
|
66
|
+
├─ Parse XML payload (Versori auto-parses with $ format)
|
|
67
|
+
├─ Extract order reference (handles $ for attributes, _ for text)
|
|
68
|
+
└─ Validate required fields
|
|
69
|
+
|
|
70
|
+
4. BUILD EVENT
|
|
71
|
+
├─ Construct OrderCancel event payload
|
|
72
|
+
├─ Set retailerId (from config or payload)
|
|
73
|
+
├─ Set name: "OrderCancel"
|
|
74
|
+
├─ Set entityRef: order reference
|
|
75
|
+
└─ Set entityType: "ORDER"
|
|
76
|
+
|
|
77
|
+
5. SEND EVENT (Event API)
|
|
78
|
+
├─ Send event to Fluent Commerce Event API (async)
|
|
79
|
+
├─ Handle success/error responses
|
|
80
|
+
└─ Log event result
|
|
81
|
+
|
|
82
|
+
6. RETURN RESPONSE
|
|
83
|
+
├─ Return success with event details
|
|
84
|
+
└─ Return error with details if failed
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Key Features
|
|
88
|
+
|
|
89
|
+
- **Direct Payload Processing**: Receives XML payload directly in webhook request body
|
|
90
|
+
- **XML Parsing**: Handles Versori auto-parsed XML format ($ for attributes, _ for text)
|
|
91
|
+
- **Event API Integration**: Sends OrderCancel events to Fluent Commerce
|
|
92
|
+
- **Error Handling**: Comprehensive error handling with detailed logging
|
|
93
|
+
- **Native Versori Logging**: Uses Versori log from context
|
|
94
|
+
- **Flexible Order Reference Extraction**: Supports multiple XML element patterns
|
|
95
|
+
|
|
96
|
+
### 📦 Package Information
|
|
97
|
+
|
|
98
|
+
**SDK:** [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk) `latest`
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm install @fluentcommerce/fc-connect-sdk@latest
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
**Templates are designed for direct deployment; customize via activation variables.**
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 📦 SDK Imports (Verified - Versori Optimized)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// ✅ VERIFIED IMPORTS - These match actual SDK exports
|
|
114
|
+
import { Buffer } from 'node:buffer'; // Required for Versori/Deno runtime
|
|
115
|
+
import {
|
|
116
|
+
createClient, // Universal client factory
|
|
117
|
+
XMLParserService, // XML parsing utility
|
|
118
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
119
|
+
|
|
120
|
+
import type { FluentClient } from '@fluentcommerce/fc-connect-sdk';
|
|
121
|
+
|
|
122
|
+
// Versori platform imports
|
|
123
|
+
import { webhook, http } from '@versori/run';
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Note:** All imports are from actual SDK exports - this code compiles and runs as-is.
|
|
127
|
+
|
|
128
|
+
**⚠️ CRITICAL - Buffer Import Required:**
|
|
129
|
+
|
|
130
|
+
The `Buffer` import from `node:buffer` is **required** for Versori/Deno runtime compatibility:
|
|
131
|
+
- Versori and Deno do NOT have `Buffer` as a global (unlike Node.js)
|
|
132
|
+
- Without this import, code will crash with `ReferenceError: Buffer is not defined`
|
|
133
|
+
- Always include this import in Versori templates, even if not directly used in the template code
|
|
134
|
+
- Required for SDK internal operations and any Buffer usage in your code
|
|
135
|
+
|
|
136
|
+
**✅ VERSORI PLATFORM - Use Native Logs:**
|
|
137
|
+
|
|
138
|
+
- Use `log` from context: `const { log } = ctx;`
|
|
139
|
+
- Native Versori logs are simpler and automatically integrated with platform monitoring
|
|
140
|
+
|
|
141
|
+
**✅ VERSORI XML PARSING:**
|
|
142
|
+
|
|
143
|
+
Versori automatically parses XML payloads when `Content-Type: application/xml` is set:
|
|
144
|
+
- Attributes accessed via `$` (e.g., `element.$?.attributeName`)
|
|
145
|
+
- Text content accessed via `_` (e.g., `element._`)
|
|
146
|
+
- Nested elements accessed directly (e.g., `element.childElement`)
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 🔐 Fluent Commerce Connection Setup
|
|
151
|
+
|
|
152
|
+
**✅ BEST PRACTICE:** Store Fluent Commerce credentials in a Versori connection object:
|
|
153
|
+
|
|
154
|
+
**Connection Configuration:**
|
|
155
|
+
|
|
156
|
+
1. **Create Connection in Versori:**
|
|
157
|
+
- Name: `fluent_commerce`
|
|
158
|
+
- Type: HTTP Basic Auth or OAuth2
|
|
159
|
+
- Credentials: Fluent Commerce API credentials
|
|
160
|
+
|
|
161
|
+
2. **Connection Variables:**
|
|
162
|
+
- `FLUENT_BASE_URL` - Fluent Commerce API base URL (e.g., `https://api.fluentcommerce.com`)
|
|
163
|
+
- `FLUENT_RETAILER_ID` - Your retailer ID
|
|
164
|
+
- `FLUENT_CLIENT_ID` - OAuth client ID (if using OAuth2)
|
|
165
|
+
- `FLUENT_CLIENT_SECRET` - OAuth client secret (if using OAuth2)
|
|
166
|
+
|
|
167
|
+
**Benefits:**
|
|
168
|
+
- ✅ Credentials stored securely in Versori vault
|
|
169
|
+
- ✅ Connection can be reused across workflows
|
|
170
|
+
- ✅ No sensitive data in activation variables
|
|
171
|
+
- ✅ Easier credential rotation
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 📄 Expected XML Payload Format
|
|
176
|
+
|
|
177
|
+
The webhook accepts XML payloads with order reference information. Multiple formats are supported:
|
|
178
|
+
|
|
179
|
+
### Format 1: Simple Order Reference
|
|
180
|
+
|
|
181
|
+
```xml
|
|
182
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
183
|
+
<orderCancel>
|
|
184
|
+
<orderRef>ORD-12345</orderRef>
|
|
185
|
+
</orderCancel>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Format 2: With Attributes
|
|
189
|
+
|
|
190
|
+
```xml
|
|
191
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
192
|
+
<orderCancel>
|
|
193
|
+
<order ref="ORD-12345"/>
|
|
194
|
+
</orderCancel>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Format 3: Nested Structure
|
|
198
|
+
|
|
199
|
+
```xml
|
|
200
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
201
|
+
<orderCancel>
|
|
202
|
+
<order>
|
|
203
|
+
<reference>ORD-12345</reference>
|
|
204
|
+
<reason>Customer requested cancellation</reason>
|
|
205
|
+
</order>
|
|
206
|
+
</orderCancel>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Format 4: Root Element with Attributes
|
|
210
|
+
|
|
211
|
+
```xml
|
|
212
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
213
|
+
<orderCancel orderRef="ORD-12345">
|
|
214
|
+
<reason>Customer requested cancellation</reason>
|
|
215
|
+
</orderCancel>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Note:** The template extracts order reference from various XML patterns. Customize the extraction logic in the service if your payload uses different element names.
|
|
219
|
+
|
|
220
|
+
**Versori XML Parsing Format (CRITICAL):**
|
|
221
|
+
|
|
222
|
+
When Versori receives XML with `Content-Type: application/xml`, it **automatically parses** the XML into a JavaScript object. You do NOT need to manually parse XML - Versori handles it automatically.
|
|
223
|
+
|
|
224
|
+
**Access Patterns:**
|
|
225
|
+
- **Attributes**: `element.$?.attributeName` (e.g., `<order ref="ORD-12345"/>` → `order.$?.ref`)
|
|
226
|
+
- **Text content**: `element._` or direct property access (e.g., `<orderRef>ORD-12345</orderRef>` → `orderRef._` or `orderRef`)
|
|
227
|
+
- **Nested elements**: Direct property access (e.g., `<orderCancel><orderRef>...</orderRef></orderCancel>` → `orderCancel.orderRef`)
|
|
228
|
+
|
|
229
|
+
**Examples:**
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// XML: <order ref="ORD-12345"/>
|
|
233
|
+
// Versori auto-parsed: { order: { $: { ref: "ORD-12345" } } }
|
|
234
|
+
const orderRef = parsed.order?.$?.ref; // ✅ "ORD-12345"
|
|
235
|
+
|
|
236
|
+
// XML: <orderRef>ORD-12345</orderRef>
|
|
237
|
+
// Versori auto-parsed: { orderRef: { _: "ORD-12345" } } OR { orderRef: "ORD-12345" }
|
|
238
|
+
const orderRef = parsed.orderRef?._ || parsed.orderRef; // ✅ "ORD-12345"
|
|
239
|
+
|
|
240
|
+
// XML: <orderCancel><order ref="ORD-12345"/></orderCancel>
|
|
241
|
+
// Versori auto-parsed: { orderCancel: { order: { $: { ref: "ORD-12345" } } } }
|
|
242
|
+
const orderRef = parsed.orderCancel?.order?.$?.ref; // ✅ "ORD-12345"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Key Point:** Versori automatically parses XML when `Content-Type: application/xml` is set. Your webhook receives `ctx.data` as a pre-parsed JavaScript object - no manual XML parsing needed!
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Event Payload Structure
|
|
250
|
+
|
|
251
|
+
The template builds and sends this event structure:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"retailerId": "{{retailer_id}}",
|
|
256
|
+
"name": "OrderCancel",
|
|
257
|
+
"entityRef": "{{order_ref}}",
|
|
258
|
+
"entityType": "ORDER"
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Fields:**
|
|
263
|
+
- `retailerId`: Retrieved from Fluent Commerce connection or activation variable
|
|
264
|
+
- `name`: Fixed as "OrderCancel"
|
|
265
|
+
- `entityRef`: Extracted from incoming XML payload
|
|
266
|
+
- `entityType`: Fixed as "ORDER"
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 🔧 Complete Production Code
|
|
271
|
+
|
|
272
|
+
### Versori Workflows Structure
|
|
273
|
+
|
|
274
|
+
**Key Concept**: Versori workflows are organized by **trigger type** at the first level, then by **specific workflow** with descriptive file names.
|
|
275
|
+
|
|
276
|
+
**Trigger Types:**
|
|
277
|
+
- **`webhook()`** → HTTP-based triggers (event-driven) - Creates HTTP endpoints
|
|
278
|
+
|
|
279
|
+
**Execution Steps (chained to triggers):**
|
|
280
|
+
- **`http()`** → External API calls (chained from webhook)
|
|
281
|
+
|
|
282
|
+
### Recommended Project Structure
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
order-cancel-webhook/
|
|
286
|
+
├── index.ts # Entry point - exports all workflows
|
|
287
|
+
└── src/
|
|
288
|
+
├── workflows/
|
|
289
|
+
│ └── webhook/
|
|
290
|
+
│ └── order-cancel.ts # Webhook: Order cancel handler
|
|
291
|
+
│
|
|
292
|
+
├── services/
|
|
293
|
+
│ └── order-cancel.service.ts # Shared orchestration logic
|
|
294
|
+
│
|
|
295
|
+
└── types/
|
|
296
|
+
└── order-cancel.types.ts # Type definitions
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Benefits:**
|
|
300
|
+
- ✅ Clear structure (webhook handlers in `webhook/`)
|
|
301
|
+
- ✅ Descriptive file names (easy to browse and understand)
|
|
302
|
+
- ✅ Reusable code in `services/` (DRY principle)
|
|
303
|
+
- ✅ Centralized type definitions
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Workflow Files
|
|
308
|
+
|
|
309
|
+
### 1. Webhook Workflow (`src/workflows/webhook/order-cancel.ts`)
|
|
310
|
+
|
|
311
|
+
**Purpose**: Handle order cancel requests via webhook
|
|
312
|
+
**Trigger**: HTTP POST
|
|
313
|
+
**Endpoint**: `POST https://{workspace}.versori.run/order-cancel`
|
|
314
|
+
**Use Cases**: Order cancellation from external systems, manual cancellations
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { webhook, http } from '@versori/run';
|
|
318
|
+
import { executeOrderCancel } from '../../services/order-cancel.service';
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Webhook: Order Cancel Handler
|
|
322
|
+
*
|
|
323
|
+
* Endpoint: POST https://{workspace}.versori.run/order-cancel
|
|
324
|
+
* Request body: XML payload with order reference
|
|
325
|
+
* Content-Type: application/xml
|
|
326
|
+
*
|
|
327
|
+
* Pattern: webhook().then(http()) - needs Fluent API access
|
|
328
|
+
* Uses shared service: order-cancel.service.ts
|
|
329
|
+
*
|
|
330
|
+
* SECURITY: Authentication handled via connection parameter
|
|
331
|
+
* No manual API key validation needed - Versori manages this via connection auth
|
|
332
|
+
*/
|
|
333
|
+
export const orderCancelWebhook = webhook('order-cancel', {
|
|
334
|
+
// ✅ Webhook response mode: 'sync'
|
|
335
|
+
// - HTTP response sent when handler completes
|
|
336
|
+
// - Returns event ID and success status immediately after Fluent accepts event
|
|
337
|
+
// - Alternative: 'async' mode would return immediately (before processing)
|
|
338
|
+
response: { mode: 'sync' },
|
|
339
|
+
connection: 'order-cancel-webhook', // Versori validates API key
|
|
340
|
+
}).then(
|
|
341
|
+
http('process-order-cancel', { connection: 'fluent_commerce' }, async ctx => {
|
|
342
|
+
const { log, data } = ctx;
|
|
343
|
+
|
|
344
|
+
log.info('🚀 [WEBHOOK] Order cancel request received', {
|
|
345
|
+
timestamp: new Date().toISOString(),
|
|
346
|
+
hasPayload: !!data,
|
|
347
|
+
contentType: ctx.request?.headers?.get('content-type'),
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
try {
|
|
351
|
+
// Reuse shared orchestration logic
|
|
352
|
+
const result = await executeOrderCancel(ctx);
|
|
353
|
+
|
|
354
|
+
log.info('✅ [WEBHOOK] Order cancel completed successfully', {
|
|
355
|
+
orderRef: result.orderRef,
|
|
356
|
+
eventId: result.eventId,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
success: true,
|
|
361
|
+
orderRef: result.orderRef,
|
|
362
|
+
eventId: result.eventId,
|
|
363
|
+
message: 'Order cancel event sent successfully',
|
|
364
|
+
};
|
|
365
|
+
} catch (e: any) {
|
|
366
|
+
log.error('❌ [WEBHOOK] Order cancel failed', {
|
|
367
|
+
message: e?.message,
|
|
368
|
+
stack: e?.stack,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
success: false,
|
|
373
|
+
error: e?.message || 'Unknown error occurred',
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
### 2. Entry Point (`index.ts`)
|
|
383
|
+
|
|
384
|
+
**Purpose**: Register all workflows with Versori platform
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
/**
|
|
388
|
+
* Entry Point - Registers all workflows with Versori platform
|
|
389
|
+
*
|
|
390
|
+
* Versori automatically discovers and registers exported workflows
|
|
391
|
+
*
|
|
392
|
+
* File Structure:
|
|
393
|
+
* - src/workflows/webhook/ → HTTP-based triggers (webhooks)
|
|
394
|
+
* - src/services/ → Shared service logic (reusable across workflows)
|
|
395
|
+
*/
|
|
396
|
+
|
|
397
|
+
// Import webhook workflows
|
|
398
|
+
import { orderCancelWebhook } from './src/workflows/webhook/order-cancel';
|
|
399
|
+
|
|
400
|
+
// Register all workflows with Versori platform
|
|
401
|
+
export {
|
|
402
|
+
// Webhooks (HTTP-based triggers)
|
|
403
|
+
orderCancelWebhook,
|
|
404
|
+
};
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**What Gets Exposed:**
|
|
408
|
+
- ✅ `orderCancelWebhook` → `https://{workspace}.versori.run/order-cancel`
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 3. Type Definitions (`src/types/order-cancel.types.ts`)
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
/**
|
|
416
|
+
* Type Definitions for Order Cancel Ingestion
|
|
417
|
+
*
|
|
418
|
+
* Centralized type definitions for order cancel workflow
|
|
419
|
+
*/
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Versori XML parsed format
|
|
423
|
+
* Attributes accessed via $, text content via _
|
|
424
|
+
*/
|
|
425
|
+
export interface VersoriXMLParsed {
|
|
426
|
+
[key: string]: unknown;
|
|
427
|
+
$?: Record<string, unknown>; // Attributes
|
|
428
|
+
_?: string; // Text content
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Order cancel request payload (XML parsed format)
|
|
433
|
+
*/
|
|
434
|
+
export interface OrderCancelPayload {
|
|
435
|
+
orderCancel?: {
|
|
436
|
+
orderRef?: VersoriXMLParsed | string;
|
|
437
|
+
order?: {
|
|
438
|
+
$?: {
|
|
439
|
+
ref?: string;
|
|
440
|
+
};
|
|
441
|
+
reference?: VersoriXMLParsed | string;
|
|
442
|
+
ref?: VersoriXMLParsed | string;
|
|
443
|
+
};
|
|
444
|
+
$?: {
|
|
445
|
+
orderRef?: string;
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
order?: {
|
|
449
|
+
$?: {
|
|
450
|
+
ref?: string;
|
|
451
|
+
};
|
|
452
|
+
reference?: VersoriXMLParsed | string;
|
|
453
|
+
ref?: VersoriXMLParsed | string;
|
|
454
|
+
};
|
|
455
|
+
[key: string]: unknown; // Allow additional fields
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Order cancel event payload
|
|
460
|
+
*/
|
|
461
|
+
export interface OrderCancelEvent {
|
|
462
|
+
retailerId: string;
|
|
463
|
+
name: 'OrderCancel';
|
|
464
|
+
entityRef: string;
|
|
465
|
+
entityType: 'ORDER';
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Order cancel result
|
|
470
|
+
*/
|
|
471
|
+
export interface OrderCancelResult {
|
|
472
|
+
success: boolean;
|
|
473
|
+
orderRef: string;
|
|
474
|
+
eventId?: string;
|
|
475
|
+
error?: string;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Versori Context Interface
|
|
480
|
+
* Represents the Versori runtime context passed to workflow functions
|
|
481
|
+
*/
|
|
482
|
+
export interface VersoriContext {
|
|
483
|
+
log: {
|
|
484
|
+
info: (message: string, data?: Record<string, unknown>) => void;
|
|
485
|
+
warn: (message: string, data?: Record<string, unknown>) => void;
|
|
486
|
+
error: (message: string, data?: Record<string, unknown>) => void;
|
|
487
|
+
debug?: (message: string, data?: Record<string, unknown>) => void;
|
|
488
|
+
};
|
|
489
|
+
data?: unknown;
|
|
490
|
+
request?: Request;
|
|
491
|
+
activation: {
|
|
492
|
+
getVariable: (name: string) => string | undefined;
|
|
493
|
+
connections?: Record<string, unknown>;
|
|
494
|
+
};
|
|
495
|
+
connections?: Record<string, unknown>;
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 4. Service: Order Cancel Processor (`src/services/order-cancel.service.ts`)
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
/**
|
|
505
|
+
* Order Cancel Service
|
|
506
|
+
*
|
|
507
|
+
* Processes order cancel requests: extracts order reference from XML payload,
|
|
508
|
+
* builds OrderCancel event, and sends to Fluent Commerce Event API.
|
|
509
|
+
* Handles Versori XML parsing format ($ for attributes, _ for text).
|
|
510
|
+
*/
|
|
511
|
+
|
|
512
|
+
import {
|
|
513
|
+
createClient,
|
|
514
|
+
XMLParserService,
|
|
515
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
516
|
+
import type { FluentClient } from '@fluentcommerce/fc-connect-sdk';
|
|
517
|
+
import type {
|
|
518
|
+
OrderCancelPayload,
|
|
519
|
+
OrderCancelResult,
|
|
520
|
+
VersoriContext,
|
|
521
|
+
VersoriXMLParsed,
|
|
522
|
+
} from '../types/order-cancel.types';
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Extract text content from Versori XML parsed format
|
|
526
|
+
* Handles both object format ({ _: "text" }) and direct string
|
|
527
|
+
*/
|
|
528
|
+
function extractTextContent(value: VersoriXMLParsed | string | undefined): string | null {
|
|
529
|
+
if (!value) {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (typeof value === 'string') {
|
|
534
|
+
return value;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (typeof value === 'object' && '_' in value) {
|
|
538
|
+
const text = value._;
|
|
539
|
+
return typeof text === 'string' ? text : null;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Extract order reference from XML payload
|
|
547
|
+
*
|
|
548
|
+
* Supports multiple XML formats:
|
|
549
|
+
* - <orderCancel><orderRef>ORD-12345</orderRef></orderCancel>
|
|
550
|
+
* - <orderCancel><order ref="ORD-12345"/></orderCancel>
|
|
551
|
+
* - <orderCancel><order><reference>ORD-12345</reference></order></orderCancel>
|
|
552
|
+
* - <orderCancel orderRef="ORD-12345"/>
|
|
553
|
+
*/
|
|
554
|
+
function extractOrderRef(payload: OrderCancelPayload): string | null {
|
|
555
|
+
// Try orderCancel.orderRef (text content)
|
|
556
|
+
if (payload.orderCancel) {
|
|
557
|
+
const orderCancel = payload.orderCancel;
|
|
558
|
+
|
|
559
|
+
// Try orderCancel.orderRef as text
|
|
560
|
+
if (orderCancel.orderRef) {
|
|
561
|
+
const ref = extractTextContent(orderCancel.orderRef);
|
|
562
|
+
if (ref) {
|
|
563
|
+
return ref;
|
|
564
|
+
}
|
|
565
|
+
// Try as direct string
|
|
566
|
+
if (typeof orderCancel.orderRef === 'string') {
|
|
567
|
+
return orderCancel.orderRef;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Try orderCancel.order.$?.ref (attribute)
|
|
572
|
+
if (
|
|
573
|
+
orderCancel.order &&
|
|
574
|
+
typeof orderCancel.order === 'object' &&
|
|
575
|
+
'$' in orderCancel.order
|
|
576
|
+
) {
|
|
577
|
+
const attrs = orderCancel.order.$ as Record<string, unknown>;
|
|
578
|
+
if (attrs && typeof attrs.ref === 'string') {
|
|
579
|
+
return attrs.ref;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Try orderCancel.order.reference (text content)
|
|
584
|
+
if (
|
|
585
|
+
orderCancel.order &&
|
|
586
|
+
typeof orderCancel.order === 'object' &&
|
|
587
|
+
'reference' in orderCancel.order
|
|
588
|
+
) {
|
|
589
|
+
const ref = extractTextContent(orderCancel.order.reference as VersoriXMLParsed);
|
|
590
|
+
if (ref) {
|
|
591
|
+
return ref;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Try orderCancel.order.ref (text content)
|
|
596
|
+
if (
|
|
597
|
+
orderCancel.order &&
|
|
598
|
+
typeof orderCancel.order === 'object' &&
|
|
599
|
+
'ref' in orderCancel.order
|
|
600
|
+
) {
|
|
601
|
+
const ref = extractTextContent(orderCancel.order.ref as VersoriXMLParsed);
|
|
602
|
+
if (ref) {
|
|
603
|
+
return ref;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Try orderCancel.$?.orderRef (root attribute)
|
|
608
|
+
if ('$' in orderCancel && orderCancel.$) {
|
|
609
|
+
const attrs = orderCancel.$ as Record<string, unknown>;
|
|
610
|
+
if (attrs && typeof attrs.orderRef === 'string') {
|
|
611
|
+
return attrs.orderRef;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Try direct order element
|
|
617
|
+
if (payload.order) {
|
|
618
|
+
const order = payload.order;
|
|
619
|
+
|
|
620
|
+
// Try order.$?.ref (attribute)
|
|
621
|
+
if (typeof order === 'object' && '$' in order && order.$) {
|
|
622
|
+
const attrs = order.$ as Record<string, unknown>;
|
|
623
|
+
if (attrs && typeof attrs.ref === 'string') {
|
|
624
|
+
return attrs.ref;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Try order.reference (text content)
|
|
629
|
+
if (typeof order === 'object' && 'reference' in order) {
|
|
630
|
+
const ref = extractTextContent(order.reference as VersoriXMLParsed);
|
|
631
|
+
if (ref) {
|
|
632
|
+
return ref;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Try order.ref (text content)
|
|
637
|
+
if (typeof order === 'object' && 'ref' in order) {
|
|
638
|
+
const ref = extractTextContent(order.ref as VersoriXMLParsed);
|
|
639
|
+
if (ref) {
|
|
640
|
+
return ref;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Parse webhook payload from Versori context
|
|
650
|
+
*
|
|
651
|
+
* CRITICAL: Versori automatically parses XML when Content-Type: application/xml is set.
|
|
652
|
+
* The ctx.data will be a pre-parsed JavaScript object - no manual parsing needed!
|
|
653
|
+
*
|
|
654
|
+
* Handles both pre-parsed XML (ctx.data) and raw request body (ctx.request) as fallback
|
|
655
|
+
*/
|
|
656
|
+
async function parseWebhookPayload(
|
|
657
|
+
ctx: VersoriContext
|
|
658
|
+
): Promise<OrderCancelPayload | null> {
|
|
659
|
+
const { log, data, request } = ctx;
|
|
660
|
+
|
|
661
|
+
// ✅ Scenario 1: Pre-parsed XML (Versori auto-parsed when Content-Type: application/xml)
|
|
662
|
+
// This is the PRIMARY path - Versori handles XML parsing automatically
|
|
663
|
+
if (data && typeof data === 'object' && data !== null) {
|
|
664
|
+
log.info('📥 [PARSE] Using Versori auto-parsed XML payload', {
|
|
665
|
+
hasData: true,
|
|
666
|
+
dataKeys: Object.keys(data),
|
|
667
|
+
contentType: request?.headers?.get('content-type'),
|
|
668
|
+
});
|
|
669
|
+
return data as OrderCancelPayload;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// ⚠️ Scenario 2: Raw request body (fallback - should rarely be needed)
|
|
673
|
+
// Only used if Versori didn't auto-parse (e.g., wrong Content-Type header)
|
|
674
|
+
if (request && typeof request.text === 'function') {
|
|
675
|
+
log.warn('📥 [PARSE] Falling back to manual XML parsing (Content-Type may be incorrect)');
|
|
676
|
+
try {
|
|
677
|
+
const rawBody = await request.text();
|
|
678
|
+
if (!rawBody || rawBody.trim() === '') {
|
|
679
|
+
log.error('❌ [PARSE] Request body is empty');
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const parser = new XMLParserService(log);
|
|
684
|
+
const parsed = await parser.parse(rawBody);
|
|
685
|
+
|
|
686
|
+
log.info('📥 [PARSE] Successfully parsed XML payload', {
|
|
687
|
+
parsedKeys: Object.keys(parsed),
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
return parsed as OrderCancelPayload;
|
|
691
|
+
} catch (parseError: unknown) {
|
|
692
|
+
const errorMessage =
|
|
693
|
+
parseError instanceof Error ? parseError.message : String(parseError);
|
|
694
|
+
log.error('❌ [PARSE] Failed to parse XML payload', {
|
|
695
|
+
error: errorMessage,
|
|
696
|
+
});
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
log.error('❌ [PARSE] No valid payload found in context');
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Build OrderCancel event payload
|
|
707
|
+
*/
|
|
708
|
+
function buildOrderCancelEvent(
|
|
709
|
+
orderRef: string,
|
|
710
|
+
retailerId: string
|
|
711
|
+
): {
|
|
712
|
+
retailerId: string;
|
|
713
|
+
name: 'OrderCancel';
|
|
714
|
+
entityRef: string;
|
|
715
|
+
entityType: 'ORDER';
|
|
716
|
+
} {
|
|
717
|
+
return {
|
|
718
|
+
retailerId,
|
|
719
|
+
name: 'OrderCancel',
|
|
720
|
+
entityRef: orderRef,
|
|
721
|
+
entityType: 'ORDER',
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Execute order cancel workflow
|
|
727
|
+
*
|
|
728
|
+
* Main orchestration function:
|
|
729
|
+
* 1. Parse webhook payload
|
|
730
|
+
* 2. Extract order reference
|
|
731
|
+
* 3. Create Fluent client
|
|
732
|
+
* 4. Build event payload
|
|
733
|
+
* 5. Send event to Fluent Commerce
|
|
734
|
+
*/
|
|
735
|
+
export async function executeOrderCancel(
|
|
736
|
+
ctx: VersoriContext
|
|
737
|
+
): Promise<OrderCancelResult> {
|
|
738
|
+
const { log, activation } = ctx;
|
|
739
|
+
|
|
740
|
+
log.info('🚀 [SERVICE] Starting order cancel processing');
|
|
741
|
+
|
|
742
|
+
// STEP 1: Parse webhook payload
|
|
743
|
+
// ✅ Versori automatically parses XML when Content-Type: application/xml is set
|
|
744
|
+
// ctx.data will be a pre-parsed JavaScript object - no manual parsing needed!
|
|
745
|
+
const payload = await parseWebhookPayload(ctx);
|
|
746
|
+
if (!payload) {
|
|
747
|
+
throw new Error(
|
|
748
|
+
'Failed to parse webhook payload. Ensure Content-Type: application/xml is set in request headers.'
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
log.info('📥 [SERVICE] Payload parsed successfully (Versori auto-parsed XML)', {
|
|
753
|
+
payloadKeys: Object.keys(payload),
|
|
754
|
+
note: 'Versori automatically parses XML when Content-Type: application/xml is set',
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
// STEP 2: Extract order reference
|
|
758
|
+
const orderRef = extractOrderRef(payload);
|
|
759
|
+
if (!orderRef) {
|
|
760
|
+
log.error('❌ [SERVICE] Order reference not found in XML payload', {
|
|
761
|
+
payloadKeys: Object.keys(payload),
|
|
762
|
+
expectedPatterns: [
|
|
763
|
+
'orderCancel.orderRef',
|
|
764
|
+
'orderCancel.order[@ref]',
|
|
765
|
+
'orderCancel.order.reference',
|
|
766
|
+
'orderCancel[@orderRef]',
|
|
767
|
+
],
|
|
768
|
+
});
|
|
769
|
+
throw new Error(
|
|
770
|
+
'Order reference not found in XML payload. Expected patterns: orderCancel.orderRef, orderCancel.order[@ref], orderCancel.order.reference, or orderCancel[@orderRef]'
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
log.info('✅ [SERVICE] Order reference extracted', { orderRef });
|
|
775
|
+
|
|
776
|
+
// STEP 3: Get retailer ID from activation variable or connection
|
|
777
|
+
const retailerId =
|
|
778
|
+
activation.getVariable('FLUENT_RETAILER_ID') ||
|
|
779
|
+
(activation.connections?.fluent_commerce as any)?.retailerId;
|
|
780
|
+
|
|
781
|
+
if (!retailerId) {
|
|
782
|
+
log.error('❌ [SERVICE] Retailer ID not found', {
|
|
783
|
+
checkedVariables: ['FLUENT_RETAILER_ID'],
|
|
784
|
+
hasConnection: !!activation.connections?.fluent_commerce,
|
|
785
|
+
});
|
|
786
|
+
throw new Error(
|
|
787
|
+
'Retailer ID not found. Set FLUENT_RETAILER_ID activation variable or configure in connection.'
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
log.info('✅ [SERVICE] Retailer ID retrieved', { retailerId });
|
|
792
|
+
|
|
793
|
+
// STEP 4: Create Fluent client
|
|
794
|
+
// ✅ Pass ctx directly - createClient auto-detects Versori context
|
|
795
|
+
const client = await createClient(ctx);
|
|
796
|
+
|
|
797
|
+
log.info('✅ [SERVICE] Fluent client created');
|
|
798
|
+
|
|
799
|
+
// STEP 5: Build event payload
|
|
800
|
+
const eventPayload = buildOrderCancelEvent(orderRef, retailerId);
|
|
801
|
+
|
|
802
|
+
log.info('📤 [SERVICE] Sending OrderCancel event', {
|
|
803
|
+
orderRef,
|
|
804
|
+
retailerId,
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// STEP 6: Send event to Fluent Commerce
|
|
808
|
+
// ✅ Using 'async' mode (recommended):
|
|
809
|
+
// - Fluent accepts event immediately and processes in background
|
|
810
|
+
// - Returns event ID quickly (non-blocking)
|
|
811
|
+
// - Better performance for webhook responses
|
|
812
|
+
// - Alternative: 'sync' mode waits for event processing (slower, blocking)
|
|
813
|
+
// - Sync mode success: { eventId: "...", eventStatus: "COMPLETE" }
|
|
814
|
+
// - Sync mode failure: { eventStatus: "FAILED" }
|
|
815
|
+
// - Sync mode no match: { eventId: "...", eventStatus: "NO_MATCH" }
|
|
816
|
+
const response = await client.sendEvent(eventPayload, 'async');
|
|
817
|
+
|
|
818
|
+
// Extract event ID from Fluent response
|
|
819
|
+
// Async mode response format: { id: "evt_abc123", ... }
|
|
820
|
+
// Sync mode response format (success): { eventId: "...", eventStatus: "COMPLETE" }
|
|
821
|
+
// Sync mode response format (failure): { eventStatus: "FAILED" }
|
|
822
|
+
// Sync mode response format (no match): { eventId: "...", eventStatus: "NO_MATCH" }
|
|
823
|
+
let eventId: string | undefined;
|
|
824
|
+
|
|
825
|
+
if (response && typeof response === 'object') {
|
|
826
|
+
// Extract event ID first (needed for error messages)
|
|
827
|
+
if ('id' in response) {
|
|
828
|
+
eventId = response.id as string;
|
|
829
|
+
} else if ('eventId' in response) {
|
|
830
|
+
eventId = response.eventId as string;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Check for sync mode failure statuses
|
|
834
|
+
if ('eventStatus' in response) {
|
|
835
|
+
const eventStatus = response.eventStatus as string;
|
|
836
|
+
|
|
837
|
+
if (eventStatus === 'FAILED') {
|
|
838
|
+
log.error('❌ [SERVICE] OrderCancel event failed (sync mode)', {
|
|
839
|
+
orderRef,
|
|
840
|
+
eventId,
|
|
841
|
+
eventStatus,
|
|
842
|
+
response,
|
|
843
|
+
});
|
|
844
|
+
throw new Error('Order cancel event failed. Event status: FAILED');
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (eventStatus === 'NO_MATCH') {
|
|
848
|
+
log.error('❌ [SERVICE] OrderCancel event no match (sync mode)', {
|
|
849
|
+
orderRef,
|
|
850
|
+
eventId,
|
|
851
|
+
eventStatus,
|
|
852
|
+
response,
|
|
853
|
+
});
|
|
854
|
+
throw new Error(
|
|
855
|
+
'Order cancel event did not match any workflow. Possible causes: incorrect event name, status mismatch, or entity not found. Event status: NO_MATCH'
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (eventStatus === 'COMPLETE') {
|
|
860
|
+
log.info('✅ [SERVICE] OrderCancel event completed (sync mode)', {
|
|
861
|
+
orderRef,
|
|
862
|
+
eventId,
|
|
863
|
+
eventStatus,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
log.info('✅ [SERVICE] OrderCancel event sent successfully', {
|
|
870
|
+
orderRef,
|
|
871
|
+
eventId,
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
return {
|
|
875
|
+
success: true,
|
|
876
|
+
orderRef,
|
|
877
|
+
eventId,
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
---
|
|
883
|
+
|
|
884
|
+
## 5. Configuration
|
|
885
|
+
|
|
886
|
+
### Activation Variables
|
|
887
|
+
|
|
888
|
+
Configure these variables in Versori activation settings:
|
|
889
|
+
|
|
890
|
+
```json
|
|
891
|
+
{
|
|
892
|
+
"FLUENT_RETAILER_ID": "your-retailer-id"
|
|
893
|
+
}
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
**Note:** If using Versori connection for Fluent Commerce, retailer ID can also be configured in the connection settings.
|
|
897
|
+
|
|
898
|
+
### Webhook Connection
|
|
899
|
+
|
|
900
|
+
Create a Versori connection for webhook authentication:
|
|
901
|
+
|
|
902
|
+
1. **Connection Name:** `order-cancel-webhook`
|
|
903
|
+
2. **Type:** API Key or Basic Auth
|
|
904
|
+
3. **Purpose:** Authenticate incoming webhook requests
|
|
905
|
+
|
|
906
|
+
**Example webhook call:**
|
|
907
|
+
|
|
908
|
+
```bash
|
|
909
|
+
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
910
|
+
-H "Content-Type: application/xml" \
|
|
911
|
+
-H "X-API-Key: your-api-key" \
|
|
912
|
+
--data-binary @order-cancel.xml
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
**Example XML file (`order-cancel.xml`):**
|
|
916
|
+
|
|
917
|
+
```xml
|
|
918
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
919
|
+
<orderCancel>
|
|
920
|
+
<orderRef>ORD-12345</orderRef>
|
|
921
|
+
</orderCancel>
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
**CRITICAL: Content-Type Header**
|
|
925
|
+
|
|
926
|
+
The `Content-Type: application/xml` header is **required** for Versori to automatically parse the XML. Without this header, Versori will not parse the XML and you'll need to manually parse using `XMLParserService`.
|
|
927
|
+
|
|
928
|
+
**✅ CORRECT:**
|
|
929
|
+
```bash
|
|
930
|
+
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
931
|
+
-H "Content-Type: application/xml" \ # ✅ Required!
|
|
932
|
+
-H "X-API-Key: your-api-key" \
|
|
933
|
+
--data-binary @order-cancel.xml
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
**❌ WRONG:**
|
|
937
|
+
```bash
|
|
938
|
+
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
939
|
+
-H "Content-Type: text/plain" \ # ❌ Wrong Content-Type
|
|
940
|
+
-H "X-API-Key: your-api-key" \
|
|
941
|
+
--data-binary @order-cancel.xml
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
---
|
|
945
|
+
|
|
946
|
+
## 6. Error Handling
|
|
947
|
+
|
|
948
|
+
The template includes comprehensive error handling:
|
|
949
|
+
|
|
950
|
+
### Payload Parsing Errors
|
|
951
|
+
|
|
952
|
+
- **Empty payload:** Returns error response
|
|
953
|
+
- **Invalid XML:** Returns error with parse details
|
|
954
|
+
- **Missing order reference:** Returns error with expected patterns
|
|
955
|
+
|
|
956
|
+
### Event Sending Errors
|
|
957
|
+
|
|
958
|
+
- **Network errors:** Logged and returned in error response
|
|
959
|
+
- **API errors:** Logged with full error details
|
|
960
|
+
- **Validation errors:** Logged with validation message
|
|
961
|
+
|
|
962
|
+
### Error Response Format
|
|
963
|
+
|
|
964
|
+
```json
|
|
965
|
+
{
|
|
966
|
+
"success": false,
|
|
967
|
+
"error": "Order reference not found in XML payload. Expected patterns: orderCancel.orderRef, orderCancel.order[@ref], orderCancel.order.reference, or orderCancel[@orderRef]"
|
|
968
|
+
}
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
---
|
|
972
|
+
|
|
973
|
+
## 7. Testing
|
|
974
|
+
|
|
975
|
+
### Test with cURL
|
|
976
|
+
|
|
977
|
+
```bash
|
|
978
|
+
# Test order cancel webhook with XML file
|
|
979
|
+
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
980
|
+
-H "Content-Type: application/xml" \
|
|
981
|
+
-H "X-API-Key: your-api-key" \
|
|
982
|
+
--data-binary @order-cancel.xml
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
### Test with Inline XML
|
|
986
|
+
|
|
987
|
+
```bash
|
|
988
|
+
curl -X POST https://{workspace}.versori.run/order-cancel \
|
|
989
|
+
-H "Content-Type: application/xml" \
|
|
990
|
+
-H "X-API-Key: your-api-key" \
|
|
991
|
+
-d '<?xml version="1.0" encoding="UTF-8"?><orderCancel><orderRef>ORD-12345</orderRef></orderCancel>'
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
### Expected Success Response
|
|
995
|
+
|
|
996
|
+
```json
|
|
997
|
+
{
|
|
998
|
+
"success": true,
|
|
999
|
+
"orderRef": "ORD-12345",
|
|
1000
|
+
"eventId": "evt_abc123",
|
|
1001
|
+
"message": "Order cancel event sent successfully"
|
|
1002
|
+
}
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
**Response Details:**
|
|
1006
|
+
- `success`: `true` indicates webhook processed successfully
|
|
1007
|
+
- `orderRef`: The order reference that was cancelled
|
|
1008
|
+
- `eventId`: Fluent Commerce event ID (returned from Event API async endpoint)
|
|
1009
|
+
- `message`: Human-readable success message
|
|
1010
|
+
|
|
1011
|
+
**Event API Mode: `async` (recommended)**
|
|
1012
|
+
- Fluent accepts the event immediately and returns an event ID
|
|
1013
|
+
- Event processing happens in the background
|
|
1014
|
+
- Webhook response includes the event ID for tracking
|
|
1015
|
+
- Response format: `{ id: "evt_abc123" }`
|
|
1016
|
+
|
|
1017
|
+
**Alternative: `sync` mode**
|
|
1018
|
+
- Fluent processes the event synchronously before responding
|
|
1019
|
+
- Slower response time (waits for event processing)
|
|
1020
|
+
- Success response: `{ eventId: "...", eventStatus: "COMPLETE" }`
|
|
1021
|
+
- Failure response: `{ eventStatus: "FAILED" }`
|
|
1022
|
+
- No match response: `{ eventId: "...", eventStatus: "NO_MATCH" }` (incorrect event name, status mismatch, or entity not found)
|
|
1023
|
+
- Use only if you need immediate confirmation of event processing
|
|
1024
|
+
|
|
1025
|
+
### Expected Error Response
|
|
1026
|
+
|
|
1027
|
+
**Webhook Processing Errors:**
|
|
1028
|
+
```json
|
|
1029
|
+
{
|
|
1030
|
+
"success": false,
|
|
1031
|
+
"error": "Order reference not found in XML payload"
|
|
1032
|
+
}
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
**Event API Sync Mode Responses:**
|
|
1036
|
+
|
|
1037
|
+
**Success (sync mode):**
|
|
1038
|
+
```json
|
|
1039
|
+
{
|
|
1040
|
+
"eventId": "421d1709-d0af-4d8a-b7b6-75e40c5fc038",
|
|
1041
|
+
"eventStatus": "COMPLETE"
|
|
1042
|
+
}
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
**Failure (sync mode):**
|
|
1046
|
+
```json
|
|
1047
|
+
{
|
|
1048
|
+
"eventStatus": "FAILED"
|
|
1049
|
+
}
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
**No Match (sync mode):**
|
|
1053
|
+
Occurs when event name is incorrect, status mismatch, or entity not found:
|
|
1054
|
+
```json
|
|
1055
|
+
{
|
|
1056
|
+
"eventId": "9782c552-033c-47c7-89ea-2b0068fbdd0a",
|
|
1057
|
+
"eventStatus": "NO_MATCH"
|
|
1058
|
+
}
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
The webhook will catch failures and return:
|
|
1062
|
+
```json
|
|
1063
|
+
{
|
|
1064
|
+
"success": false,
|
|
1065
|
+
"error": "Order cancel event failed. Event status: FAILED"
|
|
1066
|
+
}
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
Or for NO_MATCH:
|
|
1070
|
+
```json
|
|
1071
|
+
{
|
|
1072
|
+
"success": false,
|
|
1073
|
+
"error": "Order cancel event did not match any workflow. Possible causes: incorrect event name, status mismatch, or entity not found. Event status: NO_MATCH"
|
|
1074
|
+
}
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
---
|
|
1078
|
+
|
|
1079
|
+
## 8. Customization
|
|
1080
|
+
|
|
1081
|
+
### Custom Order Reference Element
|
|
1082
|
+
|
|
1083
|
+
If your XML uses different element names, modify `extractOrderRef()` in `order-cancel.service.ts`:
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
function extractOrderRef(payload: OrderCancelPayload): string | null {
|
|
1087
|
+
// Add your custom element extraction logic
|
|
1088
|
+
if (payload.customCancel && typeof payload.customCancel === 'object') {
|
|
1089
|
+
const cancel = payload.customCancel;
|
|
1090
|
+
if ('$' in cancel && cancel.$) {
|
|
1091
|
+
const attrs = cancel.$ as Record<string, unknown>;
|
|
1092
|
+
if (attrs && typeof attrs.orderId === 'string') {
|
|
1093
|
+
return attrs.orderId;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
// ... existing logic
|
|
1098
|
+
}
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
### Custom Event Name
|
|
1102
|
+
|
|
1103
|
+
To use a different event name, modify `buildOrderCancelEvent()`:
|
|
1104
|
+
|
|
1105
|
+
```typescript
|
|
1106
|
+
function buildOrderCancelEvent(
|
|
1107
|
+
orderRef: string,
|
|
1108
|
+
retailerId: string
|
|
1109
|
+
) {
|
|
1110
|
+
return {
|
|
1111
|
+
retailerId,
|
|
1112
|
+
name: 'CustomOrderCancel', // Change event name
|
|
1113
|
+
entityRef: orderRef,
|
|
1114
|
+
entityType: 'ORDER',
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
### Additional Event Data
|
|
1120
|
+
|
|
1121
|
+
To include additional data in the event:
|
|
1122
|
+
|
|
1123
|
+
```typescript
|
|
1124
|
+
function buildOrderCancelEvent(
|
|
1125
|
+
orderRef: string,
|
|
1126
|
+
retailerId: string,
|
|
1127
|
+
additionalData?: Record<string, unknown>
|
|
1128
|
+
) {
|
|
1129
|
+
return {
|
|
1130
|
+
retailerId,
|
|
1131
|
+
name: 'OrderCancel',
|
|
1132
|
+
entityRef: orderRef,
|
|
1133
|
+
entityType: 'ORDER',
|
|
1134
|
+
data: additionalData, // Add custom data
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
---
|
|
1140
|
+
|
|
1141
|
+
## Summary
|
|
1142
|
+
|
|
1143
|
+
✅ **DO:**
|
|
1144
|
+
- Use Versori connection for Fluent Commerce credentials
|
|
1145
|
+
- Handle both pre-parsed and raw XML payloads
|
|
1146
|
+
- Extract order reference with multiple fallback patterns
|
|
1147
|
+
- Handle Versori XML format ($ for attributes, _ for text)
|
|
1148
|
+
- Log all steps for debugging
|
|
1149
|
+
- Return clear error messages
|
|
1150
|
+
|
|
1151
|
+
❌ **DON'T:**
|
|
1152
|
+
- Hardcode credentials in code
|
|
1153
|
+
- Assume payload format without validation
|
|
1154
|
+
- Skip error handling
|
|
1155
|
+
- Use `sync` mode for Event API (use `async` for better performance and faster webhook responses)
|
|
1156
|
+
- Ignore Versori XML parsing format ($ and _)
|
|
1157
|
+
|
|
1158
|
+
---
|
|
1159
|
+
|
|
1160
|
+
## Next Steps
|
|
1161
|
+
|
|
1162
|
+
1. **Deploy:** Copy code to your Versori project
|
|
1163
|
+
2. **Configure:** Set up Fluent Commerce connection and activation variables
|
|
1164
|
+
3. **Test:** Test webhook with sample XML payloads
|
|
1165
|
+
4. **Monitor:** Check Versori logs for event processing
|
|
1166
|
+
|
|
1167
|
+
For more templates, see:
|
|
1168
|
+
- [JSON Payload Template](./template-ingestion-payload-json-order-cancel-event.md)
|
|
1169
|
+
- [Other Event API Templates](./event-api-guide.md)
|
|
1170
|
+
|