@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
package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md
CHANGED
|
@@ -1,681 +1,681 @@
|
|
|
1
|
-
# Versori Webhook Connection-Based Security
|
|
2
|
-
|
|
3
|
-
**Platform:** Versori
|
|
4
|
-
**Security Pattern:** Connection-Level Authentication
|
|
5
|
-
**Level:** Recommended
|
|
6
|
-
**Last Updated:** 2025-10-28
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Overview
|
|
11
|
-
|
|
12
|
-
This guide explains **connection-based webhook security** in Versori - how to authenticate webhook endpoints at the platform level BEFORE your workflow code runs.
|
|
13
|
-
|
|
14
|
-
### Connection-Based Security Pattern
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
export const myWebhook = webhook('my-webhook', {
|
|
18
|
-
connection: 'my-webhook-auth', // Versori validates BEFORE code runs
|
|
19
|
-
response: { mode: 'sync' },
|
|
20
|
-
}).then(
|
|
21
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
22
|
-
// No validation needed - if we got here, auth passed!
|
|
23
|
-
// Business logic...
|
|
24
|
-
})
|
|
25
|
-
);
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Benefits
|
|
29
|
-
|
|
30
|
-
| Benefit | Description |
|
|
31
|
-
| ---------------------- | -------------------------------------------------------------- |
|
|
32
|
-
| **Security at Edge** | Validation happens at platform level before workflow execution |
|
|
33
|
-
| **No Code Changes** | Rotate keys by updating connection, not code |
|
|
34
|
-
| **Resource Efficient** | Failed auth requests never consume workflow resources |
|
|
35
|
-
| **Consistent Pattern** | Same approach across all webhooks |
|
|
36
|
-
| **Easier Testing** | Clear separation: connection config vs business logic |
|
|
37
|
-
| **Better Logging** | Platform logs all auth attempts automatically |
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## How It Works
|
|
42
|
-
|
|
43
|
-
### Request Flow
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
┌─────────────────┐
|
|
47
|
-
│ External │
|
|
48
|
-
│ System/Client │
|
|
49
|
-
└────────┬────────┘
|
|
50
|
-
│
|
|
51
|
-
│ POST /webhook/my-endpoint
|
|
52
|
-
│ Headers:
|
|
53
|
-
│ (as configured on the connection)
|
|
54
|
-
│ Body: { "data": "..." }
|
|
55
|
-
│
|
|
56
|
-
▼
|
|
57
|
-
┌────────────────────────────────────┐
|
|
58
|
-
│ Versori Platform (Edge Layer) │
|
|
59
|
-
│ │
|
|
60
|
-
│ 1. Connection-based authentication│
|
|
61
|
-
│ 2. Load connection: my-webhook-auth│
|
|
62
|
-
│ 3. Compare values (constant time) │
|
|
63
|
-
│ │
|
|
64
|
-
│ ✓ Valid? → Continue to workflow │
|
|
65
|
-
│ ✗ Invalid? → Return 401/403 │
|
|
66
|
-
└────────┬───────────────────────────┘
|
|
67
|
-
│
|
|
68
|
-
│ ✅ Only valid requests proceed
|
|
69
|
-
▼
|
|
70
|
-
┌────────────────────────────────────┐
|
|
71
|
-
│ Your Workflow Code │
|
|
72
|
-
│ │
|
|
73
|
-
│ - No auth validation needed │
|
|
74
|
-
│ - Focus on business logic │
|
|
75
|
-
│ - Process request data │
|
|
76
|
-
└────────────────────────────────────┘
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Security Guarantee
|
|
80
|
-
|
|
81
|
-
If your workflow code executes, authentication has already succeeded. **No manual validation required.**
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Setup Guide
|
|
86
|
-
|
|
87
|
-
### Step 1: Create API Key Connection
|
|
88
|
-
|
|
89
|
-
1. **Navigate to Versori Dashboard**
|
|
90
|
-
- Go to your workspace
|
|
91
|
-
- Click **Connections** in sidebar
|
|
92
|
-
- Click **Add Connection**
|
|
93
|
-
|
|
94
|
-
2. **Configure Connection**
|
|
95
|
-
- **Name**: `my-webhook-auth` (choose descriptive name)
|
|
96
|
-
- **Description**: `API key authentication for my-webhook endpoint`
|
|
97
|
-
- **Type**: `API Key Authentication`
|
|
98
|
-
|
|
99
|
-
3. **Authentication**
|
|
100
|
-
- Configure auth on the connection (no inline headers or variables)
|
|
101
|
-
|
|
102
|
-
4. **Save Connection**
|
|
103
|
-
- Click **Save**
|
|
104
|
-
- Note the connection name for use in code
|
|
105
|
-
|
|
106
|
-
### Step 2: Generate Secure API Keys
|
|
107
|
-
|
|
108
|
-
**Generate cryptographically secure keys (64+ characters recommended):**
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
# Node.js
|
|
112
|
-
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
113
|
-
|
|
114
|
-
# Output example:
|
|
115
|
-
# 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f
|
|
116
|
-
|
|
117
|
-
# Python
|
|
118
|
-
python3 -c "import secrets; print(secrets.token_hex(32))"
|
|
119
|
-
|
|
120
|
-
# OpenSSL
|
|
121
|
-
openssl rand -hex 32
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
**Key Requirements:**
|
|
125
|
-
|
|
126
|
-
- Minimum 32 characters (64+ recommended)
|
|
127
|
-
- Cryptographically random (don't make up keys!)
|
|
128
|
-
- Alphanumeric (hex format is ideal)
|
|
129
|
-
- Unique per environment (dev/staging/prod)
|
|
130
|
-
- Unique per client (don't share keys between systems)
|
|
131
|
-
|
|
132
|
-
### Step 3: Use Connection in Webhook Definition
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
import { webhook, http } from '@versori/run';
|
|
136
|
-
|
|
137
|
-
export const mySecureWebhook = webhook('my-webhook', {
|
|
138
|
-
connection: 'my-webhook-auth', // ✅ Reference connection by name
|
|
139
|
-
response: { mode: 'sync' },
|
|
140
|
-
}).then(
|
|
141
|
-
http('process-data', { connection: 'fluent_commerce' }, async ctx => {
|
|
142
|
-
const { log, data } = ctx;
|
|
143
|
-
|
|
144
|
-
// ✅ Authentication already validated by Versori
|
|
145
|
-
// No manual checks needed!
|
|
146
|
-
|
|
147
|
-
log.info('Processing authenticated request', {
|
|
148
|
-
dataSize: JSON.stringify(data).length,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Your business logic here
|
|
152
|
-
return {
|
|
153
|
-
success: true,
|
|
154
|
-
message: 'Request processed',
|
|
155
|
-
timestamp: new Date().toISOString(),
|
|
156
|
-
};
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Step 4: Test the Webhook
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
# Test (auth handled by connection)
|
|
165
|
-
curl -X POST https://your-workspace.versori.run/my-webhook \
|
|
166
|
-
-H "Content-Type: application/json" \
|
|
167
|
-
-d '{"test": "data"}'
|
|
168
|
-
# Expected: 200 OK with workflow response when using valid connection
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## Common Patterns
|
|
174
|
-
|
|
175
|
-
### Pattern 1: Single Webhook, Single Connection
|
|
176
|
-
|
|
177
|
-
**Use Case:** One webhook endpoint with one API key
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
// Connection: 'order-webhook-auth'
|
|
181
|
-
export const orderWebhook = webhook('order-ingestion', {
|
|
182
|
-
connection: 'order-webhook-auth',
|
|
183
|
-
response: { mode: 'sync' },
|
|
184
|
-
}).then(
|
|
185
|
-
http('process-order', { connection: 'fluent_commerce' }, async ctx => {
|
|
186
|
-
// Process order...
|
|
187
|
-
})
|
|
188
|
-
);
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**Setup:**
|
|
192
|
-
|
|
193
|
-
- Create 1 connection: `order-webhook-auth`
|
|
194
|
-
- Use in 1 webhook definition
|
|
195
|
-
|
|
196
|
-
### Pattern 2: Multiple Webhooks, Shared Connection
|
|
197
|
-
|
|
198
|
-
**Use Case:** Multiple webhooks sharing same API key (same partner/client)
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
// Connection: 'partner-api-auth' (shared)
|
|
202
|
-
|
|
203
|
-
export const orderWebhook = webhook('orders', {
|
|
204
|
-
connection: 'partner-api-auth', // Shared connection
|
|
205
|
-
response: { mode: 'sync' },
|
|
206
|
-
}).then(
|
|
207
|
-
http('process-order', { connection: 'fluent' }, async ctx => {
|
|
208
|
-
// Process order...
|
|
209
|
-
})
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
export const inventoryWebhook = webhook('inventory', {
|
|
213
|
-
connection: 'partner-api-auth', // Same connection
|
|
214
|
-
response: { mode: 'sync' },
|
|
215
|
-
}).then(
|
|
216
|
-
http('process-inventory', { connection: 'fluent' }, async ctx => {
|
|
217
|
-
// Process inventory...
|
|
218
|
-
})
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
export const statusWebhook = webhook('status', {
|
|
222
|
-
connection: 'partner-api-auth', // Same connection
|
|
223
|
-
response: { mode: 'sync' },
|
|
224
|
-
}).then(
|
|
225
|
-
http('query-status', { connection: 'fluent' }, async ctx => {
|
|
226
|
-
// Query status...
|
|
227
|
-
})
|
|
228
|
-
);
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
**Setup:**
|
|
232
|
-
|
|
233
|
-
- Create 1 connection: `partner-api-auth`
|
|
234
|
-
- Use in 3 webhooks
|
|
235
|
-
- All webhooks accept same API key
|
|
236
|
-
- Easy to rotate: update 1 connection, affects all webhooks
|
|
237
|
-
|
|
238
|
-
### Pattern 3: Multiple Webhooks, Different Connections
|
|
239
|
-
|
|
240
|
-
**Use Case:** Different partners/clients need different API keys
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
// Connections: 'partner-a-auth', 'partner-b-auth', 'partner-c-auth'
|
|
244
|
-
|
|
245
|
-
export const partnerAWebhook = webhook('partner-a-orders', {
|
|
246
|
-
connection: 'partner-a-auth', // Partner A's key
|
|
247
|
-
response: { mode: 'sync' },
|
|
248
|
-
}).then(
|
|
249
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
250
|
-
// Partner A logic...
|
|
251
|
-
})
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
export const partnerBWebhook = webhook('partner-b-orders', {
|
|
255
|
-
connection: 'partner-b-auth', // Partner B's key
|
|
256
|
-
response: { mode: 'sync' },
|
|
257
|
-
}).then(
|
|
258
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
259
|
-
// Partner B logic...
|
|
260
|
-
})
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
export const partnerCWebhook = webhook('partner-c-orders', {
|
|
264
|
-
connection: 'partner-c-auth', // Partner C's key
|
|
265
|
-
response: { mode: 'sync' },
|
|
266
|
-
}).then(
|
|
267
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
268
|
-
// Partner C logic...
|
|
269
|
-
})
|
|
270
|
-
);
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
**Setup:**
|
|
274
|
-
|
|
275
|
-
- Create 3 connections: one per partner
|
|
276
|
-
- Each webhook uses its partner's connection
|
|
277
|
-
- Isolate security: compromised key only affects one partner
|
|
278
|
-
- Rotate independently per partner
|
|
279
|
-
|
|
280
|
-
### Pattern 4: Custom Header Names
|
|
281
|
-
|
|
282
|
-
**Use Case:** Partner requires custom header
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
// Connection: 'partner-auth'
|
|
286
|
-
// Header: 'X-Partner-Token' (configured in Versori connection)
|
|
287
|
-
|
|
288
|
-
export const partnerWebhook = webhook('partner-integration', {
|
|
289
|
-
connection: 'partner-auth', // Uses X-Partner-Token header
|
|
290
|
-
response: { mode: 'sync' },
|
|
291
|
-
}).then(
|
|
292
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
293
|
-
// Process...
|
|
294
|
-
})
|
|
295
|
-
);
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
**Setup in Versori:**
|
|
299
|
-
Configure partner-specific authentication on the connection (e.g., `X-Partner-Token`).
|
|
300
|
-
|
|
301
|
-
**Partner's Request:**
|
|
302
|
-
|
|
303
|
-
```bash
|
|
304
|
-
curl -X POST https://workspace.versori.run/partner-integration \
|
|
305
|
-
-H "X-Partner-Token: abc123xyz" \
|
|
306
|
-
-H "Content-Type: application/json" \
|
|
307
|
-
-d '{"data": "..."}'
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
## Key Rotation
|
|
313
|
-
|
|
314
|
-
### Zero-Downtime Key Rotation
|
|
315
|
-
|
|
316
|
-
**Problem:** Need to rotate API key without breaking active integrations
|
|
317
|
-
|
|
318
|
-
**Solution:** Dual-connection pattern (support old + new keys during transition)
|
|
319
|
-
|
|
320
|
-
#### Step 1: Create New Connection
|
|
321
|
-
|
|
322
|
-
```
|
|
323
|
-
Use a new connection `my-webhook-auth-v2` with updated authentication settings.
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
#### Step 2: Update Webhook to Support Both Keys
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
// Temporarily accept BOTH old and new keys
|
|
330
|
-
// Note: This requires custom validation (see Advanced Patterns)
|
|
331
|
-
|
|
332
|
-
export const myWebhook = webhook('my-webhook', {
|
|
333
|
-
// Remove connection temporarily for dual-key support
|
|
334
|
-
response: { mode: 'sync' },
|
|
335
|
-
})
|
|
336
|
-
.then(
|
|
337
|
-
fn('validate-dual-keys', async ctx => {
|
|
338
|
-
const { request } = ctx;
|
|
339
|
-
const req = request();
|
|
340
|
-
const providedKey = req.headers.get('x-api-key');
|
|
341
|
-
|
|
342
|
-
// Accept either old or new key during transition
|
|
343
|
-
const validKeys = [
|
|
344
|
-
'<old-key>', // Get from old connection
|
|
345
|
-
'<new-key>', // Get from new connection
|
|
346
|
-
];
|
|
347
|
-
|
|
348
|
-
if (!validKeys.some(k => constantTimeEqual(providedKey, k))) {
|
|
349
|
-
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
|
|
350
|
-
status: 401,
|
|
351
|
-
headers: { 'Content-Type': 'application/json' },
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return ctx.data;
|
|
356
|
-
})
|
|
357
|
-
)
|
|
358
|
-
.then(
|
|
359
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
360
|
-
// Business logic...
|
|
361
|
-
})
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
// Helper function for constant-time string comparison (timing attack prevention)
|
|
365
|
-
function constantTimeEqual(a: string, b: string): boolean {
|
|
366
|
-
if (a.length !== b.length) return false;
|
|
367
|
-
let result = 0;
|
|
368
|
-
for (let i = 0; i < a.length; i++) {
|
|
369
|
-
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
370
|
-
}
|
|
371
|
-
return result === 0;
|
|
372
|
-
}
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
#### Step 3: Notify Partners
|
|
376
|
-
|
|
377
|
-
```
|
|
378
|
-
Subject: API Key Rotation - Action Required
|
|
379
|
-
|
|
380
|
-
We are rotating API keys for enhanced security.
|
|
381
|
-
|
|
382
|
-
CURRENT KEY: abc123...
|
|
383
|
-
REPLACEMENT KEY: xyz789...
|
|
384
|
-
|
|
385
|
-
Please update your integration by 2025-11-15.
|
|
386
|
-
|
|
387
|
-
Both keys will work until 2025-11-30.
|
|
388
|
-
After that date, only the new key will be accepted.
|
|
389
|
-
|
|
390
|
-
Update your requests:
|
|
391
|
-
curl -X POST https://workspace.versori.run/webhook \
|
|
392
|
-
-H "x-api-key: xyz789..." \
|
|
393
|
-
-H "Content-Type: application/json" \
|
|
394
|
-
-d '{...}'
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
#### Step 4: Monitor Transition
|
|
398
|
-
|
|
399
|
-
```typescript
|
|
400
|
-
// Add logging to track which key is used
|
|
401
|
-
fn('validate-dual-keys', async ctx => {
|
|
402
|
-
const providedKey = ctx.request().headers.get('x-api-key');
|
|
403
|
-
|
|
404
|
-
if (constantTimeEqual(providedKey, '<old-key>')) {
|
|
405
|
-
ctx.log.warn('Old API key used - please upgrade', {
|
|
406
|
-
keyPrefix: providedKey.substring(0, 8),
|
|
407
|
-
});
|
|
408
|
-
} else if (constantTimeEqual(providedKey, '<new-key>')) {
|
|
409
|
-
ctx.log.info('New API key used');
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// ... validation
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
#### Step 5: Remove Old Key
|
|
417
|
-
|
|
418
|
-
After transition period:
|
|
419
|
-
|
|
420
|
-
```typescript
|
|
421
|
-
// Remove dual-key validation, switch back to connection-based
|
|
422
|
-
|
|
423
|
-
export const myWebhook = webhook('my-webhook', {
|
|
424
|
-
connection: 'my-webhook-auth-v2', // Only new key
|
|
425
|
-
response: { mode: 'sync' },
|
|
426
|
-
}).then(
|
|
427
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
428
|
-
// Business logic...
|
|
429
|
-
})
|
|
430
|
-
);
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
---
|
|
434
|
-
|
|
435
|
-
## Troubleshooting
|
|
436
|
-
|
|
437
|
-
### Issue 1: "401 Unauthorized" on valid requests
|
|
438
|
-
|
|
439
|
-
**Symptoms:**
|
|
440
|
-
|
|
441
|
-
- Webhook always returns 401
|
|
442
|
-
- You're certain the API key is correct
|
|
443
|
-
|
|
444
|
-
**Possible Causes:**
|
|
445
|
-
|
|
446
|
-
1. **Header name mismatch**
|
|
447
|
-
|
|
448
|
-
```
|
|
449
|
-
❌ Wrong: Connection expects 'x-api-key', partner sends 'X-API-Key'
|
|
450
|
-
✅ Correct: Match case and format exactly
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
2. **Whitespace in API key**
|
|
454
|
-
|
|
455
|
-
```
|
|
456
|
-
❌ Wrong: Key has trailing space: "abc123 "
|
|
457
|
-
✅ Correct: Trim key value in connection config
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
3. **Connection not linked to webhook**
|
|
461
|
-
|
|
462
|
-
```typescript
|
|
463
|
-
❌ Wrong: webhook('my-webhook', {}) // Missing connection
|
|
464
|
-
✅ Correct: webhook('my-webhook', { connection: 'my-webhook-auth' })
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
4. **Connection doesn't exist**
|
|
468
|
-
```
|
|
469
|
-
❌ Wrong: Connection name typo: 'my-webohok-auth'
|
|
470
|
-
✅ Correct: Verify exact name in Versori Dashboard
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
### Issue 2: Webhook works without authentication
|
|
474
|
-
|
|
475
|
-
**Symptoms:**
|
|
476
|
-
|
|
477
|
-
- Webhook accepts requests without API key
|
|
478
|
-
- No 401 errors on invalid keys
|
|
479
|
-
|
|
480
|
-
**Cause:** Connection not configured in webhook definition
|
|
481
|
-
|
|
482
|
-
**Solution:**
|
|
483
|
-
|
|
484
|
-
```typescript
|
|
485
|
-
// ❌ WRONG - No auth
|
|
486
|
-
export const myWebhook = webhook('my-webhook', {
|
|
487
|
-
response: { mode: 'sync' },
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
// ✅ CORRECT - With auth
|
|
491
|
-
export const myWebhook = webhook('my-webhook', {
|
|
492
|
-
connection: 'my-webhook-auth', // ← Add this!
|
|
493
|
-
response: { mode: 'sync' },
|
|
494
|
-
});
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### Issue 3: "Connection not found" error
|
|
498
|
-
|
|
499
|
-
**Symptoms:**
|
|
500
|
-
|
|
501
|
-
- Deployment fails
|
|
502
|
-
- Error: "Connection 'xyz' not found"
|
|
503
|
-
|
|
504
|
-
**Cause:** Connection hasn't been created in Versori Dashboard
|
|
505
|
-
|
|
506
|
-
**Solution:**
|
|
507
|
-
|
|
508
|
-
1. Go to Versori Dashboard → Connections
|
|
509
|
-
2. Create connection with exact name referenced in code
|
|
510
|
-
3. Redeploy workflow
|
|
511
|
-
|
|
512
|
-
### Issue 4: Can't test locally
|
|
513
|
-
|
|
514
|
-
**Symptoms:**
|
|
515
|
-
|
|
516
|
-
- Can't run webhook locally with API key validation
|
|
517
|
-
|
|
518
|
-
**Solution:**
|
|
519
|
-
For local development, temporarily disable connection-based auth:
|
|
520
|
-
|
|
521
|
-
```typescript
|
|
522
|
-
// Development mode
|
|
523
|
-
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
524
|
-
|
|
525
|
-
export const myWebhook = webhook('my-webhook', {
|
|
526
|
-
connection: isDevelopment ? undefined : 'my-webhook-auth', // Conditional
|
|
527
|
-
response: { mode: 'sync' },
|
|
528
|
-
})
|
|
529
|
-
.then(
|
|
530
|
-
fn('optional-local-validation', async ctx => {
|
|
531
|
-
if (isDevelopment) {
|
|
532
|
-
ctx.log.warn('Running in development mode - auth disabled');
|
|
533
|
-
}
|
|
534
|
-
return ctx.data;
|
|
535
|
-
})
|
|
536
|
-
)
|
|
537
|
-
.then(
|
|
538
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
539
|
-
// Business logic...
|
|
540
|
-
})
|
|
541
|
-
);
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
---
|
|
545
|
-
|
|
546
|
-
## Security Considerations
|
|
547
|
-
|
|
548
|
-
### What Connection-Based Auth Protects Against
|
|
549
|
-
|
|
550
|
-
✅ **Unauthorized access** - No valid key = rejected at platform
|
|
551
|
-
✅ **Resource exhaustion** - Failed auth never hits workflow
|
|
552
|
-
✅ **Code injection** - Validation happens before code execution
|
|
553
|
-
✅ **Information disclosure** - No error details leak from code
|
|
554
|
-
|
|
555
|
-
### What It Does NOT Protect Against
|
|
556
|
-
|
|
557
|
-
❌ **Replay attacks** - Same request can be sent multiple times
|
|
558
|
-
❌ **Key compromise** - If key leaks, attacker has full access
|
|
559
|
-
❌ **Man-in-the-middle** - Without HTTPS (Versori enforces HTTPS)
|
|
560
|
-
❌ **Request tampering** - No signature validation (consider adding)
|
|
561
|
-
|
|
562
|
-
### Enhancing Security
|
|
563
|
-
|
|
564
|
-
**Layer 1: Connection-based auth (this guide)**
|
|
565
|
-
|
|
566
|
-
```typescript
|
|
567
|
-
webhook('my-webhook', {
|
|
568
|
-
connection: 'my-webhook-auth', // API key validation
|
|
569
|
-
});
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
**Layer 2: Add request validation**
|
|
573
|
-
|
|
574
|
-
```typescript
|
|
575
|
-
.then(fn('validate-request', async (ctx) => {
|
|
576
|
-
const { data } = ctx;
|
|
577
|
-
|
|
578
|
-
// Check required fields
|
|
579
|
-
if (!data.id || !data.timestamp) {
|
|
580
|
-
return new Response(
|
|
581
|
-
JSON.stringify({ error: 'Missing required fields' }),
|
|
582
|
-
{ status: 400 }
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Check timestamp (prevent replay of old requests)
|
|
587
|
-
const requestTime = new Date(data.timestamp).getTime();
|
|
588
|
-
const now = Date.now();
|
|
589
|
-
const maxAge = 5 * 60 * 1000; // 5 minutes
|
|
590
|
-
|
|
591
|
-
if (now - requestTime > maxAge) {
|
|
592
|
-
return new Response(
|
|
593
|
-
JSON.stringify({ error: 'Request expired' }),
|
|
594
|
-
{ status: 400 }
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
return ctx.data;
|
|
599
|
-
}))
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
**Layer 3: Add cryptographic signatures (for Fluent webhooks)**
|
|
603
|
-
|
|
604
|
-
```typescript
|
|
605
|
-
import { WebhookValidationService } from '@fluentcommerce/fc-connect-sdk';
|
|
606
|
-
|
|
607
|
-
.then(fn('validate-signature', async (ctx) => {
|
|
608
|
-
const { request, vars } = ctx;
|
|
609
|
-
const req = request();
|
|
610
|
-
|
|
611
|
-
const signature = req.headers.get('fluent-signature');
|
|
612
|
-
const publicKey = vars?.FLUENT_WEBHOOK_PUBLIC_KEY;
|
|
613
|
-
|
|
614
|
-
const validator = new WebhookValidationService({ publicKey });
|
|
615
|
-
const result = validator.validateWebhook(
|
|
616
|
-
JSON.stringify(ctx.data),
|
|
617
|
-
signature,
|
|
618
|
-
'sha512'
|
|
619
|
-
);
|
|
620
|
-
|
|
621
|
-
if (!result.isValid) {
|
|
622
|
-
return new Response(
|
|
623
|
-
JSON.stringify({ error: 'Invalid signature' }),
|
|
624
|
-
{ status: 403 }
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
return ctx.data;
|
|
629
|
-
}))
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
---
|
|
633
|
-
|
|
634
|
-
## Summary
|
|
635
|
-
|
|
636
|
-
### Quick Reference
|
|
637
|
-
|
|
638
|
-
| Task | Action |
|
|
639
|
-
| ----------------------------- | -------------------------------------------------------------------------- |
|
|
640
|
-
| **Secure a webhook** | Add `connection: 'name'` to webhook definition |
|
|
641
|
-
| **Create connection** | Versori Dashboard → Connections → Add Connection |
|
|
642
|
-
| **Generate API key** | `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` |
|
|
643
|
-
| **Rotate key** | Update connection value in Versori Dashboard |
|
|
644
|
-
| **Share key across webhooks** | Use same connection name in multiple webhooks |
|
|
645
|
-
| **Isolate keys per partner** | Create separate connection for each partner |
|
|
646
|
-
| **Custom header name** | Set "Header Name" in connection config |
|
|
647
|
-
| **Test authentication** | Try requests with valid/invalid/missing keys |
|
|
648
|
-
|
|
649
|
-
### Benefits Recap
|
|
650
|
-
|
|
651
|
-
✅ **Security at platform level** - Validation before code execution
|
|
652
|
-
✅ **No code changes for rotation** - Update connection, not code
|
|
653
|
-
✅ **Resource efficient** - Failed auth never consumes workflow resources
|
|
654
|
-
✅ **Consistent pattern** - Same approach across all webhooks
|
|
655
|
-
✅ **Easy testing** - Clear separation of concerns
|
|
656
|
-
✅ **Better monitoring** - Platform logs all auth attempts
|
|
657
|
-
|
|
658
|
-
### Related Documentation
|
|
659
|
-
|
|
660
|
-
- `Webhook Validation (Cryptographic Signatures)`
|
|
661
|
-
- [Versori Platform Integration](./modules/platforms-versori-01-introduction.md)
|
|
662
|
-
- [Connection Management](./modules/platforms-versori-05-connections.md)
|
|
663
|
-
- [Security Best Practices](./modules/platforms-versori-08-best-practices.md)
|
|
664
|
-
|
|
665
|
-
---
|
|
666
|
-
|
|
667
|
-
**Questions?**
|
|
668
|
-
|
|
669
|
-
- Check [Versori Documentation](https://docs.versori.com) for platform-specific details
|
|
670
|
-
- See template examples in `docs/01-TEMPLATES/versori/workflows/`
|
|
671
|
-
- Contact your Fluent Commerce integration team
|
|
672
|
-
|
|
673
|
-
---
|
|
674
|
-
|
|
675
|
-
**Document Version:** 2.0 (Final - Connection-Based Only)
|
|
676
|
-
**Maintained By:** FC Connect SDK Team
|
|
677
|
-
|
|
678
|
-
**Changelog:**
|
|
679
|
-
|
|
680
|
-
- v2.0: **Cleanup** - Removed OLD/NEW comparison language
|
|
681
|
-
- v1.0: Initial version
|
|
1
|
+
# Versori Webhook Connection-Based Security
|
|
2
|
+
|
|
3
|
+
**Platform:** Versori
|
|
4
|
+
**Security Pattern:** Connection-Level Authentication
|
|
5
|
+
**Level:** Recommended
|
|
6
|
+
**Last Updated:** 2025-10-28
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
This guide explains **connection-based webhook security** in Versori - how to authenticate webhook endpoints at the platform level BEFORE your workflow code runs.
|
|
13
|
+
|
|
14
|
+
### Connection-Based Security Pattern
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
export const myWebhook = webhook('my-webhook', {
|
|
18
|
+
connection: 'my-webhook-auth', // Versori validates BEFORE code runs
|
|
19
|
+
response: { mode: 'sync' },
|
|
20
|
+
}).then(
|
|
21
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
22
|
+
// No validation needed - if we got here, auth passed!
|
|
23
|
+
// Business logic...
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Benefits
|
|
29
|
+
|
|
30
|
+
| Benefit | Description |
|
|
31
|
+
| ---------------------- | -------------------------------------------------------------- |
|
|
32
|
+
| **Security at Edge** | Validation happens at platform level before workflow execution |
|
|
33
|
+
| **No Code Changes** | Rotate keys by updating connection, not code |
|
|
34
|
+
| **Resource Efficient** | Failed auth requests never consume workflow resources |
|
|
35
|
+
| **Consistent Pattern** | Same approach across all webhooks |
|
|
36
|
+
| **Easier Testing** | Clear separation: connection config vs business logic |
|
|
37
|
+
| **Better Logging** | Platform logs all auth attempts automatically |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## How It Works
|
|
42
|
+
|
|
43
|
+
### Request Flow
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
┌─────────────────┐
|
|
47
|
+
│ External │
|
|
48
|
+
│ System/Client │
|
|
49
|
+
└────────┬────────┘
|
|
50
|
+
│
|
|
51
|
+
│ POST /webhook/my-endpoint
|
|
52
|
+
│ Headers:
|
|
53
|
+
│ (as configured on the connection)
|
|
54
|
+
│ Body: { "data": "..." }
|
|
55
|
+
│
|
|
56
|
+
▼
|
|
57
|
+
┌────────────────────────────────────┐
|
|
58
|
+
│ Versori Platform (Edge Layer) │
|
|
59
|
+
│ │
|
|
60
|
+
│ 1. Connection-based authentication│
|
|
61
|
+
│ 2. Load connection: my-webhook-auth│
|
|
62
|
+
│ 3. Compare values (constant time) │
|
|
63
|
+
│ │
|
|
64
|
+
│ ✓ Valid? → Continue to workflow │
|
|
65
|
+
│ ✗ Invalid? → Return 401/403 │
|
|
66
|
+
└────────┬───────────────────────────┘
|
|
67
|
+
│
|
|
68
|
+
│ ✅ Only valid requests proceed
|
|
69
|
+
▼
|
|
70
|
+
┌────────────────────────────────────┐
|
|
71
|
+
│ Your Workflow Code │
|
|
72
|
+
│ │
|
|
73
|
+
│ - No auth validation needed │
|
|
74
|
+
│ - Focus on business logic │
|
|
75
|
+
│ - Process request data │
|
|
76
|
+
└────────────────────────────────────┘
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Security Guarantee
|
|
80
|
+
|
|
81
|
+
If your workflow code executes, authentication has already succeeded. **No manual validation required.**
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Setup Guide
|
|
86
|
+
|
|
87
|
+
### Step 1: Create API Key Connection
|
|
88
|
+
|
|
89
|
+
1. **Navigate to Versori Dashboard**
|
|
90
|
+
- Go to your workspace
|
|
91
|
+
- Click **Connections** in sidebar
|
|
92
|
+
- Click **Add Connection**
|
|
93
|
+
|
|
94
|
+
2. **Configure Connection**
|
|
95
|
+
- **Name**: `my-webhook-auth` (choose descriptive name)
|
|
96
|
+
- **Description**: `API key authentication for my-webhook endpoint`
|
|
97
|
+
- **Type**: `API Key Authentication`
|
|
98
|
+
|
|
99
|
+
3. **Authentication**
|
|
100
|
+
- Configure auth on the connection (no inline headers or variables)
|
|
101
|
+
|
|
102
|
+
4. **Save Connection**
|
|
103
|
+
- Click **Save**
|
|
104
|
+
- Note the connection name for use in code
|
|
105
|
+
|
|
106
|
+
### Step 2: Generate Secure API Keys
|
|
107
|
+
|
|
108
|
+
**Generate cryptographically secure keys (64+ characters recommended):**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Node.js
|
|
112
|
+
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
113
|
+
|
|
114
|
+
# Output example:
|
|
115
|
+
# 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f
|
|
116
|
+
|
|
117
|
+
# Python
|
|
118
|
+
python3 -c "import secrets; print(secrets.token_hex(32))"
|
|
119
|
+
|
|
120
|
+
# OpenSSL
|
|
121
|
+
openssl rand -hex 32
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Key Requirements:**
|
|
125
|
+
|
|
126
|
+
- Minimum 32 characters (64+ recommended)
|
|
127
|
+
- Cryptographically random (don't make up keys!)
|
|
128
|
+
- Alphanumeric (hex format is ideal)
|
|
129
|
+
- Unique per environment (dev/staging/prod)
|
|
130
|
+
- Unique per client (don't share keys between systems)
|
|
131
|
+
|
|
132
|
+
### Step 3: Use Connection in Webhook Definition
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { webhook, http } from '@versori/run';
|
|
136
|
+
|
|
137
|
+
export const mySecureWebhook = webhook('my-webhook', {
|
|
138
|
+
connection: 'my-webhook-auth', // ✅ Reference connection by name
|
|
139
|
+
response: { mode: 'sync' },
|
|
140
|
+
}).then(
|
|
141
|
+
http('process-data', { connection: 'fluent_commerce' }, async ctx => {
|
|
142
|
+
const { log, data } = ctx;
|
|
143
|
+
|
|
144
|
+
// ✅ Authentication already validated by Versori
|
|
145
|
+
// No manual checks needed!
|
|
146
|
+
|
|
147
|
+
log.info('Processing authenticated request', {
|
|
148
|
+
dataSize: JSON.stringify(data).length,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Your business logic here
|
|
152
|
+
return {
|
|
153
|
+
success: true,
|
|
154
|
+
message: 'Request processed',
|
|
155
|
+
timestamp: new Date().toISOString(),
|
|
156
|
+
};
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Step 4: Test the Webhook
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Test (auth handled by connection)
|
|
165
|
+
curl -X POST https://your-workspace.versori.run/my-webhook \
|
|
166
|
+
-H "Content-Type: application/json" \
|
|
167
|
+
-d '{"test": "data"}'
|
|
168
|
+
# Expected: 200 OK with workflow response when using valid connection
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Common Patterns
|
|
174
|
+
|
|
175
|
+
### Pattern 1: Single Webhook, Single Connection
|
|
176
|
+
|
|
177
|
+
**Use Case:** One webhook endpoint with one API key
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Connection: 'order-webhook-auth'
|
|
181
|
+
export const orderWebhook = webhook('order-ingestion', {
|
|
182
|
+
connection: 'order-webhook-auth',
|
|
183
|
+
response: { mode: 'sync' },
|
|
184
|
+
}).then(
|
|
185
|
+
http('process-order', { connection: 'fluent_commerce' }, async ctx => {
|
|
186
|
+
// Process order...
|
|
187
|
+
})
|
|
188
|
+
);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Setup:**
|
|
192
|
+
|
|
193
|
+
- Create 1 connection: `order-webhook-auth`
|
|
194
|
+
- Use in 1 webhook definition
|
|
195
|
+
|
|
196
|
+
### Pattern 2: Multiple Webhooks, Shared Connection
|
|
197
|
+
|
|
198
|
+
**Use Case:** Multiple webhooks sharing same API key (same partner/client)
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Connection: 'partner-api-auth' (shared)
|
|
202
|
+
|
|
203
|
+
export const orderWebhook = webhook('orders', {
|
|
204
|
+
connection: 'partner-api-auth', // Shared connection
|
|
205
|
+
response: { mode: 'sync' },
|
|
206
|
+
}).then(
|
|
207
|
+
http('process-order', { connection: 'fluent' }, async ctx => {
|
|
208
|
+
// Process order...
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
export const inventoryWebhook = webhook('inventory', {
|
|
213
|
+
connection: 'partner-api-auth', // Same connection
|
|
214
|
+
response: { mode: 'sync' },
|
|
215
|
+
}).then(
|
|
216
|
+
http('process-inventory', { connection: 'fluent' }, async ctx => {
|
|
217
|
+
// Process inventory...
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
export const statusWebhook = webhook('status', {
|
|
222
|
+
connection: 'partner-api-auth', // Same connection
|
|
223
|
+
response: { mode: 'sync' },
|
|
224
|
+
}).then(
|
|
225
|
+
http('query-status', { connection: 'fluent' }, async ctx => {
|
|
226
|
+
// Query status...
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Setup:**
|
|
232
|
+
|
|
233
|
+
- Create 1 connection: `partner-api-auth`
|
|
234
|
+
- Use in 3 webhooks
|
|
235
|
+
- All webhooks accept same API key
|
|
236
|
+
- Easy to rotate: update 1 connection, affects all webhooks
|
|
237
|
+
|
|
238
|
+
### Pattern 3: Multiple Webhooks, Different Connections
|
|
239
|
+
|
|
240
|
+
**Use Case:** Different partners/clients need different API keys
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Connections: 'partner-a-auth', 'partner-b-auth', 'partner-c-auth'
|
|
244
|
+
|
|
245
|
+
export const partnerAWebhook = webhook('partner-a-orders', {
|
|
246
|
+
connection: 'partner-a-auth', // Partner A's key
|
|
247
|
+
response: { mode: 'sync' },
|
|
248
|
+
}).then(
|
|
249
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
250
|
+
// Partner A logic...
|
|
251
|
+
})
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
export const partnerBWebhook = webhook('partner-b-orders', {
|
|
255
|
+
connection: 'partner-b-auth', // Partner B's key
|
|
256
|
+
response: { mode: 'sync' },
|
|
257
|
+
}).then(
|
|
258
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
259
|
+
// Partner B logic...
|
|
260
|
+
})
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
export const partnerCWebhook = webhook('partner-c-orders', {
|
|
264
|
+
connection: 'partner-c-auth', // Partner C's key
|
|
265
|
+
response: { mode: 'sync' },
|
|
266
|
+
}).then(
|
|
267
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
268
|
+
// Partner C logic...
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Setup:**
|
|
274
|
+
|
|
275
|
+
- Create 3 connections: one per partner
|
|
276
|
+
- Each webhook uses its partner's connection
|
|
277
|
+
- Isolate security: compromised key only affects one partner
|
|
278
|
+
- Rotate independently per partner
|
|
279
|
+
|
|
280
|
+
### Pattern 4: Custom Header Names
|
|
281
|
+
|
|
282
|
+
**Use Case:** Partner requires custom header
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Connection: 'partner-auth'
|
|
286
|
+
// Header: 'X-Partner-Token' (configured in Versori connection)
|
|
287
|
+
|
|
288
|
+
export const partnerWebhook = webhook('partner-integration', {
|
|
289
|
+
connection: 'partner-auth', // Uses X-Partner-Token header
|
|
290
|
+
response: { mode: 'sync' },
|
|
291
|
+
}).then(
|
|
292
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
293
|
+
// Process...
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Setup in Versori:**
|
|
299
|
+
Configure partner-specific authentication on the connection (e.g., `X-Partner-Token`).
|
|
300
|
+
|
|
301
|
+
**Partner's Request:**
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
curl -X POST https://workspace.versori.run/partner-integration \
|
|
305
|
+
-H "X-Partner-Token: abc123xyz" \
|
|
306
|
+
-H "Content-Type: application/json" \
|
|
307
|
+
-d '{"data": "..."}'
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Key Rotation
|
|
313
|
+
|
|
314
|
+
### Zero-Downtime Key Rotation
|
|
315
|
+
|
|
316
|
+
**Problem:** Need to rotate API key without breaking active integrations
|
|
317
|
+
|
|
318
|
+
**Solution:** Dual-connection pattern (support old + new keys during transition)
|
|
319
|
+
|
|
320
|
+
#### Step 1: Create New Connection
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
Use a new connection `my-webhook-auth-v2` with updated authentication settings.
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### Step 2: Update Webhook to Support Both Keys
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Temporarily accept BOTH old and new keys
|
|
330
|
+
// Note: This requires custom validation (see Advanced Patterns)
|
|
331
|
+
|
|
332
|
+
export const myWebhook = webhook('my-webhook', {
|
|
333
|
+
// Remove connection temporarily for dual-key support
|
|
334
|
+
response: { mode: 'sync' },
|
|
335
|
+
})
|
|
336
|
+
.then(
|
|
337
|
+
fn('validate-dual-keys', async ctx => {
|
|
338
|
+
const { request } = ctx;
|
|
339
|
+
const req = request();
|
|
340
|
+
const providedKey = req.headers.get('x-api-key');
|
|
341
|
+
|
|
342
|
+
// Accept either old or new key during transition
|
|
343
|
+
const validKeys = [
|
|
344
|
+
'<old-key>', // Get from old connection
|
|
345
|
+
'<new-key>', // Get from new connection
|
|
346
|
+
];
|
|
347
|
+
|
|
348
|
+
if (!validKeys.some(k => constantTimeEqual(providedKey, k))) {
|
|
349
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
|
|
350
|
+
status: 401,
|
|
351
|
+
headers: { 'Content-Type': 'application/json' },
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return ctx.data;
|
|
356
|
+
})
|
|
357
|
+
)
|
|
358
|
+
.then(
|
|
359
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
360
|
+
// Business logic...
|
|
361
|
+
})
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Helper function for constant-time string comparison (timing attack prevention)
|
|
365
|
+
function constantTimeEqual(a: string, b: string): boolean {
|
|
366
|
+
if (a.length !== b.length) return false;
|
|
367
|
+
let result = 0;
|
|
368
|
+
for (let i = 0; i < a.length; i++) {
|
|
369
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
370
|
+
}
|
|
371
|
+
return result === 0;
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### Step 3: Notify Partners
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
Subject: API Key Rotation - Action Required
|
|
379
|
+
|
|
380
|
+
We are rotating API keys for enhanced security.
|
|
381
|
+
|
|
382
|
+
CURRENT KEY: abc123...
|
|
383
|
+
REPLACEMENT KEY: xyz789...
|
|
384
|
+
|
|
385
|
+
Please update your integration by 2025-11-15.
|
|
386
|
+
|
|
387
|
+
Both keys will work until 2025-11-30.
|
|
388
|
+
After that date, only the new key will be accepted.
|
|
389
|
+
|
|
390
|
+
Update your requests:
|
|
391
|
+
curl -X POST https://workspace.versori.run/webhook \
|
|
392
|
+
-H "x-api-key: xyz789..." \
|
|
393
|
+
-H "Content-Type: application/json" \
|
|
394
|
+
-d '{...}'
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### Step 4: Monitor Transition
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
// Add logging to track which key is used
|
|
401
|
+
fn('validate-dual-keys', async ctx => {
|
|
402
|
+
const providedKey = ctx.request().headers.get('x-api-key');
|
|
403
|
+
|
|
404
|
+
if (constantTimeEqual(providedKey, '<old-key>')) {
|
|
405
|
+
ctx.log.warn('Old API key used - please upgrade', {
|
|
406
|
+
keyPrefix: providedKey.substring(0, 8),
|
|
407
|
+
});
|
|
408
|
+
} else if (constantTimeEqual(providedKey, '<new-key>')) {
|
|
409
|
+
ctx.log.info('New API key used');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ... validation
|
|
413
|
+
});
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
#### Step 5: Remove Old Key
|
|
417
|
+
|
|
418
|
+
After transition period:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// Remove dual-key validation, switch back to connection-based
|
|
422
|
+
|
|
423
|
+
export const myWebhook = webhook('my-webhook', {
|
|
424
|
+
connection: 'my-webhook-auth-v2', // Only new key
|
|
425
|
+
response: { mode: 'sync' },
|
|
426
|
+
}).then(
|
|
427
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
428
|
+
// Business logic...
|
|
429
|
+
})
|
|
430
|
+
);
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Troubleshooting
|
|
436
|
+
|
|
437
|
+
### Issue 1: "401 Unauthorized" on valid requests
|
|
438
|
+
|
|
439
|
+
**Symptoms:**
|
|
440
|
+
|
|
441
|
+
- Webhook always returns 401
|
|
442
|
+
- You're certain the API key is correct
|
|
443
|
+
|
|
444
|
+
**Possible Causes:**
|
|
445
|
+
|
|
446
|
+
1. **Header name mismatch**
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
❌ Wrong: Connection expects 'x-api-key', partner sends 'X-API-Key'
|
|
450
|
+
✅ Correct: Match case and format exactly
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
2. **Whitespace in API key**
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
❌ Wrong: Key has trailing space: "abc123 "
|
|
457
|
+
✅ Correct: Trim key value in connection config
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
3. **Connection not linked to webhook**
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
❌ Wrong: webhook('my-webhook', {}) // Missing connection
|
|
464
|
+
✅ Correct: webhook('my-webhook', { connection: 'my-webhook-auth' })
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
4. **Connection doesn't exist**
|
|
468
|
+
```
|
|
469
|
+
❌ Wrong: Connection name typo: 'my-webohok-auth'
|
|
470
|
+
✅ Correct: Verify exact name in Versori Dashboard
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Issue 2: Webhook works without authentication
|
|
474
|
+
|
|
475
|
+
**Symptoms:**
|
|
476
|
+
|
|
477
|
+
- Webhook accepts requests without API key
|
|
478
|
+
- No 401 errors on invalid keys
|
|
479
|
+
|
|
480
|
+
**Cause:** Connection not configured in webhook definition
|
|
481
|
+
|
|
482
|
+
**Solution:**
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
// ❌ WRONG - No auth
|
|
486
|
+
export const myWebhook = webhook('my-webhook', {
|
|
487
|
+
response: { mode: 'sync' },
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// ✅ CORRECT - With auth
|
|
491
|
+
export const myWebhook = webhook('my-webhook', {
|
|
492
|
+
connection: 'my-webhook-auth', // ← Add this!
|
|
493
|
+
response: { mode: 'sync' },
|
|
494
|
+
});
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Issue 3: "Connection not found" error
|
|
498
|
+
|
|
499
|
+
**Symptoms:**
|
|
500
|
+
|
|
501
|
+
- Deployment fails
|
|
502
|
+
- Error: "Connection 'xyz' not found"
|
|
503
|
+
|
|
504
|
+
**Cause:** Connection hasn't been created in Versori Dashboard
|
|
505
|
+
|
|
506
|
+
**Solution:**
|
|
507
|
+
|
|
508
|
+
1. Go to Versori Dashboard → Connections
|
|
509
|
+
2. Create connection with exact name referenced in code
|
|
510
|
+
3. Redeploy workflow
|
|
511
|
+
|
|
512
|
+
### Issue 4: Can't test locally
|
|
513
|
+
|
|
514
|
+
**Symptoms:**
|
|
515
|
+
|
|
516
|
+
- Can't run webhook locally with API key validation
|
|
517
|
+
|
|
518
|
+
**Solution:**
|
|
519
|
+
For local development, temporarily disable connection-based auth:
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
// Development mode
|
|
523
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
524
|
+
|
|
525
|
+
export const myWebhook = webhook('my-webhook', {
|
|
526
|
+
connection: isDevelopment ? undefined : 'my-webhook-auth', // Conditional
|
|
527
|
+
response: { mode: 'sync' },
|
|
528
|
+
})
|
|
529
|
+
.then(
|
|
530
|
+
fn('optional-local-validation', async ctx => {
|
|
531
|
+
if (isDevelopment) {
|
|
532
|
+
ctx.log.warn('Running in development mode - auth disabled');
|
|
533
|
+
}
|
|
534
|
+
return ctx.data;
|
|
535
|
+
})
|
|
536
|
+
)
|
|
537
|
+
.then(
|
|
538
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
539
|
+
// Business logic...
|
|
540
|
+
})
|
|
541
|
+
);
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## Security Considerations
|
|
547
|
+
|
|
548
|
+
### What Connection-Based Auth Protects Against
|
|
549
|
+
|
|
550
|
+
✅ **Unauthorized access** - No valid key = rejected at platform
|
|
551
|
+
✅ **Resource exhaustion** - Failed auth never hits workflow
|
|
552
|
+
✅ **Code injection** - Validation happens before code execution
|
|
553
|
+
✅ **Information disclosure** - No error details leak from code
|
|
554
|
+
|
|
555
|
+
### What It Does NOT Protect Against
|
|
556
|
+
|
|
557
|
+
❌ **Replay attacks** - Same request can be sent multiple times
|
|
558
|
+
❌ **Key compromise** - If key leaks, attacker has full access
|
|
559
|
+
❌ **Man-in-the-middle** - Without HTTPS (Versori enforces HTTPS)
|
|
560
|
+
❌ **Request tampering** - No signature validation (consider adding)
|
|
561
|
+
|
|
562
|
+
### Enhancing Security
|
|
563
|
+
|
|
564
|
+
**Layer 1: Connection-based auth (this guide)**
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
webhook('my-webhook', {
|
|
568
|
+
connection: 'my-webhook-auth', // API key validation
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Layer 2: Add request validation**
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
.then(fn('validate-request', async (ctx) => {
|
|
576
|
+
const { data } = ctx;
|
|
577
|
+
|
|
578
|
+
// Check required fields
|
|
579
|
+
if (!data.id || !data.timestamp) {
|
|
580
|
+
return new Response(
|
|
581
|
+
JSON.stringify({ error: 'Missing required fields' }),
|
|
582
|
+
{ status: 400 }
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Check timestamp (prevent replay of old requests)
|
|
587
|
+
const requestTime = new Date(data.timestamp).getTime();
|
|
588
|
+
const now = Date.now();
|
|
589
|
+
const maxAge = 5 * 60 * 1000; // 5 minutes
|
|
590
|
+
|
|
591
|
+
if (now - requestTime > maxAge) {
|
|
592
|
+
return new Response(
|
|
593
|
+
JSON.stringify({ error: 'Request expired' }),
|
|
594
|
+
{ status: 400 }
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return ctx.data;
|
|
599
|
+
}))
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Layer 3: Add cryptographic signatures (for Fluent webhooks)**
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
import { WebhookValidationService } from '@fluentcommerce/fc-connect-sdk';
|
|
606
|
+
|
|
607
|
+
.then(fn('validate-signature', async (ctx) => {
|
|
608
|
+
const { request, vars } = ctx;
|
|
609
|
+
const req = request();
|
|
610
|
+
|
|
611
|
+
const signature = req.headers.get('fluent-signature');
|
|
612
|
+
const publicKey = vars?.FLUENT_WEBHOOK_PUBLIC_KEY;
|
|
613
|
+
|
|
614
|
+
const validator = new WebhookValidationService({ publicKey });
|
|
615
|
+
const result = validator.validateWebhook(
|
|
616
|
+
JSON.stringify(ctx.data),
|
|
617
|
+
signature,
|
|
618
|
+
'sha512'
|
|
619
|
+
);
|
|
620
|
+
|
|
621
|
+
if (!result.isValid) {
|
|
622
|
+
return new Response(
|
|
623
|
+
JSON.stringify({ error: 'Invalid signature' }),
|
|
624
|
+
{ status: 403 }
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return ctx.data;
|
|
629
|
+
}))
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Summary
|
|
635
|
+
|
|
636
|
+
### Quick Reference
|
|
637
|
+
|
|
638
|
+
| Task | Action |
|
|
639
|
+
| ----------------------------- | -------------------------------------------------------------------------- |
|
|
640
|
+
| **Secure a webhook** | Add `connection: 'name'` to webhook definition |
|
|
641
|
+
| **Create connection** | Versori Dashboard → Connections → Add Connection |
|
|
642
|
+
| **Generate API key** | `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` |
|
|
643
|
+
| **Rotate key** | Update connection value in Versori Dashboard |
|
|
644
|
+
| **Share key across webhooks** | Use same connection name in multiple webhooks |
|
|
645
|
+
| **Isolate keys per partner** | Create separate connection for each partner |
|
|
646
|
+
| **Custom header name** | Set "Header Name" in connection config |
|
|
647
|
+
| **Test authentication** | Try requests with valid/invalid/missing keys |
|
|
648
|
+
|
|
649
|
+
### Benefits Recap
|
|
650
|
+
|
|
651
|
+
✅ **Security at platform level** - Validation before code execution
|
|
652
|
+
✅ **No code changes for rotation** - Update connection, not code
|
|
653
|
+
✅ **Resource efficient** - Failed auth never consumes workflow resources
|
|
654
|
+
✅ **Consistent pattern** - Same approach across all webhooks
|
|
655
|
+
✅ **Easy testing** - Clear separation of concerns
|
|
656
|
+
✅ **Better monitoring** - Platform logs all auth attempts
|
|
657
|
+
|
|
658
|
+
### Related Documentation
|
|
659
|
+
|
|
660
|
+
- `Webhook Validation (Cryptographic Signatures)`
|
|
661
|
+
- [Versori Platform Integration](./modules/platforms-versori-01-introduction.md)
|
|
662
|
+
- [Connection Management](./modules/platforms-versori-05-connections.md)
|
|
663
|
+
- [Security Best Practices](./modules/platforms-versori-08-best-practices.md)
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
**Questions?**
|
|
668
|
+
|
|
669
|
+
- Check [Versori Documentation](https://docs.versori.com) for platform-specific details
|
|
670
|
+
- See template examples in `docs/01-TEMPLATES/versori/workflows/`
|
|
671
|
+
- Contact your Fluent Commerce integration team
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
**Document Version:** 2.0 (Final - Connection-Based Only)
|
|
676
|
+
**Maintained By:** FC Connect SDK Team
|
|
677
|
+
|
|
678
|
+
**Changelog:**
|
|
679
|
+
|
|
680
|
+
- v2.0: **Cleanup** - Removed OLD/NEW comparison language
|
|
681
|
+
- v1.0: Initial version
|