@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -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
package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md
CHANGED
|
@@ -1,590 +1,590 @@
|
|
|
1
|
-
# Module 8: Rubix Webhook Validation
|
|
2
|
-
|
|
3
|
-
**Level:** Intermediate
|
|
4
|
-
**Estimated Time:** 20 minutes
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This module covers webhook signature validation for **Fluent Commerce Rubix HTTP Call webhooks** - a specific use case different from Fluent Commerce Event webhooks.
|
|
9
|
-
|
|
10
|
-
**CRITICAL DISTINCTION**: This guide is for validating webhooks sent from **Rubix workflows** using the **HTTP Call action**, which have a different payload structure than Fluent Commerce Event webhooks.
|
|
11
|
-
|
|
12
|
-
## Learning Objectives
|
|
13
|
-
|
|
14
|
-
By the end of this module, you will:
|
|
15
|
-
|
|
16
|
-
- Understand the difference between Rubix HTTP Call webhooks and Event webhooks
|
|
17
|
-
- Know which validation method to use for each webhook type
|
|
18
|
-
- Implement correct signature validation for Rubix workflows
|
|
19
|
-
- Configure Rubix workflows to send properly signed webhooks
|
|
20
|
-
- Handle signature validation in Versori webhook handlers
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Rubix HTTP Call vs Event Webhooks
|
|
25
|
-
|
|
26
|
-
### Two Types of Fluent Commerce Webhooks
|
|
27
|
-
|
|
28
|
-
Fluent Commerce has **TWO different webhook types** with different payload structures:
|
|
29
|
-
|
|
30
|
-
| Feature | Rubix HTTP Call Webhooks | Event Webhooks |
|
|
31
|
-
|---------|-------------------------|----------------|
|
|
32
|
-
| **Trigger** | Rubix workflow HTTP Call action | Fluent Commerce event system |
|
|
33
|
-
| **Payload Structure** | Custom (entityId, entityRef, etc.) | Standard (name, id, retailerId, etc.) |
|
|
34
|
-
| **Use Case** | Custom workflow integrations | Event-driven integrations |
|
|
35
|
-
| **Validation Method** | ✅ `WebhookValidationService` | ✅ `FluentClient.validateWebhook()` |
|
|
36
|
-
| **Signature Headers** | `fluent-signature`, `flex.signature` | `fluent-signature`, `flex.signature` |
|
|
37
|
-
| **Public Key Required** | Yes (x509 base64) | Yes (x509 base64) |
|
|
38
|
-
|
|
39
|
-
### Rubix HTTP Call Webhook Payload
|
|
40
|
-
|
|
41
|
-
```json
|
|
42
|
-
{
|
|
43
|
-
"entityId": "order-123",
|
|
44
|
-
"entityRef": "ORD-001",
|
|
45
|
-
"entityType": "order",
|
|
46
|
-
"triggerSource": "ORDER_FULFILLMENT",
|
|
47
|
-
"retailerId": "1",
|
|
48
|
-
"timestamp": "2025-11-07T12:34:56.789Z"
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Event Webhook Payload
|
|
53
|
-
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"name": "ORDER.CREATED",
|
|
57
|
-
"id": "evt-123",
|
|
58
|
-
"retailerId": "1",
|
|
59
|
-
"entityId": "order-123",
|
|
60
|
-
"entityType": "ORDER",
|
|
61
|
-
"timestamp": "2025-11-07T12:34:56.789Z",
|
|
62
|
-
"data": { /* event data */ }
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**Key Difference**: Rubix webhooks have custom payload structure, Event webhooks have standardized fields (`name`, `id`, `retailerId`).
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## Which Validation Method to Use?
|
|
71
|
-
|
|
72
|
-
### ✅ Use WebhookValidationService for Rubix HTTP Calls
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
import { WebhookValidationService } from '@fluentcommerce/fc-connect-sdk';
|
|
76
|
-
|
|
77
|
-
// ✅ CORRECT for Rubix HTTP Call webhooks
|
|
78
|
-
// Versori log can be passed directly (no wrapper needed)
|
|
79
|
-
const validator = new WebhookValidationService({ strictValidation: true }, log);
|
|
80
|
-
|
|
81
|
-
const result = await validator.validateWebhook(
|
|
82
|
-
rawBodyString, // Raw payload string
|
|
83
|
-
headers, // Headers object
|
|
84
|
-
publicKey // x509 base64 public key
|
|
85
|
-
);
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**Why**: `WebhookValidationService` validates the signature without requiring specific payload fields.
|
|
89
|
-
|
|
90
|
-
### ✅ Use FluentClient.validateWebhook() for Event Webhooks
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
94
|
-
|
|
95
|
-
// ✅ CORRECT for Fluent Commerce Event webhooks
|
|
96
|
-
const client = await createClient({ ...ctx, log, connections });
|
|
97
|
-
|
|
98
|
-
const isValid = await client.validateWebhook(
|
|
99
|
-
payload, // FluentWebhookPayload object (must have name, id, retailerId)
|
|
100
|
-
signature, // Signature string
|
|
101
|
-
rawPayload // Raw payload string
|
|
102
|
-
);
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
**Why**: `FluentClient.validateWebhook()` does additional field validation for Event webhooks.
|
|
106
|
-
|
|
107
|
-
### ❌ Common Mistake: Using Wrong Method
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
// ❌ WRONG - Using FluentClient.validateWebhook() for Rubix webhooks
|
|
111
|
-
const client = await createClient({ ...ctx, log });
|
|
112
|
-
const isValid = await client.validateWebhook(
|
|
113
|
-
rubixPayload, // ❌ Rubix payload doesn't have name, id, retailerId
|
|
114
|
-
signature,
|
|
115
|
-
rawPayload
|
|
116
|
-
);
|
|
117
|
-
// Result: Always returns false (fails basic field validation)
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Rubix Webhook Validation Pattern
|
|
123
|
-
|
|
124
|
-
### Complete Implementation
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
import { webhook, http } from '@versori/run';
|
|
128
|
-
import {
|
|
129
|
-
createClient,
|
|
130
|
-
WebhookValidationService,
|
|
131
|
-
toStructuredLogger,
|
|
132
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Rubix HTTP Call Webhook Handler with Signature Validation
|
|
136
|
-
*/
|
|
137
|
-
export const rubixWebhook = webhook('rubix-webhook', {
|
|
138
|
-
response: { mode: 'sync' },
|
|
139
|
-
}).then(
|
|
140
|
-
http('validate-and-process', { connection: 'fluent_commerce' }, async ctx => {
|
|
141
|
-
const { log, activation, connections } = ctx;
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
// =========================================================
|
|
145
|
-
// STEP 1: VALIDATE WEBHOOK SIGNATURE
|
|
146
|
-
// =========================================================
|
|
147
|
-
|
|
148
|
-
// Get public key (x509 base64 encoded)
|
|
149
|
-
const publicKey = activation.getVariable('fluentPublicKey');
|
|
150
|
-
if (!publicKey) {
|
|
151
|
-
log.error('Missing fluentPublicKey activation variable');
|
|
152
|
-
return {
|
|
153
|
-
status: 500,
|
|
154
|
-
body: { error: 'Missing public key configuration' }
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Get raw payload (must be raw string, not parsed)
|
|
159
|
-
const rawPayload = activation.body || ctx.data;
|
|
160
|
-
const rawBodyString = typeof rawPayload === 'string'
|
|
161
|
-
? rawPayload
|
|
162
|
-
: JSON.stringify(rawPayload);
|
|
163
|
-
|
|
164
|
-
// Get headers
|
|
165
|
-
const headers = activation.headers || {};
|
|
166
|
-
|
|
167
|
-
// Check for signature headers
|
|
168
|
-
const hasSignature = !!(
|
|
169
|
-
headers['fluent-signature'] ||
|
|
170
|
-
headers['x-fluent-signature'] ||
|
|
171
|
-
headers['flex.signature']
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
if (hasSignature) {
|
|
175
|
-
// Create validator (Versori log can be passed directly)
|
|
176
|
-
const validator = new WebhookValidationService(
|
|
177
|
-
{ strictValidation: true },
|
|
178
|
-
log
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
// Validate signature
|
|
182
|
-
// Auto-detects: fluent-signature (SHA512) preferred, flex.signature (MD5) fallback
|
|
183
|
-
const result = await validator.validateWebhook(
|
|
184
|
-
rawBodyString, // Raw payload string
|
|
185
|
-
headers, // Headers object
|
|
186
|
-
publicKey // x509 base64 public key
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
if (!result.isValid) {
|
|
190
|
-
log.error('Invalid webhook signature', {
|
|
191
|
-
error: result.error,
|
|
192
|
-
algorithm: result.algorithm,
|
|
193
|
-
});
|
|
194
|
-
return {
|
|
195
|
-
status: 401,
|
|
196
|
-
body: { error: 'Invalid signature' }
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
log.info('✅ Webhook signature validated', {
|
|
201
|
-
algorithm: result.algorithm,
|
|
202
|
-
});
|
|
203
|
-
} else {
|
|
204
|
-
log.warn('No signature header found - skipping validation');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Parse payload (AFTER validation)
|
|
208
|
-
const payload = typeof rawPayload === 'string'
|
|
209
|
-
? JSON.parse(rawPayload)
|
|
210
|
-
: rawPayload;
|
|
211
|
-
|
|
212
|
-
// =========================================================
|
|
213
|
-
// STEP 2: EXTRACT ENTITY INFORMATION
|
|
214
|
-
// =========================================================
|
|
215
|
-
|
|
216
|
-
const { entityId, entityRef, entityType, retailerId } = payload;
|
|
217
|
-
|
|
218
|
-
if (!entityId && !entityRef) {
|
|
219
|
-
log.error('Missing entity identifier');
|
|
220
|
-
return {
|
|
221
|
-
status: 400,
|
|
222
|
-
body: { error: 'Missing entityId or entityRef' }
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
log.info('Processing Rubix webhook', {
|
|
227
|
-
entityId,
|
|
228
|
-
entityRef,
|
|
229
|
-
entityType,
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// =========================================================
|
|
233
|
-
// STEP 3: QUERY FLUENT FOR ENTITY DETAILS
|
|
234
|
-
// =========================================================
|
|
235
|
-
|
|
236
|
-
const fluentClient = await createClient({
|
|
237
|
-
...ctx,
|
|
238
|
-
log,
|
|
239
|
-
connections,
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
await fluentClient.setRetailerId(retailerId);
|
|
243
|
-
|
|
244
|
-
// Query entity (example: order)
|
|
245
|
-
const query = `
|
|
246
|
-
query GetEntity($ref: String!) {
|
|
247
|
-
order(ref: $ref) {
|
|
248
|
-
id
|
|
249
|
-
ref
|
|
250
|
-
status
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
`;
|
|
254
|
-
|
|
255
|
-
const result = await fluentClient.graphql({
|
|
256
|
-
query,
|
|
257
|
-
variables: { ref: entityRef }
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
if (result.errors?.length) {
|
|
261
|
-
log.error('GraphQL query failed', { errors: result.errors });
|
|
262
|
-
return {
|
|
263
|
-
status: 502,
|
|
264
|
-
body: { error: 'Failed to fetch entity' }
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const entity = result.data?.order;
|
|
269
|
-
|
|
270
|
-
// =========================================================
|
|
271
|
-
// STEP 4: PROCESS ENTITY
|
|
272
|
-
// =========================================================
|
|
273
|
-
|
|
274
|
-
log.info('Entity retrieved', {
|
|
275
|
-
entityId: entity.id,
|
|
276
|
-
entityRef: entity.ref,
|
|
277
|
-
status: entity.status,
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// Your business logic here
|
|
281
|
-
await processEntity(entity);
|
|
282
|
-
|
|
283
|
-
return {
|
|
284
|
-
status: 200,
|
|
285
|
-
body: {
|
|
286
|
-
success: true,
|
|
287
|
-
entityId: entity.id,
|
|
288
|
-
entityRef: entity.ref,
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
} catch (error: any) {
|
|
293
|
-
log.error('Webhook processing failed', {
|
|
294
|
-
error: error.message,
|
|
295
|
-
stack: error.stack,
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
return {
|
|
299
|
-
status: 500,
|
|
300
|
-
body: { error: error.message }
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
})
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
async function processEntity(entity: any): Promise<void> {
|
|
307
|
-
// Your processing logic
|
|
308
|
-
console.log('Processing entity:', entity.ref);
|
|
309
|
-
}
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
|
|
314
|
-
## Configuring Rubix Workflows
|
|
315
|
-
|
|
316
|
-
### Step 1: Add HTTP Call Action in Rubix
|
|
317
|
-
|
|
318
|
-
In your Rubix workflow, add an **HTTP Call** action:
|
|
319
|
-
|
|
320
|
-
**Action Configuration:**
|
|
321
|
-
```
|
|
322
|
-
Method: POST
|
|
323
|
-
URL: https://{workspace}.versori.run/rubix-webhook
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
**Headers:**
|
|
327
|
-
```json
|
|
328
|
-
{
|
|
329
|
-
"Content-Type": "application/json",
|
|
330
|
-
"fluent-signature": "${webhookSignature}",
|
|
331
|
-
"x-retailer-id": "${retailerId}"
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
**Payload:**
|
|
336
|
-
```json
|
|
337
|
-
{
|
|
338
|
-
"entityId": "${entity.id}",
|
|
339
|
-
"entityRef": "${entity.ref}",
|
|
340
|
-
"entityType": "order",
|
|
341
|
-
"retailerId": "${retailerId}",
|
|
342
|
-
"timestamp": "${currentTimestamp}"
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
### Step 2: Configure Webhook Signature in Rubix
|
|
347
|
-
|
|
348
|
-
Fluent Commerce automatically generates signatures using its private key. The signature is available as `${webhookSignature}` in Rubix workflows.
|
|
349
|
-
|
|
350
|
-
**Important**: The signature is generated server-side by Fluent Commerce. You don't need to generate it manually in Rubix.
|
|
351
|
-
|
|
352
|
-
### Step 3: Configure Public Key in Versori
|
|
353
|
-
|
|
354
|
-
In Versori Dashboard → Activation Variables:
|
|
355
|
-
|
|
356
|
-
```
|
|
357
|
-
fluentPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/F8wX0...
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
**Public Key Sources:**
|
|
361
|
-
- Get from Fluent Commerce dashboard
|
|
362
|
-
- Environment/region-specific (see Fluent Commerce documentation)
|
|
363
|
-
- Format: x509 base64 encoded
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
## Signature Algorithm Selection
|
|
368
|
-
|
|
369
|
-
Fluent Commerce sends **BOTH signature headers** in every webhook:
|
|
370
|
-
|
|
371
|
-
| Header | Algorithm | Priority | Use Case |
|
|
372
|
-
|--------|-----------|----------|----------|
|
|
373
|
-
| `fluent-signature` | SHA512withRSA | ✅ Preferred | Modern Rubix workflows |
|
|
374
|
-
| `flex.signature` | MD5withRSA | ⚠️ Fallback | Legacy Flex workflows |
|
|
375
|
-
|
|
376
|
-
**SDK Auto-Detection:**
|
|
377
|
-
```typescript
|
|
378
|
-
// SDK automatically selects the best algorithm:
|
|
379
|
-
const result = await validator.validateWebhook(rawBody, headers, publicKey);
|
|
380
|
-
// 1. Tries fluent-signature (SHA512) first
|
|
381
|
-
// 2. Falls back to flex.signature (MD5) if needed
|
|
382
|
-
// 3. Returns result with algorithm used
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
**Algorithm in Response:**
|
|
386
|
-
```typescript
|
|
387
|
-
if (result.isValid) {
|
|
388
|
-
console.log(`Validated with ${result.algorithm}`);
|
|
389
|
-
// Output: "Validated with SHA512withRSA" or "Validated with MD5withRSA"
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
---
|
|
394
|
-
|
|
395
|
-
## Common Issues and Solutions
|
|
396
|
-
|
|
397
|
-
### Issue 1: Validation Always Fails
|
|
398
|
-
|
|
399
|
-
**Symptom**: Every webhook validation returns `isValid: false`
|
|
400
|
-
|
|
401
|
-
**Possible Causes:**
|
|
402
|
-
|
|
403
|
-
1. **Wrong Public Key**
|
|
404
|
-
```typescript
|
|
405
|
-
// ✅ Check: Using correct environment's public key?
|
|
406
|
-
console.log('Public key prefix:', publicKey.substring(0, 30));
|
|
407
|
-
// Should start with "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBi..."
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
2. **Modified Payload**
|
|
411
|
-
```typescript
|
|
412
|
-
// ❌ WRONG - Modifying payload before validation
|
|
413
|
-
const rawBody = JSON.stringify(JSON.parse(activation.body));
|
|
414
|
-
|
|
415
|
-
// ✅ CORRECT - Use original raw body
|
|
416
|
-
const rawBody = activation.body; // Keep as-is
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
3. **Missing Signature Header**
|
|
420
|
-
```typescript
|
|
421
|
-
// Check headers
|
|
422
|
-
console.log('Headers:', Object.keys(headers));
|
|
423
|
-
console.log('Has fluent-signature:', !!headers['fluent-signature']);
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Issue 2: Using FluentClient.validateWebhook() for Rubix
|
|
427
|
-
|
|
428
|
-
**Symptom**: Validation fails with "missing required fields"
|
|
429
|
-
|
|
430
|
-
**Cause**: `FluentClient.validateWebhook()` expects Event webhook structure
|
|
431
|
-
|
|
432
|
-
**Solution**: Use `WebhookValidationService` instead
|
|
433
|
-
|
|
434
|
-
```typescript
|
|
435
|
-
// ❌ WRONG for Rubix webhooks
|
|
436
|
-
const isValid = await fluentClient.validateWebhook(payload, sig, raw);
|
|
437
|
-
|
|
438
|
-
// ✅ CORRECT for Rubix webhooks
|
|
439
|
-
const validator = new WebhookValidationService({}, logger);
|
|
440
|
-
const result = await validator.validateWebhook(raw, headers, publicKey);
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### Issue 3: Public Key Format Issues
|
|
444
|
-
|
|
445
|
-
**Symptom**: Cryptographic errors during validation
|
|
446
|
-
|
|
447
|
-
**Possible Causes:**
|
|
448
|
-
|
|
449
|
-
1. **Extra whitespace or newlines**
|
|
450
|
-
```typescript
|
|
451
|
-
// ✅ Trim whitespace
|
|
452
|
-
const publicKey = activation.getVariable('fluentPublicKey').trim();
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
2. **Wrong encoding**
|
|
456
|
-
```typescript
|
|
457
|
-
// ✅ Should be x509 base64 encoded
|
|
458
|
-
// Format: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/F8wX0...
|
|
459
|
-
// NOT PEM format with headers (SDK handles conversion if needed)
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
3. **Environment mismatch**
|
|
463
|
-
```typescript
|
|
464
|
-
// ✅ Use correct public key for environment
|
|
465
|
-
const env = activation.getVariable('environment') || 'production';
|
|
466
|
-
const publicKey = activation.getVariable(`fluentPublicKey_${env}`);
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
---
|
|
470
|
-
|
|
471
|
-
## Testing Rubix Webhooks
|
|
472
|
-
|
|
473
|
-
### Local Testing with curl
|
|
474
|
-
|
|
475
|
-
```bash
|
|
476
|
-
# Generate test payload
|
|
477
|
-
PAYLOAD='{"entityId":"order-123","entityRef":"ORD-001","entityType":"order","retailerId":"1"}'
|
|
478
|
-
|
|
479
|
-
# Get signature from Fluent Commerce test webhook
|
|
480
|
-
# (Use Rubix test mode to capture real signature)
|
|
481
|
-
|
|
482
|
-
# Send test request
|
|
483
|
-
curl -X POST https://{workspace}.versori.run/rubix-webhook \
|
|
484
|
-
-H "Content-Type: application/json" \
|
|
485
|
-
-H "fluent-signature: {REAL_SIGNATURE_FROM_FLUENT}" \
|
|
486
|
-
-H "x-retailer-id: 1" \
|
|
487
|
-
-d "$PAYLOAD"
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### Rubix Test Mode
|
|
491
|
-
|
|
492
|
-
1. Enable test mode in Rubix workflow
|
|
493
|
-
2. Trigger workflow manually
|
|
494
|
-
3. Check Versori logs for validation results
|
|
495
|
-
4. Verify signature validation succeeds
|
|
496
|
-
|
|
497
|
-
---
|
|
498
|
-
|
|
499
|
-
## Key Takeaways
|
|
500
|
-
|
|
501
|
-
- **Two webhook types**: Rubix HTTP Calls (custom payload) vs Event webhooks (standard payload)
|
|
502
|
-
- **Rubix validation**: Use `WebhookValidationService` directly
|
|
503
|
-
- **Event validation**: Use `FluentClient.validateWebhook()`
|
|
504
|
-
- **Signature headers**: Fluent sends BOTH (`fluent-signature` and `flex.signature`)
|
|
505
|
-
- **Auto-detection**: SDK automatically selects best algorithm
|
|
506
|
-
- **Raw payload**: Always validate against raw string, not parsed JSON
|
|
507
|
-
- **Public keys**: Environment/region-specific, get from Fluent Commerce
|
|
508
|
-
|
|
509
|
-
---
|
|
510
|
-
|
|
511
|
-
## Practice Exercise
|
|
512
|
-
|
|
513
|
-
Create a Rubix webhook handler that:
|
|
514
|
-
1. Validates webhook signature using `WebhookValidationService`
|
|
515
|
-
2. Extracts entity information from custom payload
|
|
516
|
-
3. Queries Fluent GraphQL for entity details
|
|
517
|
-
4. Returns structured response
|
|
518
|
-
|
|
519
|
-
<details>
|
|
520
|
-
<summary>Solution</summary>
|
|
521
|
-
|
|
522
|
-
```typescript
|
|
523
|
-
import { webhook, http } from '@versori/run';
|
|
524
|
-
import {
|
|
525
|
-
createClient,
|
|
526
|
-
WebhookValidationService,
|
|
527
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
528
|
-
|
|
529
|
-
export const practiceRubixWebhook = webhook('practice-rubix', {
|
|
530
|
-
response: { mode: 'sync' },
|
|
531
|
-
}).then(
|
|
532
|
-
http('handler', { connection: 'fluent_commerce' }, async ctx => {
|
|
533
|
-
const { log, activation, connections } = ctx;
|
|
534
|
-
|
|
535
|
-
// Get configuration
|
|
536
|
-
const publicKey = activation.getVariable('fluentPublicKey');
|
|
537
|
-
const rawBody = activation.body || JSON.stringify(ctx.data);
|
|
538
|
-
const headers = activation.headers || {};
|
|
539
|
-
|
|
540
|
-
// Validate signature (Versori log can be passed directly)
|
|
541
|
-
const validator = new WebhookValidationService({ strictValidation: true }, log);
|
|
542
|
-
const result = await validator.validateWebhook(rawBody, headers, publicKey);
|
|
543
|
-
|
|
544
|
-
if (!result.isValid) {
|
|
545
|
-
return { status: 401, body: { error: result.error } };
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Parse payload
|
|
549
|
-
const payload = JSON.parse(rawBody);
|
|
550
|
-
const { entityRef, retailerId } = payload;
|
|
551
|
-
|
|
552
|
-
// Query Fluent
|
|
553
|
-
const client = await createClient({ ...ctx, log, connections });
|
|
554
|
-
await client.setRetailerId(retailerId);
|
|
555
|
-
|
|
556
|
-
const queryResult = await client.graphql({
|
|
557
|
-
query: `query($ref: String!) { order(ref: $ref) { id ref status } }`,
|
|
558
|
-
variables: { ref: entityRef }
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
const order = queryResult.data?.order;
|
|
562
|
-
|
|
563
|
-
return {
|
|
564
|
-
status: 200,
|
|
565
|
-
body: {
|
|
566
|
-
success: true,
|
|
567
|
-
order: { id: order.id, ref: order.ref, status: order.status }
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
|
-
})
|
|
571
|
-
);
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
</details>
|
|
575
|
-
|
|
576
|
-
---
|
|
577
|
-
|
|
578
|
-
## Next Steps
|
|
579
|
-
|
|
580
|
-
- Review [Module 3: Versori Integration](./webhook-validation-03-versori-integration.md) for more Versori patterns
|
|
581
|
-
- Check [Rubix Webhook Template](../../../01-TEMPLATES/versori/workflows/rubix-webhooks/template-fluent-rubix-webhook-pattern.md) for production example
|
|
582
|
-
- See [API Reference](./webhook-validation-07-api-reference.md) for complete method signatures
|
|
583
|
-
|
|
584
|
-
---
|
|
585
|
-
|
|
586
|
-
## Further Reading
|
|
587
|
-
|
|
588
|
-
- [Fluent Commerce Webhook Documentation](https://docs.fluentcommerce.com/essential-knowledge/webhooks)
|
|
589
|
-
- [Rubix Workflow HTTP Call Action](https://docs.fluentcommerce.com/rubix/workflows/http-call)
|
|
590
|
-
- [Versori Platform Guide](../../../04-REFERENCE/platforms/versori/)
|
|
1
|
+
# Module 8: Rubix Webhook Validation
|
|
2
|
+
|
|
3
|
+
**Level:** Intermediate
|
|
4
|
+
**Estimated Time:** 20 minutes
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
This module covers webhook signature validation for **Fluent Commerce Rubix HTTP Call webhooks** - a specific use case different from Fluent Commerce Event webhooks.
|
|
9
|
+
|
|
10
|
+
**CRITICAL DISTINCTION**: This guide is for validating webhooks sent from **Rubix workflows** using the **HTTP Call action**, which have a different payload structure than Fluent Commerce Event webhooks.
|
|
11
|
+
|
|
12
|
+
## Learning Objectives
|
|
13
|
+
|
|
14
|
+
By the end of this module, you will:
|
|
15
|
+
|
|
16
|
+
- Understand the difference between Rubix HTTP Call webhooks and Event webhooks
|
|
17
|
+
- Know which validation method to use for each webhook type
|
|
18
|
+
- Implement correct signature validation for Rubix workflows
|
|
19
|
+
- Configure Rubix workflows to send properly signed webhooks
|
|
20
|
+
- Handle signature validation in Versori webhook handlers
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Rubix HTTP Call vs Event Webhooks
|
|
25
|
+
|
|
26
|
+
### Two Types of Fluent Commerce Webhooks
|
|
27
|
+
|
|
28
|
+
Fluent Commerce has **TWO different webhook types** with different payload structures:
|
|
29
|
+
|
|
30
|
+
| Feature | Rubix HTTP Call Webhooks | Event Webhooks |
|
|
31
|
+
|---------|-------------------------|----------------|
|
|
32
|
+
| **Trigger** | Rubix workflow HTTP Call action | Fluent Commerce event system |
|
|
33
|
+
| **Payload Structure** | Custom (entityId, entityRef, etc.) | Standard (name, id, retailerId, etc.) |
|
|
34
|
+
| **Use Case** | Custom workflow integrations | Event-driven integrations |
|
|
35
|
+
| **Validation Method** | ✅ `WebhookValidationService` | ✅ `FluentClient.validateWebhook()` |
|
|
36
|
+
| **Signature Headers** | `fluent-signature`, `flex.signature` | `fluent-signature`, `flex.signature` |
|
|
37
|
+
| **Public Key Required** | Yes (x509 base64) | Yes (x509 base64) |
|
|
38
|
+
|
|
39
|
+
### Rubix HTTP Call Webhook Payload
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"entityId": "order-123",
|
|
44
|
+
"entityRef": "ORD-001",
|
|
45
|
+
"entityType": "order",
|
|
46
|
+
"triggerSource": "ORDER_FULFILLMENT",
|
|
47
|
+
"retailerId": "1",
|
|
48
|
+
"timestamp": "2025-11-07T12:34:56.789Z"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Event Webhook Payload
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"name": "ORDER.CREATED",
|
|
57
|
+
"id": "evt-123",
|
|
58
|
+
"retailerId": "1",
|
|
59
|
+
"entityId": "order-123",
|
|
60
|
+
"entityType": "ORDER",
|
|
61
|
+
"timestamp": "2025-11-07T12:34:56.789Z",
|
|
62
|
+
"data": { /* event data */ }
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Key Difference**: Rubix webhooks have custom payload structure, Event webhooks have standardized fields (`name`, `id`, `retailerId`).
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Which Validation Method to Use?
|
|
71
|
+
|
|
72
|
+
### ✅ Use WebhookValidationService for Rubix HTTP Calls
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { WebhookValidationService } from '@fluentcommerce/fc-connect-sdk';
|
|
76
|
+
|
|
77
|
+
// ✅ CORRECT for Rubix HTTP Call webhooks
|
|
78
|
+
// Versori log can be passed directly (no wrapper needed)
|
|
79
|
+
const validator = new WebhookValidationService({ strictValidation: true }, log);
|
|
80
|
+
|
|
81
|
+
const result = await validator.validateWebhook(
|
|
82
|
+
rawBodyString, // Raw payload string
|
|
83
|
+
headers, // Headers object
|
|
84
|
+
publicKey // x509 base64 public key
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Why**: `WebhookValidationService` validates the signature without requiring specific payload fields.
|
|
89
|
+
|
|
90
|
+
### ✅ Use FluentClient.validateWebhook() for Event Webhooks
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
94
|
+
|
|
95
|
+
// ✅ CORRECT for Fluent Commerce Event webhooks
|
|
96
|
+
const client = await createClient({ ...ctx, log, connections });
|
|
97
|
+
|
|
98
|
+
const isValid = await client.validateWebhook(
|
|
99
|
+
payload, // FluentWebhookPayload object (must have name, id, retailerId)
|
|
100
|
+
signature, // Signature string
|
|
101
|
+
rawPayload // Raw payload string
|
|
102
|
+
);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Why**: `FluentClient.validateWebhook()` does additional field validation for Event webhooks.
|
|
106
|
+
|
|
107
|
+
### ❌ Common Mistake: Using Wrong Method
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// ❌ WRONG - Using FluentClient.validateWebhook() for Rubix webhooks
|
|
111
|
+
const client = await createClient({ ...ctx, log });
|
|
112
|
+
const isValid = await client.validateWebhook(
|
|
113
|
+
rubixPayload, // ❌ Rubix payload doesn't have name, id, retailerId
|
|
114
|
+
signature,
|
|
115
|
+
rawPayload
|
|
116
|
+
);
|
|
117
|
+
// Result: Always returns false (fails basic field validation)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Rubix Webhook Validation Pattern
|
|
123
|
+
|
|
124
|
+
### Complete Implementation
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { webhook, http } from '@versori/run';
|
|
128
|
+
import {
|
|
129
|
+
createClient,
|
|
130
|
+
WebhookValidationService,
|
|
131
|
+
toStructuredLogger,
|
|
132
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Rubix HTTP Call Webhook Handler with Signature Validation
|
|
136
|
+
*/
|
|
137
|
+
export const rubixWebhook = webhook('rubix-webhook', {
|
|
138
|
+
response: { mode: 'sync' },
|
|
139
|
+
}).then(
|
|
140
|
+
http('validate-and-process', { connection: 'fluent_commerce' }, async ctx => {
|
|
141
|
+
const { log, activation, connections } = ctx;
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
// =========================================================
|
|
145
|
+
// STEP 1: VALIDATE WEBHOOK SIGNATURE
|
|
146
|
+
// =========================================================
|
|
147
|
+
|
|
148
|
+
// Get public key (x509 base64 encoded)
|
|
149
|
+
const publicKey = activation.getVariable('fluentPublicKey');
|
|
150
|
+
if (!publicKey) {
|
|
151
|
+
log.error('Missing fluentPublicKey activation variable');
|
|
152
|
+
return {
|
|
153
|
+
status: 500,
|
|
154
|
+
body: { error: 'Missing public key configuration' }
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Get raw payload (must be raw string, not parsed)
|
|
159
|
+
const rawPayload = activation.body || ctx.data;
|
|
160
|
+
const rawBodyString = typeof rawPayload === 'string'
|
|
161
|
+
? rawPayload
|
|
162
|
+
: JSON.stringify(rawPayload);
|
|
163
|
+
|
|
164
|
+
// Get headers
|
|
165
|
+
const headers = activation.headers || {};
|
|
166
|
+
|
|
167
|
+
// Check for signature headers
|
|
168
|
+
const hasSignature = !!(
|
|
169
|
+
headers['fluent-signature'] ||
|
|
170
|
+
headers['x-fluent-signature'] ||
|
|
171
|
+
headers['flex.signature']
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
if (hasSignature) {
|
|
175
|
+
// Create validator (Versori log can be passed directly)
|
|
176
|
+
const validator = new WebhookValidationService(
|
|
177
|
+
{ strictValidation: true },
|
|
178
|
+
log
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// Validate signature
|
|
182
|
+
// Auto-detects: fluent-signature (SHA512) preferred, flex.signature (MD5) fallback
|
|
183
|
+
const result = await validator.validateWebhook(
|
|
184
|
+
rawBodyString, // Raw payload string
|
|
185
|
+
headers, // Headers object
|
|
186
|
+
publicKey // x509 base64 public key
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (!result.isValid) {
|
|
190
|
+
log.error('Invalid webhook signature', {
|
|
191
|
+
error: result.error,
|
|
192
|
+
algorithm: result.algorithm,
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
status: 401,
|
|
196
|
+
body: { error: 'Invalid signature' }
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
log.info('✅ Webhook signature validated', {
|
|
201
|
+
algorithm: result.algorithm,
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
log.warn('No signature header found - skipping validation');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Parse payload (AFTER validation)
|
|
208
|
+
const payload = typeof rawPayload === 'string'
|
|
209
|
+
? JSON.parse(rawPayload)
|
|
210
|
+
: rawPayload;
|
|
211
|
+
|
|
212
|
+
// =========================================================
|
|
213
|
+
// STEP 2: EXTRACT ENTITY INFORMATION
|
|
214
|
+
// =========================================================
|
|
215
|
+
|
|
216
|
+
const { entityId, entityRef, entityType, retailerId } = payload;
|
|
217
|
+
|
|
218
|
+
if (!entityId && !entityRef) {
|
|
219
|
+
log.error('Missing entity identifier');
|
|
220
|
+
return {
|
|
221
|
+
status: 400,
|
|
222
|
+
body: { error: 'Missing entityId or entityRef' }
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
log.info('Processing Rubix webhook', {
|
|
227
|
+
entityId,
|
|
228
|
+
entityRef,
|
|
229
|
+
entityType,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// =========================================================
|
|
233
|
+
// STEP 3: QUERY FLUENT FOR ENTITY DETAILS
|
|
234
|
+
// =========================================================
|
|
235
|
+
|
|
236
|
+
const fluentClient = await createClient({
|
|
237
|
+
...ctx,
|
|
238
|
+
log,
|
|
239
|
+
connections,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
await fluentClient.setRetailerId(retailerId);
|
|
243
|
+
|
|
244
|
+
// Query entity (example: order)
|
|
245
|
+
const query = `
|
|
246
|
+
query GetEntity($ref: String!) {
|
|
247
|
+
order(ref: $ref) {
|
|
248
|
+
id
|
|
249
|
+
ref
|
|
250
|
+
status
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
254
|
+
|
|
255
|
+
const result = await fluentClient.graphql({
|
|
256
|
+
query,
|
|
257
|
+
variables: { ref: entityRef }
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
if (result.errors?.length) {
|
|
261
|
+
log.error('GraphQL query failed', { errors: result.errors });
|
|
262
|
+
return {
|
|
263
|
+
status: 502,
|
|
264
|
+
body: { error: 'Failed to fetch entity' }
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const entity = result.data?.order;
|
|
269
|
+
|
|
270
|
+
// =========================================================
|
|
271
|
+
// STEP 4: PROCESS ENTITY
|
|
272
|
+
// =========================================================
|
|
273
|
+
|
|
274
|
+
log.info('Entity retrieved', {
|
|
275
|
+
entityId: entity.id,
|
|
276
|
+
entityRef: entity.ref,
|
|
277
|
+
status: entity.status,
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// Your business logic here
|
|
281
|
+
await processEntity(entity);
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
status: 200,
|
|
285
|
+
body: {
|
|
286
|
+
success: true,
|
|
287
|
+
entityId: entity.id,
|
|
288
|
+
entityRef: entity.ref,
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
} catch (error: any) {
|
|
293
|
+
log.error('Webhook processing failed', {
|
|
294
|
+
error: error.message,
|
|
295
|
+
stack: error.stack,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
status: 500,
|
|
300
|
+
body: { error: error.message }
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
async function processEntity(entity: any): Promise<void> {
|
|
307
|
+
// Your processing logic
|
|
308
|
+
console.log('Processing entity:', entity.ref);
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Configuring Rubix Workflows
|
|
315
|
+
|
|
316
|
+
### Step 1: Add HTTP Call Action in Rubix
|
|
317
|
+
|
|
318
|
+
In your Rubix workflow, add an **HTTP Call** action:
|
|
319
|
+
|
|
320
|
+
**Action Configuration:**
|
|
321
|
+
```
|
|
322
|
+
Method: POST
|
|
323
|
+
URL: https://{workspace}.versori.run/rubix-webhook
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Headers:**
|
|
327
|
+
```json
|
|
328
|
+
{
|
|
329
|
+
"Content-Type": "application/json",
|
|
330
|
+
"fluent-signature": "${webhookSignature}",
|
|
331
|
+
"x-retailer-id": "${retailerId}"
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Payload:**
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"entityId": "${entity.id}",
|
|
339
|
+
"entityRef": "${entity.ref}",
|
|
340
|
+
"entityType": "order",
|
|
341
|
+
"retailerId": "${retailerId}",
|
|
342
|
+
"timestamp": "${currentTimestamp}"
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Step 2: Configure Webhook Signature in Rubix
|
|
347
|
+
|
|
348
|
+
Fluent Commerce automatically generates signatures using its private key. The signature is available as `${webhookSignature}` in Rubix workflows.
|
|
349
|
+
|
|
350
|
+
**Important**: The signature is generated server-side by Fluent Commerce. You don't need to generate it manually in Rubix.
|
|
351
|
+
|
|
352
|
+
### Step 3: Configure Public Key in Versori
|
|
353
|
+
|
|
354
|
+
In Versori Dashboard → Activation Variables:
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
fluentPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/F8wX0...
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Public Key Sources:**
|
|
361
|
+
- Get from Fluent Commerce dashboard
|
|
362
|
+
- Environment/region-specific (see Fluent Commerce documentation)
|
|
363
|
+
- Format: x509 base64 encoded
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Signature Algorithm Selection
|
|
368
|
+
|
|
369
|
+
Fluent Commerce sends **BOTH signature headers** in every webhook:
|
|
370
|
+
|
|
371
|
+
| Header | Algorithm | Priority | Use Case |
|
|
372
|
+
|--------|-----------|----------|----------|
|
|
373
|
+
| `fluent-signature` | SHA512withRSA | ✅ Preferred | Modern Rubix workflows |
|
|
374
|
+
| `flex.signature` | MD5withRSA | ⚠️ Fallback | Legacy Flex workflows |
|
|
375
|
+
|
|
376
|
+
**SDK Auto-Detection:**
|
|
377
|
+
```typescript
|
|
378
|
+
// SDK automatically selects the best algorithm:
|
|
379
|
+
const result = await validator.validateWebhook(rawBody, headers, publicKey);
|
|
380
|
+
// 1. Tries fluent-signature (SHA512) first
|
|
381
|
+
// 2. Falls back to flex.signature (MD5) if needed
|
|
382
|
+
// 3. Returns result with algorithm used
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Algorithm in Response:**
|
|
386
|
+
```typescript
|
|
387
|
+
if (result.isValid) {
|
|
388
|
+
console.log(`Validated with ${result.algorithm}`);
|
|
389
|
+
// Output: "Validated with SHA512withRSA" or "Validated with MD5withRSA"
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Common Issues and Solutions
|
|
396
|
+
|
|
397
|
+
### Issue 1: Validation Always Fails
|
|
398
|
+
|
|
399
|
+
**Symptom**: Every webhook validation returns `isValid: false`
|
|
400
|
+
|
|
401
|
+
**Possible Causes:**
|
|
402
|
+
|
|
403
|
+
1. **Wrong Public Key**
|
|
404
|
+
```typescript
|
|
405
|
+
// ✅ Check: Using correct environment's public key?
|
|
406
|
+
console.log('Public key prefix:', publicKey.substring(0, 30));
|
|
407
|
+
// Should start with "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBi..."
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
2. **Modified Payload**
|
|
411
|
+
```typescript
|
|
412
|
+
// ❌ WRONG - Modifying payload before validation
|
|
413
|
+
const rawBody = JSON.stringify(JSON.parse(activation.body));
|
|
414
|
+
|
|
415
|
+
// ✅ CORRECT - Use original raw body
|
|
416
|
+
const rawBody = activation.body; // Keep as-is
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
3. **Missing Signature Header**
|
|
420
|
+
```typescript
|
|
421
|
+
// Check headers
|
|
422
|
+
console.log('Headers:', Object.keys(headers));
|
|
423
|
+
console.log('Has fluent-signature:', !!headers['fluent-signature']);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Issue 2: Using FluentClient.validateWebhook() for Rubix
|
|
427
|
+
|
|
428
|
+
**Symptom**: Validation fails with "missing required fields"
|
|
429
|
+
|
|
430
|
+
**Cause**: `FluentClient.validateWebhook()` expects Event webhook structure
|
|
431
|
+
|
|
432
|
+
**Solution**: Use `WebhookValidationService` instead
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
// ❌ WRONG for Rubix webhooks
|
|
436
|
+
const isValid = await fluentClient.validateWebhook(payload, sig, raw);
|
|
437
|
+
|
|
438
|
+
// ✅ CORRECT for Rubix webhooks
|
|
439
|
+
const validator = new WebhookValidationService({}, logger);
|
|
440
|
+
const result = await validator.validateWebhook(raw, headers, publicKey);
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Issue 3: Public Key Format Issues
|
|
444
|
+
|
|
445
|
+
**Symptom**: Cryptographic errors during validation
|
|
446
|
+
|
|
447
|
+
**Possible Causes:**
|
|
448
|
+
|
|
449
|
+
1. **Extra whitespace or newlines**
|
|
450
|
+
```typescript
|
|
451
|
+
// ✅ Trim whitespace
|
|
452
|
+
const publicKey = activation.getVariable('fluentPublicKey').trim();
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
2. **Wrong encoding**
|
|
456
|
+
```typescript
|
|
457
|
+
// ✅ Should be x509 base64 encoded
|
|
458
|
+
// Format: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/F8wX0...
|
|
459
|
+
// NOT PEM format with headers (SDK handles conversion if needed)
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
3. **Environment mismatch**
|
|
463
|
+
```typescript
|
|
464
|
+
// ✅ Use correct public key for environment
|
|
465
|
+
const env = activation.getVariable('environment') || 'production';
|
|
466
|
+
const publicKey = activation.getVariable(`fluentPublicKey_${env}`);
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Testing Rubix Webhooks
|
|
472
|
+
|
|
473
|
+
### Local Testing with curl
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# Generate test payload
|
|
477
|
+
PAYLOAD='{"entityId":"order-123","entityRef":"ORD-001","entityType":"order","retailerId":"1"}'
|
|
478
|
+
|
|
479
|
+
# Get signature from Fluent Commerce test webhook
|
|
480
|
+
# (Use Rubix test mode to capture real signature)
|
|
481
|
+
|
|
482
|
+
# Send test request
|
|
483
|
+
curl -X POST https://{workspace}.versori.run/rubix-webhook \
|
|
484
|
+
-H "Content-Type: application/json" \
|
|
485
|
+
-H "fluent-signature: {REAL_SIGNATURE_FROM_FLUENT}" \
|
|
486
|
+
-H "x-retailer-id: 1" \
|
|
487
|
+
-d "$PAYLOAD"
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Rubix Test Mode
|
|
491
|
+
|
|
492
|
+
1. Enable test mode in Rubix workflow
|
|
493
|
+
2. Trigger workflow manually
|
|
494
|
+
3. Check Versori logs for validation results
|
|
495
|
+
4. Verify signature validation succeeds
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## Key Takeaways
|
|
500
|
+
|
|
501
|
+
- **Two webhook types**: Rubix HTTP Calls (custom payload) vs Event webhooks (standard payload)
|
|
502
|
+
- **Rubix validation**: Use `WebhookValidationService` directly
|
|
503
|
+
- **Event validation**: Use `FluentClient.validateWebhook()`
|
|
504
|
+
- **Signature headers**: Fluent sends BOTH (`fluent-signature` and `flex.signature`)
|
|
505
|
+
- **Auto-detection**: SDK automatically selects best algorithm
|
|
506
|
+
- **Raw payload**: Always validate against raw string, not parsed JSON
|
|
507
|
+
- **Public keys**: Environment/region-specific, get from Fluent Commerce
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Practice Exercise
|
|
512
|
+
|
|
513
|
+
Create a Rubix webhook handler that:
|
|
514
|
+
1. Validates webhook signature using `WebhookValidationService`
|
|
515
|
+
2. Extracts entity information from custom payload
|
|
516
|
+
3. Queries Fluent GraphQL for entity details
|
|
517
|
+
4. Returns structured response
|
|
518
|
+
|
|
519
|
+
<details>
|
|
520
|
+
<summary>Solution</summary>
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
import { webhook, http } from '@versori/run';
|
|
524
|
+
import {
|
|
525
|
+
createClient,
|
|
526
|
+
WebhookValidationService,
|
|
527
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
528
|
+
|
|
529
|
+
export const practiceRubixWebhook = webhook('practice-rubix', {
|
|
530
|
+
response: { mode: 'sync' },
|
|
531
|
+
}).then(
|
|
532
|
+
http('handler', { connection: 'fluent_commerce' }, async ctx => {
|
|
533
|
+
const { log, activation, connections } = ctx;
|
|
534
|
+
|
|
535
|
+
// Get configuration
|
|
536
|
+
const publicKey = activation.getVariable('fluentPublicKey');
|
|
537
|
+
const rawBody = activation.body || JSON.stringify(ctx.data);
|
|
538
|
+
const headers = activation.headers || {};
|
|
539
|
+
|
|
540
|
+
// Validate signature (Versori log can be passed directly)
|
|
541
|
+
const validator = new WebhookValidationService({ strictValidation: true }, log);
|
|
542
|
+
const result = await validator.validateWebhook(rawBody, headers, publicKey);
|
|
543
|
+
|
|
544
|
+
if (!result.isValid) {
|
|
545
|
+
return { status: 401, body: { error: result.error } };
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Parse payload
|
|
549
|
+
const payload = JSON.parse(rawBody);
|
|
550
|
+
const { entityRef, retailerId } = payload;
|
|
551
|
+
|
|
552
|
+
// Query Fluent
|
|
553
|
+
const client = await createClient({ ...ctx, log, connections });
|
|
554
|
+
await client.setRetailerId(retailerId);
|
|
555
|
+
|
|
556
|
+
const queryResult = await client.graphql({
|
|
557
|
+
query: `query($ref: String!) { order(ref: $ref) { id ref status } }`,
|
|
558
|
+
variables: { ref: entityRef }
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
const order = queryResult.data?.order;
|
|
562
|
+
|
|
563
|
+
return {
|
|
564
|
+
status: 200,
|
|
565
|
+
body: {
|
|
566
|
+
success: true,
|
|
567
|
+
order: { id: order.id, ref: order.ref, status: order.status }
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
})
|
|
571
|
+
);
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
</details>
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Next Steps
|
|
579
|
+
|
|
580
|
+
- Review [Module 3: Versori Integration](./webhook-validation-03-versori-integration.md) for more Versori patterns
|
|
581
|
+
- Check [Rubix Webhook Template](../../../01-TEMPLATES/versori/workflows/rubix-webhooks/template-fluent-rubix-webhook-pattern.md) for production example
|
|
582
|
+
- See [API Reference](./webhook-validation-07-api-reference.md) for complete method signatures
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Further Reading
|
|
587
|
+
|
|
588
|
+
- [Fluent Commerce Webhook Documentation](https://docs.fluentcommerce.com/essential-knowledge/webhooks)
|
|
589
|
+
- [Rubix Workflow HTTP Call Action](https://docs.fluentcommerce.com/rubix/workflows/http-call)
|
|
590
|
+
- [Versori Platform Guide](../../../04-REFERENCE/platforms/versori/)
|