@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +11 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
- package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
|
@@ -1,816 +1,816 @@
|
|
|
1
|
-
# Securing Versori Webhooks with Connection-Based API Key Authentication (Zero Code Required)
|
|
2
|
-
|
|
3
|
-
**Platform:** Versori
|
|
4
|
-
**Level:** Beginner
|
|
5
|
-
**Estimated Time:** 10 minutes
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
Versori provides **built-in API key authentication** for webhooks through the connection system. When you configure a connection with API key authentication and reference it in your webhook definition, the platform automatically validates all incoming requests **before your code runs**.
|
|
12
|
-
|
|
13
|
-
**Zero validation code required!**
|
|
14
|
-
|
|
15
|
-
### Key Benefits
|
|
16
|
-
|
|
17
|
-
- **Platform-managed security** - Validation happens before your code executes
|
|
18
|
-
- **No code required** - Just reference the connection by name
|
|
19
|
-
- **401 rejection automatic** - Invalid requests never reach your code
|
|
20
|
-
- **Simple configuration** - Set up once in Versori Dashboard
|
|
21
|
-
- **Easy rotation** - Update keys in UI without code changes
|
|
22
|
-
- **Works for both** - Incoming webhooks AND outgoing API calls
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## How It Works
|
|
27
|
-
|
|
28
|
-
### The Platform Validation Flow
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
┌─────────────────┐
|
|
32
|
-
│ External │
|
|
33
|
-
│ System │
|
|
34
|
-
└────────┬────────┘
|
|
35
|
-
│
|
|
36
|
-
│ POST /webhook/order-create
|
|
37
|
-
│ Headers:
|
|
38
|
-
│ (as configured on the connection)
|
|
39
|
-
│ Body: { order data }
|
|
40
|
-
▼
|
|
41
|
-
┌─────────────────────────────────────┐
|
|
42
|
-
│ Versori Platform │
|
|
43
|
-
│ ┌───────────────────────────────┐ │
|
|
44
|
-
│ │ 1. Connection-based auth │ │
|
|
45
|
-
│ │ 2. Load connection config │ │
|
|
46
|
-
│ │ 3. Compare header to expected │ │
|
|
47
|
-
│ │ 4. Reject if mismatch (401) │ │
|
|
48
|
-
│ └───────────────────────────────┘ │
|
|
49
|
-
└────────────────┬────────────────────┘
|
|
50
|
-
│
|
|
51
|
-
│ ✅ Auth passed
|
|
52
|
-
▼
|
|
53
|
-
┌──────────────────┐
|
|
54
|
-
│ Your Code │
|
|
55
|
-
│ (executes only │
|
|
56
|
-
│ if auth valid) │
|
|
57
|
-
└──────────────────┘
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**Critical Point:** If your code runs, authentication already succeeded!
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Configuration
|
|
65
|
-
|
|
66
|
-
### Step 1: Configure Connection in Versori Dashboard
|
|
67
|
-
|
|
68
|
-
1. **Navigate to Connections**
|
|
69
|
-
- Open Versori Dashboard
|
|
70
|
-
- Go to **Connections** tab
|
|
71
|
-
- Click **"Add Connection"**
|
|
72
|
-
|
|
73
|
-
2. **Create API Key Connection**
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
Connection Settings:
|
|
77
|
-
├── Name: my-webhook-auth
|
|
78
|
-
├── Description: API key for incoming webhooks
|
|
79
|
-
├── Type: API Key
|
|
80
|
-
└── Configuration:
|
|
81
|
-
└── Configure authentication on the Versori connection (no inline headers)
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
3. **Save Connection**
|
|
85
|
-
- Click **"Save"**
|
|
86
|
-
- Note the connection name (`my-webhook-auth`) for use in code
|
|
87
|
-
|
|
88
|
-
### Step 2: Generate Strong API Key
|
|
89
|
-
|
|
90
|
-
**Use cryptographically secure generation:**
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
# Node.js - Generate 64-character key
|
|
94
|
-
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
95
|
-
|
|
96
|
-
# Output (example):
|
|
97
|
-
# 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Key Requirements:**
|
|
101
|
-
|
|
102
|
-
- Minimum 32 characters (64+ recommended)
|
|
103
|
-
- Cryptographically random generation
|
|
104
|
-
- Alphanumeric characters
|
|
105
|
-
- Unique per environment/webhook
|
|
106
|
-
|
|
107
|
-
### Step 3: Distribute API Key to Callers
|
|
108
|
-
|
|
109
|
-
**Provide the API key to systems that will call your webhook:**
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
# Share with caller via secure channel
|
|
113
|
-
# Connection-level authentication configured in Versori UI
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**Never:**
|
|
117
|
-
|
|
118
|
-
- Commit keys to version control
|
|
119
|
-
- Share keys via email/chat
|
|
120
|
-
- Use the same key across environments
|
|
121
|
-
- Log full keys in application logs
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## Implementation
|
|
126
|
-
|
|
127
|
-
### Basic Webhook with API Key Authentication
|
|
128
|
-
|
|
129
|
-
**The simplest possible secure webhook:**
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
import { webhook, http } from '@versori/run';
|
|
133
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Secure webhook with platform-managed API key authentication
|
|
137
|
-
*
|
|
138
|
-
* Platform validates requests via the configured connection automatically.
|
|
139
|
-
* If this code runs, authentication already succeeded!
|
|
140
|
-
*
|
|
141
|
-
* Required connection: 'order-webhook-auth' (type: API Key)
|
|
142
|
-
*/
|
|
143
|
-
export const secureOrderWebhook = webhook('secure-order', {
|
|
144
|
-
connection: 'order-webhook-auth', // ← Platform validates incoming requests!
|
|
145
|
-
response: { mode: 'sync' },
|
|
146
|
-
}).then(
|
|
147
|
-
http('process-order', { connection: 'fluent_commerce' }, async ctx => {
|
|
148
|
-
const { log, data } = ctx;
|
|
149
|
-
|
|
150
|
-
// ✅ If we're here, API key validation already passed!
|
|
151
|
-
// No manual validation code needed!
|
|
152
|
-
|
|
153
|
-
log.info('Processing authenticated order', {
|
|
154
|
-
orderId: data?.orderId,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
const client = await createClient(ctx);
|
|
158
|
-
|
|
159
|
-
// Your business logic here
|
|
160
|
-
const result = await processOrder(client, data);
|
|
161
|
-
|
|
162
|
-
return {
|
|
163
|
-
success: true,
|
|
164
|
-
orderId: data.orderId,
|
|
165
|
-
result,
|
|
166
|
-
};
|
|
167
|
-
})
|
|
168
|
-
);
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
**That's it!** The platform handles everything else.
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## Complete Examples
|
|
176
|
-
|
|
177
|
-
### Example 1: Simple Webhook with API Key Protection
|
|
178
|
-
|
|
179
|
-
**Use Case:** External system sends order data, webhook validates and processes it.
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
import { webhook, http } from '@versori/run';
|
|
183
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Secure order ingestion webhook
|
|
187
|
-
*
|
|
188
|
-
* Connection: 'order-webhook-auth'
|
|
189
|
-
* - Configure authentication on the connection; do not pass headers in code examples
|
|
190
|
-
*/
|
|
191
|
-
export const orderIngestion = webhook('order-ingestion', {
|
|
192
|
-
connection: 'order-webhook-auth', // ← Platform handles auth
|
|
193
|
-
response: { mode: 'sync' },
|
|
194
|
-
}).then(
|
|
195
|
-
http('process', { connection: 'fluent_commerce' }, async ctx => {
|
|
196
|
-
const { log, data } = ctx;
|
|
197
|
-
|
|
198
|
-
// Authentication validated by platform before reaching here
|
|
199
|
-
log.info('Authenticated order received', { orderId: data.orderId });
|
|
200
|
-
|
|
201
|
-
const client = await createClient(ctx);
|
|
202
|
-
|
|
203
|
-
// Create Fluent order
|
|
204
|
-
const mutation = `
|
|
205
|
-
mutation CreateOrder($input: CreateOrderInput!) {
|
|
206
|
-
createOrder(input: $input) {
|
|
207
|
-
id
|
|
208
|
-
ref
|
|
209
|
-
status
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
`;
|
|
213
|
-
|
|
214
|
-
const result = await client.graphql({
|
|
215
|
-
query: mutation,
|
|
216
|
-
variables: {
|
|
217
|
-
input: {
|
|
218
|
-
ref: data.orderId,
|
|
219
|
-
type: data.orderType,
|
|
220
|
-
customer: data.customer,
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
log.info('Order created', {
|
|
226
|
-
fluentOrderId: result.data.createOrder.id,
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
return {
|
|
230
|
-
success: true,
|
|
231
|
-
orderId: data.orderId,
|
|
232
|
-
fluentOrderId: result.data.createOrder.id,
|
|
233
|
-
};
|
|
234
|
-
})
|
|
235
|
-
);
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Example 2: Dual Connections (Incoming + Outgoing)
|
|
239
|
-
|
|
240
|
-
**Use Case:** Receive webhook (authenticate incoming), then call external API (authenticate outgoing).
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
import { webhook, http } from '@versori/run';
|
|
244
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Combined authentication pattern:
|
|
248
|
-
* 1. Incoming: Platform validates webhook caller (connection: 'inventory-webhook-auth')
|
|
249
|
-
* 2. Outgoing: Platform adds auth headers to external API (connection: 'external_api')
|
|
250
|
-
*
|
|
251
|
-
* Required connections:
|
|
252
|
-
* - 'inventory-webhook-auth': API Key for incoming requests
|
|
253
|
-
* - 'external_api': API Key for outgoing requests
|
|
254
|
-
* - 'fluent_commerce': OAuth2 for Fluent API
|
|
255
|
-
*/
|
|
256
|
-
export const inventoryValidation = webhook('inventory-validation', {
|
|
257
|
-
connection: 'inventory-webhook-auth', // ← Platform validates incoming request
|
|
258
|
-
response: { mode: 'sync' },
|
|
259
|
-
})
|
|
260
|
-
.then(
|
|
261
|
-
http(
|
|
262
|
-
'validate-external',
|
|
263
|
-
{
|
|
264
|
-
connection: 'external_api', // ← Platform adds auth headers to outgoing requests
|
|
265
|
-
},
|
|
266
|
-
async ctx => {
|
|
267
|
-
const { log, data } = ctx;
|
|
268
|
-
|
|
269
|
-
// ✅ Incoming authentication already validated by platform
|
|
270
|
-
|
|
271
|
-
log.info('Validating inventory with external system', {
|
|
272
|
-
sku: data.sku,
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Call external API - auth headers automatically added by platform
|
|
276
|
-
const response = await ctx.fetch('https://api.external.com/validate', {
|
|
277
|
-
method: 'POST',
|
|
278
|
-
body: JSON.stringify({ sku: data.sku }),
|
|
279
|
-
headers: { 'Content-Type': 'application/json' },
|
|
280
|
-
// Auth headers automatically added by Versori
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
const validation = await response.json();
|
|
284
|
-
|
|
285
|
-
return {
|
|
286
|
-
step: 'validation',
|
|
287
|
-
sku: data.sku,
|
|
288
|
-
valid: validation.valid,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
)
|
|
292
|
-
)
|
|
293
|
-
.then(
|
|
294
|
-
http(
|
|
295
|
-
'update-fluent',
|
|
296
|
-
{
|
|
297
|
-
connection: 'fluent_commerce',
|
|
298
|
-
},
|
|
299
|
-
async ctx => {
|
|
300
|
-
const { log, data } = ctx;
|
|
301
|
-
|
|
302
|
-
// Update Fluent with validation result
|
|
303
|
-
const client = await createClient(ctx);
|
|
304
|
-
|
|
305
|
-
const mutation = `
|
|
306
|
-
mutation UpdateInventory($input: UpdateInventoryInput!) {
|
|
307
|
-
updateInventory(input: $input) {
|
|
308
|
-
id
|
|
309
|
-
ref
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
`;
|
|
313
|
-
|
|
314
|
-
await client.graphql({
|
|
315
|
-
query: mutation,
|
|
316
|
-
variables: {
|
|
317
|
-
input: {
|
|
318
|
-
ref: data.sku,
|
|
319
|
-
validated: data.valid,
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
log.info('Inventory updated in Fluent', {
|
|
325
|
-
sku: data.sku,
|
|
326
|
-
valid: data.valid,
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
return {
|
|
330
|
-
success: true,
|
|
331
|
-
sku: data.sku,
|
|
332
|
-
validated: data.valid,
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
)
|
|
336
|
-
);
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
### Example 3: Real-World - Ad-Hoc Extraction Webhook
|
|
340
|
-
|
|
341
|
-
**Use Case:** Trigger on-demand data extraction via authenticated webhook.
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
import { webhook, http } from '@versori/run';
|
|
345
|
-
import { createClient, ExtractionOrchestrator } from '@fluentcommerce/fc-connect-sdk';
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Ad-hoc virtual positions extraction
|
|
349
|
-
*
|
|
350
|
-
* Triggered by external system with API key authentication.
|
|
351
|
-
* Extracts data from Fluent and returns results.
|
|
352
|
-
*
|
|
353
|
-
* Connection: 'extraction-webhook-auth'
|
|
354
|
-
* - Use a dedicated connection for extraction triggers with appropriate authentication
|
|
355
|
-
*/
|
|
356
|
-
export const adhocExtraction = webhook('adhoc-extraction', {
|
|
357
|
-
connection: 'extraction-webhook-auth', // ← Platform validates before execution
|
|
358
|
-
response: { mode: 'sync' },
|
|
359
|
-
}).then(
|
|
360
|
-
http('extract', { connection: 'fluent_commerce' }, async ctx => {
|
|
361
|
-
const { log, data, activation } = ctx;
|
|
362
|
-
|
|
363
|
-
// ✅ Authentication already validated by platform
|
|
364
|
-
// If we're here, the caller provided valid API key
|
|
365
|
-
|
|
366
|
-
log.info('Starting ad-hoc extraction', {
|
|
367
|
-
requestedBy: data.requestedBy,
|
|
368
|
-
filters: data.filters,
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
const client = await createClient(ctx);
|
|
372
|
-
|
|
373
|
-
// Build query based on request parameters
|
|
374
|
-
const query = `
|
|
375
|
-
query GetVirtualPositions(
|
|
376
|
-
$first: Int,
|
|
377
|
-
$after: String,
|
|
378
|
-
$locationRef: [String!]
|
|
379
|
-
) {
|
|
380
|
-
virtualPositions(
|
|
381
|
-
first: $first,
|
|
382
|
-
after: $after,
|
|
383
|
-
locationRef: $locationRef
|
|
384
|
-
) {
|
|
385
|
-
edges {
|
|
386
|
-
node {
|
|
387
|
-
id
|
|
388
|
-
ref
|
|
389
|
-
productRef
|
|
390
|
-
quantity
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
pageInfo {
|
|
394
|
-
hasNextPage
|
|
395
|
-
endCursor
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
`;
|
|
400
|
-
|
|
401
|
-
// Use ExtractionOrchestrator for pagination
|
|
402
|
-
const orchestrator = new ExtractionOrchestrator(client, log);
|
|
403
|
-
|
|
404
|
-
const results = await orchestrator.extractWithPagination({
|
|
405
|
-
query,
|
|
406
|
-
variables: {
|
|
407
|
-
locationRef: data.filters?.locations || null,
|
|
408
|
-
},
|
|
409
|
-
dataPath: 'virtualPositions',
|
|
410
|
-
pageSize: 100,
|
|
411
|
-
maxPages: 50,
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
log.info('Extraction completed', {
|
|
415
|
-
totalRecords: results.data.length,
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
return {
|
|
419
|
-
success: true,
|
|
420
|
-
recordCount: results.data.length,
|
|
421
|
-
data: results.data,
|
|
422
|
-
metadata: {
|
|
423
|
-
requestedBy: data.requestedBy,
|
|
424
|
-
timestamp: new Date().toISOString(),
|
|
425
|
-
},
|
|
426
|
-
};
|
|
427
|
-
})
|
|
428
|
-
);
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
---
|
|
432
|
-
|
|
433
|
-
## Testing
|
|
434
|
-
|
|
435
|
-
### Test with Valid API Key
|
|
436
|
-
|
|
437
|
-
**Expected: 200 OK, workflow executes:**
|
|
438
|
-
|
|
439
|
-
```bash
|
|
440
|
-
curl -X POST https://yourworkspace.versori.run/webhooks/secure-order \
|
|
441
|
-
-H "X-API-Key: 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f" \
|
|
442
|
-
-H "Content-Type: application/json" \
|
|
443
|
-
-d '{
|
|
444
|
-
"orderId": "ORD-123",
|
|
445
|
-
"orderType": "STANDARD",
|
|
446
|
-
"customer": { "email": "test@example.com" }
|
|
447
|
-
}'
|
|
448
|
-
|
|
449
|
-
# Response:
|
|
450
|
-
# HTTP/1.1 200 OK
|
|
451
|
-
# {
|
|
452
|
-
# "success": true,
|
|
453
|
-
# "orderId": "ORD-123",
|
|
454
|
-
# "fluentOrderId": "123456"
|
|
455
|
-
# }
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
### Test with Missing API Key
|
|
459
|
-
|
|
460
|
-
**Expected: 401 Unauthorized, code never runs:**
|
|
461
|
-
|
|
462
|
-
```bash
|
|
463
|
-
curl -X POST https://yourworkspace.versori.run/webhooks/secure-order \
|
|
464
|
-
-H "Content-Type: application/json" \
|
|
465
|
-
-d '{
|
|
466
|
-
"orderId": "ORD-123",
|
|
467
|
-
"orderType": "STANDARD"
|
|
468
|
-
}'
|
|
469
|
-
|
|
470
|
-
# Response:
|
|
471
|
-
# HTTP/1.1 401 Unauthorized
|
|
472
|
-
# {
|
|
473
|
-
# "error": "Missing authentication",
|
|
474
|
-
# "message": "X-API-Key header required"
|
|
475
|
-
# }
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
### Test with Invalid API Key
|
|
479
|
-
|
|
480
|
-
**Expected: 401 Unauthorized, code never runs:**
|
|
481
|
-
|
|
482
|
-
```bash
|
|
483
|
-
curl -X POST https://yourworkspace.versori.run/webhooks/secure-order \
|
|
484
|
-
-H "X-API-Key: wrong-key-12345" \
|
|
485
|
-
-H "Content-Type: application/json" \
|
|
486
|
-
-d '{
|
|
487
|
-
"orderId": "ORD-123",
|
|
488
|
-
"orderType": "STANDARD"
|
|
489
|
-
}'
|
|
490
|
-
|
|
491
|
-
# Response:
|
|
492
|
-
# HTTP/1.1 401 Unauthorized
|
|
493
|
-
# {
|
|
494
|
-
# "error": "Invalid authentication",
|
|
495
|
-
# "message": "API key validation failed"
|
|
496
|
-
# }
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
### Test Outgoing API Call
|
|
500
|
-
|
|
501
|
-
**Verify platform adds auth headers automatically:**
|
|
502
|
-
|
|
503
|
-
```typescript
|
|
504
|
-
export const debugConnection = http(
|
|
505
|
-
'debug',
|
|
506
|
-
{
|
|
507
|
-
connection: 'external_api',
|
|
508
|
-
},
|
|
509
|
-
async ctx => {
|
|
510
|
-
const { log } = ctx;
|
|
511
|
-
|
|
512
|
-
// Log connection details (never log actual keys!)
|
|
513
|
-
const conn = ctx.activation?.connection;
|
|
514
|
-
log.info('Connection loaded', {
|
|
515
|
-
hasUrl: !!conn?.url,
|
|
516
|
-
hasHeaders: !!conn?.headers,
|
|
517
|
-
headerNames: Object.keys(conn?.headers || {}),
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
// Test API call - auth headers automatically added
|
|
521
|
-
try {
|
|
522
|
-
const response = await ctx.fetch('https://api.external.com/health');
|
|
523
|
-
|
|
524
|
-
log.info('Connection test succeeded', {
|
|
525
|
-
status: response.status,
|
|
526
|
-
ok: response.ok,
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
return { success: true, connected: true };
|
|
530
|
-
} catch (error) {
|
|
531
|
-
log.error('Connection test failed', { error: error.message });
|
|
532
|
-
return { success: false, error: error.message };
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
);
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
---
|
|
539
|
-
|
|
540
|
-
## Best Practices
|
|
541
|
-
|
|
542
|
-
### 1. Use Strong, Random Keys
|
|
543
|
-
|
|
544
|
-
```bash
|
|
545
|
-
# ✅ CORRECT - 64 characters, cryptographically random
|
|
546
|
-
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
547
|
-
# Output: 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f
|
|
548
|
-
|
|
549
|
-
# ❌ WRONG - Short, predictable
|
|
550
|
-
X-API-Key: secret123
|
|
551
|
-
```
|
|
552
|
-
|
|
553
|
-
### 2. One Connection Per Webhook/Purpose
|
|
554
|
-
|
|
555
|
-
```typescript
|
|
556
|
-
// ✅ CORRECT - Separate connections for different purposes
|
|
557
|
-
export const orderWebhook = webhook('orders', {
|
|
558
|
-
connection: 'order-webhook-auth', // Orders connection
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
export const inventoryWebhook = webhook('inventory', {
|
|
562
|
-
connection: 'inventory-webhook-auth', // Inventory connection
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
// ❌ WRONG - Shared key across different systems
|
|
566
|
-
export const orderWebhook = webhook('orders', {
|
|
567
|
-
connection: 'shared-webhook-auth', // Don't reuse!
|
|
568
|
-
});
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
### 3. Rotate Keys Regularly
|
|
572
|
-
|
|
573
|
-
**Update in Versori Dashboard (no code changes needed):**
|
|
574
|
-
|
|
575
|
-
1. Generate new key: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
|
|
576
|
-
2. Update connection in Versori Dashboard
|
|
577
|
-
3. Distribute new key to callers
|
|
578
|
-
4. No code deployment required!
|
|
579
|
-
|
|
580
|
-
**Rotation Schedule:**
|
|
581
|
-
|
|
582
|
-
- Development: Every 90 days
|
|
583
|
-
- Staging: Every 60 days
|
|
584
|
-
- Production: Every 30 days
|
|
585
|
-
|
|
586
|
-
### 4. Document Connection Requirements
|
|
587
|
-
|
|
588
|
-
```typescript
|
|
589
|
-
/**
|
|
590
|
-
* Secure Order Processing Webhook
|
|
591
|
-
*
|
|
592
|
-
* Required Connections:
|
|
593
|
-
* 1. 'order-webhook-auth' (API Key - Incoming)
|
|
594
|
-
* - Authentication is enforced by the Versori connection prior to code execution
|
|
595
|
-
*
|
|
596
|
-
* 2. 'fluent_commerce' (OAuth2 - Outgoing)
|
|
597
|
-
* - Type: OAuth2
|
|
598
|
-
* - Purpose: Authenticate requests to Fluent API
|
|
599
|
-
*
|
|
600
|
-
* Setup:
|
|
601
|
-
* 1. Create both connections in Versori Dashboard
|
|
602
|
-
* 2. Provide X-API-Key to webhook callers
|
|
603
|
-
* 3. Deploy webhook
|
|
604
|
-
*/
|
|
605
|
-
export const secureOrderWebhook = webhook('secure-order', {
|
|
606
|
-
connection: 'order-webhook-auth',
|
|
607
|
-
// ... rest of webhook
|
|
608
|
-
});
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
### 5. Log Security Events (Safely)
|
|
612
|
-
|
|
613
|
-
```typescript
|
|
614
|
-
export const secureWebhook = webhook('secure', {
|
|
615
|
-
connection: 'webhook-auth',
|
|
616
|
-
response: { mode: 'sync' },
|
|
617
|
-
}).then(
|
|
618
|
-
http('process', { connection: 'fluent' }, async ctx => {
|
|
619
|
-
const { log, data, request } = ctx;
|
|
620
|
-
|
|
621
|
-
// ✅ CORRECT - Log without exposing keys
|
|
622
|
-
const req = request();
|
|
623
|
-
log.info('Authenticated request received', {
|
|
624
|
-
endpoint: req.url,
|
|
625
|
-
method: req.method,
|
|
626
|
-
hasApiKey: !!req.headers.get('x-api-key'),
|
|
627
|
-
keyPrefix: req.headers.get('x-api-key')?.substring(0, 8) + '...',
|
|
628
|
-
ipAddress: req.headers.get('x-forwarded-for'),
|
|
629
|
-
timestamp: new Date().toISOString(),
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
// ❌ WRONG - Exposes full API key
|
|
633
|
-
log.info('Request', {
|
|
634
|
-
apiKey: req.headers.get('x-api-key'), // NEVER log full keys!
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
// Process request...
|
|
638
|
-
})
|
|
639
|
-
);
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
### 6. Use Descriptive Connection Names
|
|
643
|
-
|
|
644
|
-
```typescript
|
|
645
|
-
// ✅ CORRECT - Clear purpose
|
|
646
|
-
connection: 'order-webhook-auth';
|
|
647
|
-
connection: 'inventory-extraction-trigger';
|
|
648
|
-
connection: 'shopify-order-sync-webhook';
|
|
649
|
-
|
|
650
|
-
// ❌ WRONG - Vague names
|
|
651
|
-
connection: 'webhook1';
|
|
652
|
-
connection: 'api-key';
|
|
653
|
-
connection: 'auth';
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
---
|
|
657
|
-
|
|
658
|
-
## Troubleshooting
|
|
659
|
-
|
|
660
|
-
### Issue: 401 Unauthorized (Valid Key)
|
|
661
|
-
|
|
662
|
-
**Symptoms:**
|
|
663
|
-
|
|
664
|
-
- You're providing the correct API key
|
|
665
|
-
- Still getting 401 Unauthorized
|
|
666
|
-
- Code never executes
|
|
667
|
-
|
|
668
|
-
**Possible Causes:**
|
|
669
|
-
|
|
670
|
-
1. **Header name mismatch:**
|
|
671
|
-
|
|
672
|
-
```bash
|
|
673
|
-
# Check connection config - must match exactly
|
|
674
|
-
Connection: X-API-Key (configured)
|
|
675
|
-
Request: x-api-key (sent) # ❌ Case-sensitive!
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
2. **Whitespace in key:**
|
|
679
|
-
|
|
680
|
-
```bash
|
|
681
|
-
# ❌ WRONG - Extra space
|
|
682
|
-
curl -H "X-API-Key: abc123 "
|
|
683
|
-
|
|
684
|
-
# ✅ CORRECT - No whitespace
|
|
685
|
-
curl -H "X-API-Key: abc123"
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
3. **Wrong connection name:**
|
|
689
|
-
|
|
690
|
-
```typescript
|
|
691
|
-
// Webhook references: 'order-webhook-auth'
|
|
692
|
-
webhook('orders', { connection: 'order-webhook-auth' });
|
|
693
|
-
|
|
694
|
-
// But connection in UI is named: 'order-webhook' ❌
|
|
695
|
-
// Fix: Match names exactly!
|
|
696
|
-
```
|
|
697
|
-
|
|
698
|
-
### Issue: Connection Not Found
|
|
699
|
-
|
|
700
|
-
**Symptoms:**
|
|
701
|
-
|
|
702
|
-
- Error: "Connection not found"
|
|
703
|
-
- Webhook fails to start
|
|
704
|
-
|
|
705
|
-
**Solution:**
|
|
706
|
-
|
|
707
|
-
1. Verify connection exists in Versori Dashboard
|
|
708
|
-
2. Check connection name matches exactly (case-sensitive)
|
|
709
|
-
3. Ensure connection is saved and active
|
|
710
|
-
|
|
711
|
-
### Issue: Auth Headers Not Added (Outgoing)
|
|
712
|
-
|
|
713
|
-
**Symptoms:**
|
|
714
|
-
|
|
715
|
-
- External API returns 401
|
|
716
|
-
- Auth headers missing from request
|
|
717
|
-
- Outgoing API call fails
|
|
718
|
-
|
|
719
|
-
**Solution:**
|
|
720
|
-
|
|
721
|
-
1. Verify `connection` parameter specified in `http()` options:
|
|
722
|
-
|
|
723
|
-
```typescript
|
|
724
|
-
// ✅ CORRECT
|
|
725
|
-
.then(http('call-api', { connection: 'external_api' }, async (ctx) => {
|
|
726
|
-
await ctx.fetch('https://api.external.com/data');
|
|
727
|
-
}))
|
|
728
|
-
|
|
729
|
-
// ❌ WRONG - Missing connection
|
|
730
|
-
.then(http('call-api', async (ctx) => {
|
|
731
|
-
await ctx.fetch('https://api.external.com/data');
|
|
732
|
-
}))
|
|
733
|
-
```
|
|
734
|
-
|
|
735
|
-
2. Check connection configuration in Versori Dashboard
|
|
736
|
-
3. Verify connection type matches API requirements
|
|
737
|
-
|
|
738
|
-
### Issue: Need Different Keys Per Environment
|
|
739
|
-
|
|
740
|
-
**Solution:** Use environment-specific connections:
|
|
741
|
-
|
|
742
|
-
```typescript
|
|
743
|
-
// Development environment
|
|
744
|
-
webhook('orders-dev', { connection: 'order-webhook-auth-dev' });
|
|
745
|
-
|
|
746
|
-
// Production environment
|
|
747
|
-
webhook('orders-prod', { connection: 'order-webhook-auth-prod' });
|
|
748
|
-
```
|
|
749
|
-
|
|
750
|
-
Configure different keys in Versori Dashboard for each environment.
|
|
751
|
-
|
|
752
|
-
---
|
|
753
|
-
|
|
754
|
-
## Summary
|
|
755
|
-
|
|
756
|
-
### Key Takeaways
|
|
757
|
-
|
|
758
|
-
**Connection-Based Authentication (Recommended):**
|
|
759
|
-
|
|
760
|
-
- ✅ Zero validation code required
|
|
761
|
-
- ✅ Platform validates before code runs
|
|
762
|
-
- ✅ Configure once in Versori Dashboard
|
|
763
|
-
- ✅ Reference by name: `{ connection: 'webhook-auth' }`
|
|
764
|
-
- ✅ Works for incoming AND outgoing requests
|
|
765
|
-
- ✅ Rotate keys in UI without code changes
|
|
766
|
-
- ✅ Automatic 401 rejection for invalid requests
|
|
767
|
-
|
|
768
|
-
**The Magic Line:**
|
|
769
|
-
|
|
770
|
-
```typescript
|
|
771
|
-
webhook('my-webhook', {
|
|
772
|
-
connection: 'webhook-auth', // ← This ONE line enables platform validation
|
|
773
|
-
});
|
|
774
|
-
```
|
|
775
|
-
|
|
776
|
-
### Quick Decision Guide
|
|
777
|
-
|
|
778
|
-
| Scenario | Pattern | Code Required |
|
|
779
|
-
| ------------------------------- | ----------------------- | ------------- |
|
|
780
|
-
| **Incoming webhook needs auth** | Connection-based | Zero |
|
|
781
|
-
| **Webhook calls external API** | Connection-based | Zero |
|
|
782
|
-
| **Both incoming + outgoing** | Connection-based (both) | Zero |
|
|
783
|
-
| **Custom auth algorithm** | Manual validation | Moderate |
|
|
784
|
-
|
|
785
|
-
### Setup Checklist
|
|
786
|
-
|
|
787
|
-
- [ ] Generate strong API key (64+ characters)
|
|
788
|
-
- [ ] Create connection in Versori Dashboard
|
|
789
|
-
- [ ] Configure API Key type and header name
|
|
790
|
-
- [ ] Add connection to webhook definition
|
|
791
|
-
- [ ] Distribute key to webhook callers
|
|
792
|
-
- [ ] Test with valid/invalid keys
|
|
793
|
-
- [ ] Document connection requirements
|
|
794
|
-
- [ ] Set up key rotation schedule
|
|
795
|
-
|
|
796
|
-
---
|
|
797
|
-
|
|
798
|
-
## Related Documentation
|
|
799
|
-
|
|
800
|
-
- [Module 5: Connection Management](./modules/platforms-versori-05-connections.md) - Detailed connection configuration
|
|
801
|
-
- [Webhook Validation Guide](../../../02-CORE-GUIDES/webhook-validation/webhook-validation-readme.md) - Cryptographic signature validation (Fluent webhooks)
|
|
802
|
-
- [Module 3: Versori Integration](../../../02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md) - Combining API keys with signatures
|
|
803
|
-
- [KV State Management Pattern](../../../01-TEMPLATES/versori/patterns/kv-state-management.md) - Request deduplication
|
|
804
|
-
- [XML Response Patterns](../../../01-TEMPLATES/versori/patterns/xml-response-patterns.md) - Custom response formats
|
|
805
|
-
|
|
806
|
-
---
|
|
807
|
-
|
|
808
|
-
**Document Version:** 4.0 (Final - Connection-Based Only)
|
|
809
|
-
**Maintained By:** FC Connect SDK Team
|
|
810
|
-
|
|
811
|
-
**Changelog:**
|
|
812
|
-
|
|
813
|
-
- v4.0: **Cleanup** - Focused on connection-based patterns
|
|
814
|
-
- v3.0: Major rewrite - Documented connection-based pattern
|
|
815
|
-
- v2.0: Clarified use cases
|
|
816
|
-
- v1.0: Initial version
|
|
1
|
+
# Securing Versori Webhooks with Connection-Based API Key Authentication (Zero Code Required)
|
|
2
|
+
|
|
3
|
+
**Platform:** Versori
|
|
4
|
+
**Level:** Beginner
|
|
5
|
+
**Estimated Time:** 10 minutes
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Versori provides **built-in API key authentication** for webhooks through the connection system. When you configure a connection with API key authentication and reference it in your webhook definition, the platform automatically validates all incoming requests **before your code runs**.
|
|
12
|
+
|
|
13
|
+
**Zero validation code required!**
|
|
14
|
+
|
|
15
|
+
### Key Benefits
|
|
16
|
+
|
|
17
|
+
- **Platform-managed security** - Validation happens before your code executes
|
|
18
|
+
- **No code required** - Just reference the connection by name
|
|
19
|
+
- **401 rejection automatic** - Invalid requests never reach your code
|
|
20
|
+
- **Simple configuration** - Set up once in Versori Dashboard
|
|
21
|
+
- **Easy rotation** - Update keys in UI without code changes
|
|
22
|
+
- **Works for both** - Incoming webhooks AND outgoing API calls
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## How It Works
|
|
27
|
+
|
|
28
|
+
### The Platform Validation Flow
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
┌─────────────────┐
|
|
32
|
+
│ External │
|
|
33
|
+
│ System │
|
|
34
|
+
└────────┬────────┘
|
|
35
|
+
│
|
|
36
|
+
│ POST /webhook/order-create
|
|
37
|
+
│ Headers:
|
|
38
|
+
│ (as configured on the connection)
|
|
39
|
+
│ Body: { order data }
|
|
40
|
+
▼
|
|
41
|
+
┌─────────────────────────────────────┐
|
|
42
|
+
│ Versori Platform │
|
|
43
|
+
│ ┌───────────────────────────────┐ │
|
|
44
|
+
│ │ 1. Connection-based auth │ │
|
|
45
|
+
│ │ 2. Load connection config │ │
|
|
46
|
+
│ │ 3. Compare header to expected │ │
|
|
47
|
+
│ │ 4. Reject if mismatch (401) │ │
|
|
48
|
+
│ └───────────────────────────────┘ │
|
|
49
|
+
└────────────────┬────────────────────┘
|
|
50
|
+
│
|
|
51
|
+
│ ✅ Auth passed
|
|
52
|
+
▼
|
|
53
|
+
┌──────────────────┐
|
|
54
|
+
│ Your Code │
|
|
55
|
+
│ (executes only │
|
|
56
|
+
│ if auth valid) │
|
|
57
|
+
└──────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Critical Point:** If your code runs, authentication already succeeded!
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
### Step 1: Configure Connection in Versori Dashboard
|
|
67
|
+
|
|
68
|
+
1. **Navigate to Connections**
|
|
69
|
+
- Open Versori Dashboard
|
|
70
|
+
- Go to **Connections** tab
|
|
71
|
+
- Click **"Add Connection"**
|
|
72
|
+
|
|
73
|
+
2. **Create API Key Connection**
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Connection Settings:
|
|
77
|
+
├── Name: my-webhook-auth
|
|
78
|
+
├── Description: API key for incoming webhooks
|
|
79
|
+
├── Type: API Key
|
|
80
|
+
└── Configuration:
|
|
81
|
+
└── Configure authentication on the Versori connection (no inline headers)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
3. **Save Connection**
|
|
85
|
+
- Click **"Save"**
|
|
86
|
+
- Note the connection name (`my-webhook-auth`) for use in code
|
|
87
|
+
|
|
88
|
+
### Step 2: Generate Strong API Key
|
|
89
|
+
|
|
90
|
+
**Use cryptographically secure generation:**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Node.js - Generate 64-character key
|
|
94
|
+
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
95
|
+
|
|
96
|
+
# Output (example):
|
|
97
|
+
# 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Key Requirements:**
|
|
101
|
+
|
|
102
|
+
- Minimum 32 characters (64+ recommended)
|
|
103
|
+
- Cryptographically random generation
|
|
104
|
+
- Alphanumeric characters
|
|
105
|
+
- Unique per environment/webhook
|
|
106
|
+
|
|
107
|
+
### Step 3: Distribute API Key to Callers
|
|
108
|
+
|
|
109
|
+
**Provide the API key to systems that will call your webhook:**
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Share with caller via secure channel
|
|
113
|
+
# Connection-level authentication configured in Versori UI
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Never:**
|
|
117
|
+
|
|
118
|
+
- Commit keys to version control
|
|
119
|
+
- Share keys via email/chat
|
|
120
|
+
- Use the same key across environments
|
|
121
|
+
- Log full keys in application logs
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Implementation
|
|
126
|
+
|
|
127
|
+
### Basic Webhook with API Key Authentication
|
|
128
|
+
|
|
129
|
+
**The simplest possible secure webhook:**
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { webhook, http } from '@versori/run';
|
|
133
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Secure webhook with platform-managed API key authentication
|
|
137
|
+
*
|
|
138
|
+
* Platform validates requests via the configured connection automatically.
|
|
139
|
+
* If this code runs, authentication already succeeded!
|
|
140
|
+
*
|
|
141
|
+
* Required connection: 'order-webhook-auth' (type: API Key)
|
|
142
|
+
*/
|
|
143
|
+
export const secureOrderWebhook = webhook('secure-order', {
|
|
144
|
+
connection: 'order-webhook-auth', // ← Platform validates incoming requests!
|
|
145
|
+
response: { mode: 'sync' },
|
|
146
|
+
}).then(
|
|
147
|
+
http('process-order', { connection: 'fluent_commerce' }, async ctx => {
|
|
148
|
+
const { log, data } = ctx;
|
|
149
|
+
|
|
150
|
+
// ✅ If we're here, API key validation already passed!
|
|
151
|
+
// No manual validation code needed!
|
|
152
|
+
|
|
153
|
+
log.info('Processing authenticated order', {
|
|
154
|
+
orderId: data?.orderId,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const client = await createClient(ctx);
|
|
158
|
+
|
|
159
|
+
// Your business logic here
|
|
160
|
+
const result = await processOrder(client, data);
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
success: true,
|
|
164
|
+
orderId: data.orderId,
|
|
165
|
+
result,
|
|
166
|
+
};
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**That's it!** The platform handles everything else.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Complete Examples
|
|
176
|
+
|
|
177
|
+
### Example 1: Simple Webhook with API Key Protection
|
|
178
|
+
|
|
179
|
+
**Use Case:** External system sends order data, webhook validates and processes it.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { webhook, http } from '@versori/run';
|
|
183
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Secure order ingestion webhook
|
|
187
|
+
*
|
|
188
|
+
* Connection: 'order-webhook-auth'
|
|
189
|
+
* - Configure authentication on the connection; do not pass headers in code examples
|
|
190
|
+
*/
|
|
191
|
+
export const orderIngestion = webhook('order-ingestion', {
|
|
192
|
+
connection: 'order-webhook-auth', // ← Platform handles auth
|
|
193
|
+
response: { mode: 'sync' },
|
|
194
|
+
}).then(
|
|
195
|
+
http('process', { connection: 'fluent_commerce' }, async ctx => {
|
|
196
|
+
const { log, data } = ctx;
|
|
197
|
+
|
|
198
|
+
// Authentication validated by platform before reaching here
|
|
199
|
+
log.info('Authenticated order received', { orderId: data.orderId });
|
|
200
|
+
|
|
201
|
+
const client = await createClient(ctx);
|
|
202
|
+
|
|
203
|
+
// Create Fluent order
|
|
204
|
+
const mutation = `
|
|
205
|
+
mutation CreateOrder($input: CreateOrderInput!) {
|
|
206
|
+
createOrder(input: $input) {
|
|
207
|
+
id
|
|
208
|
+
ref
|
|
209
|
+
status
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
`;
|
|
213
|
+
|
|
214
|
+
const result = await client.graphql({
|
|
215
|
+
query: mutation,
|
|
216
|
+
variables: {
|
|
217
|
+
input: {
|
|
218
|
+
ref: data.orderId,
|
|
219
|
+
type: data.orderType,
|
|
220
|
+
customer: data.customer,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
log.info('Order created', {
|
|
226
|
+
fluentOrderId: result.data.createOrder.id,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
success: true,
|
|
231
|
+
orderId: data.orderId,
|
|
232
|
+
fluentOrderId: result.data.createOrder.id,
|
|
233
|
+
};
|
|
234
|
+
})
|
|
235
|
+
);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Example 2: Dual Connections (Incoming + Outgoing)
|
|
239
|
+
|
|
240
|
+
**Use Case:** Receive webhook (authenticate incoming), then call external API (authenticate outgoing).
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { webhook, http } from '@versori/run';
|
|
244
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Combined authentication pattern:
|
|
248
|
+
* 1. Incoming: Platform validates webhook caller (connection: 'inventory-webhook-auth')
|
|
249
|
+
* 2. Outgoing: Platform adds auth headers to external API (connection: 'external_api')
|
|
250
|
+
*
|
|
251
|
+
* Required connections:
|
|
252
|
+
* - 'inventory-webhook-auth': API Key for incoming requests
|
|
253
|
+
* - 'external_api': API Key for outgoing requests
|
|
254
|
+
* - 'fluent_commerce': OAuth2 for Fluent API
|
|
255
|
+
*/
|
|
256
|
+
export const inventoryValidation = webhook('inventory-validation', {
|
|
257
|
+
connection: 'inventory-webhook-auth', // ← Platform validates incoming request
|
|
258
|
+
response: { mode: 'sync' },
|
|
259
|
+
})
|
|
260
|
+
.then(
|
|
261
|
+
http(
|
|
262
|
+
'validate-external',
|
|
263
|
+
{
|
|
264
|
+
connection: 'external_api', // ← Platform adds auth headers to outgoing requests
|
|
265
|
+
},
|
|
266
|
+
async ctx => {
|
|
267
|
+
const { log, data } = ctx;
|
|
268
|
+
|
|
269
|
+
// ✅ Incoming authentication already validated by platform
|
|
270
|
+
|
|
271
|
+
log.info('Validating inventory with external system', {
|
|
272
|
+
sku: data.sku,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Call external API - auth headers automatically added by platform
|
|
276
|
+
const response = await ctx.fetch('https://api.external.com/validate', {
|
|
277
|
+
method: 'POST',
|
|
278
|
+
body: JSON.stringify({ sku: data.sku }),
|
|
279
|
+
headers: { 'Content-Type': 'application/json' },
|
|
280
|
+
// Auth headers automatically added by Versori
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const validation = await response.json();
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
step: 'validation',
|
|
287
|
+
sku: data.sku,
|
|
288
|
+
valid: validation.valid,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
)
|
|
293
|
+
.then(
|
|
294
|
+
http(
|
|
295
|
+
'update-fluent',
|
|
296
|
+
{
|
|
297
|
+
connection: 'fluent_commerce',
|
|
298
|
+
},
|
|
299
|
+
async ctx => {
|
|
300
|
+
const { log, data } = ctx;
|
|
301
|
+
|
|
302
|
+
// Update Fluent with validation result
|
|
303
|
+
const client = await createClient(ctx);
|
|
304
|
+
|
|
305
|
+
const mutation = `
|
|
306
|
+
mutation UpdateInventory($input: UpdateInventoryInput!) {
|
|
307
|
+
updateInventory(input: $input) {
|
|
308
|
+
id
|
|
309
|
+
ref
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
`;
|
|
313
|
+
|
|
314
|
+
await client.graphql({
|
|
315
|
+
query: mutation,
|
|
316
|
+
variables: {
|
|
317
|
+
input: {
|
|
318
|
+
ref: data.sku,
|
|
319
|
+
validated: data.valid,
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
log.info('Inventory updated in Fluent', {
|
|
325
|
+
sku: data.sku,
|
|
326
|
+
valid: data.valid,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
success: true,
|
|
331
|
+
sku: data.sku,
|
|
332
|
+
validated: data.valid,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Example 3: Real-World - Ad-Hoc Extraction Webhook
|
|
340
|
+
|
|
341
|
+
**Use Case:** Trigger on-demand data extraction via authenticated webhook.
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
import { webhook, http } from '@versori/run';
|
|
345
|
+
import { createClient, ExtractionOrchestrator } from '@fluentcommerce/fc-connect-sdk';
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Ad-hoc virtual positions extraction
|
|
349
|
+
*
|
|
350
|
+
* Triggered by external system with API key authentication.
|
|
351
|
+
* Extracts data from Fluent and returns results.
|
|
352
|
+
*
|
|
353
|
+
* Connection: 'extraction-webhook-auth'
|
|
354
|
+
* - Use a dedicated connection for extraction triggers with appropriate authentication
|
|
355
|
+
*/
|
|
356
|
+
export const adhocExtraction = webhook('adhoc-extraction', {
|
|
357
|
+
connection: 'extraction-webhook-auth', // ← Platform validates before execution
|
|
358
|
+
response: { mode: 'sync' },
|
|
359
|
+
}).then(
|
|
360
|
+
http('extract', { connection: 'fluent_commerce' }, async ctx => {
|
|
361
|
+
const { log, data, activation } = ctx;
|
|
362
|
+
|
|
363
|
+
// ✅ Authentication already validated by platform
|
|
364
|
+
// If we're here, the caller provided valid API key
|
|
365
|
+
|
|
366
|
+
log.info('Starting ad-hoc extraction', {
|
|
367
|
+
requestedBy: data.requestedBy,
|
|
368
|
+
filters: data.filters,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
const client = await createClient(ctx);
|
|
372
|
+
|
|
373
|
+
// Build query based on request parameters
|
|
374
|
+
const query = `
|
|
375
|
+
query GetVirtualPositions(
|
|
376
|
+
$first: Int,
|
|
377
|
+
$after: String,
|
|
378
|
+
$locationRef: [String!]
|
|
379
|
+
) {
|
|
380
|
+
virtualPositions(
|
|
381
|
+
first: $first,
|
|
382
|
+
after: $after,
|
|
383
|
+
locationRef: $locationRef
|
|
384
|
+
) {
|
|
385
|
+
edges {
|
|
386
|
+
node {
|
|
387
|
+
id
|
|
388
|
+
ref
|
|
389
|
+
productRef
|
|
390
|
+
quantity
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
pageInfo {
|
|
394
|
+
hasNextPage
|
|
395
|
+
endCursor
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
`;
|
|
400
|
+
|
|
401
|
+
// Use ExtractionOrchestrator for pagination
|
|
402
|
+
const orchestrator = new ExtractionOrchestrator(client, log);
|
|
403
|
+
|
|
404
|
+
const results = await orchestrator.extractWithPagination({
|
|
405
|
+
query,
|
|
406
|
+
variables: {
|
|
407
|
+
locationRef: data.filters?.locations || null,
|
|
408
|
+
},
|
|
409
|
+
dataPath: 'virtualPositions',
|
|
410
|
+
pageSize: 100,
|
|
411
|
+
maxPages: 50,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
log.info('Extraction completed', {
|
|
415
|
+
totalRecords: results.data.length,
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
success: true,
|
|
420
|
+
recordCount: results.data.length,
|
|
421
|
+
data: results.data,
|
|
422
|
+
metadata: {
|
|
423
|
+
requestedBy: data.requestedBy,
|
|
424
|
+
timestamp: new Date().toISOString(),
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
})
|
|
428
|
+
);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Testing
|
|
434
|
+
|
|
435
|
+
### Test with Valid API Key
|
|
436
|
+
|
|
437
|
+
**Expected: 200 OK, workflow executes:**
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
curl -X POST https://yourworkspace.versori.run/webhooks/secure-order \
|
|
441
|
+
-H "X-API-Key: 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f" \
|
|
442
|
+
-H "Content-Type: application/json" \
|
|
443
|
+
-d '{
|
|
444
|
+
"orderId": "ORD-123",
|
|
445
|
+
"orderType": "STANDARD",
|
|
446
|
+
"customer": { "email": "test@example.com" }
|
|
447
|
+
}'
|
|
448
|
+
|
|
449
|
+
# Response:
|
|
450
|
+
# HTTP/1.1 200 OK
|
|
451
|
+
# {
|
|
452
|
+
# "success": true,
|
|
453
|
+
# "orderId": "ORD-123",
|
|
454
|
+
# "fluentOrderId": "123456"
|
|
455
|
+
# }
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Test with Missing API Key
|
|
459
|
+
|
|
460
|
+
**Expected: 401 Unauthorized, code never runs:**
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
curl -X POST https://yourworkspace.versori.run/webhooks/secure-order \
|
|
464
|
+
-H "Content-Type: application/json" \
|
|
465
|
+
-d '{
|
|
466
|
+
"orderId": "ORD-123",
|
|
467
|
+
"orderType": "STANDARD"
|
|
468
|
+
}'
|
|
469
|
+
|
|
470
|
+
# Response:
|
|
471
|
+
# HTTP/1.1 401 Unauthorized
|
|
472
|
+
# {
|
|
473
|
+
# "error": "Missing authentication",
|
|
474
|
+
# "message": "X-API-Key header required"
|
|
475
|
+
# }
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Test with Invalid API Key
|
|
479
|
+
|
|
480
|
+
**Expected: 401 Unauthorized, code never runs:**
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
curl -X POST https://yourworkspace.versori.run/webhooks/secure-order \
|
|
484
|
+
-H "X-API-Key: wrong-key-12345" \
|
|
485
|
+
-H "Content-Type: application/json" \
|
|
486
|
+
-d '{
|
|
487
|
+
"orderId": "ORD-123",
|
|
488
|
+
"orderType": "STANDARD"
|
|
489
|
+
}'
|
|
490
|
+
|
|
491
|
+
# Response:
|
|
492
|
+
# HTTP/1.1 401 Unauthorized
|
|
493
|
+
# {
|
|
494
|
+
# "error": "Invalid authentication",
|
|
495
|
+
# "message": "API key validation failed"
|
|
496
|
+
# }
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Test Outgoing API Call
|
|
500
|
+
|
|
501
|
+
**Verify platform adds auth headers automatically:**
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
export const debugConnection = http(
|
|
505
|
+
'debug',
|
|
506
|
+
{
|
|
507
|
+
connection: 'external_api',
|
|
508
|
+
},
|
|
509
|
+
async ctx => {
|
|
510
|
+
const { log } = ctx;
|
|
511
|
+
|
|
512
|
+
// Log connection details (never log actual keys!)
|
|
513
|
+
const conn = ctx.activation?.connection;
|
|
514
|
+
log.info('Connection loaded', {
|
|
515
|
+
hasUrl: !!conn?.url,
|
|
516
|
+
hasHeaders: !!conn?.headers,
|
|
517
|
+
headerNames: Object.keys(conn?.headers || {}),
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// Test API call - auth headers automatically added
|
|
521
|
+
try {
|
|
522
|
+
const response = await ctx.fetch('https://api.external.com/health');
|
|
523
|
+
|
|
524
|
+
log.info('Connection test succeeded', {
|
|
525
|
+
status: response.status,
|
|
526
|
+
ok: response.ok,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
return { success: true, connected: true };
|
|
530
|
+
} catch (error) {
|
|
531
|
+
log.error('Connection test failed', { error: error.message });
|
|
532
|
+
return { success: false, error: error.message };
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
);
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## Best Practices
|
|
541
|
+
|
|
542
|
+
### 1. Use Strong, Random Keys
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
# ✅ CORRECT - 64 characters, cryptographically random
|
|
546
|
+
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
547
|
+
# Output: 7f3e9a2b1c8d6e4f5a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f
|
|
548
|
+
|
|
549
|
+
# ❌ WRONG - Short, predictable
|
|
550
|
+
X-API-Key: secret123
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### 2. One Connection Per Webhook/Purpose
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
// ✅ CORRECT - Separate connections for different purposes
|
|
557
|
+
export const orderWebhook = webhook('orders', {
|
|
558
|
+
connection: 'order-webhook-auth', // Orders connection
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
export const inventoryWebhook = webhook('inventory', {
|
|
562
|
+
connection: 'inventory-webhook-auth', // Inventory connection
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// ❌ WRONG - Shared key across different systems
|
|
566
|
+
export const orderWebhook = webhook('orders', {
|
|
567
|
+
connection: 'shared-webhook-auth', // Don't reuse!
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### 3. Rotate Keys Regularly
|
|
572
|
+
|
|
573
|
+
**Update in Versori Dashboard (no code changes needed):**
|
|
574
|
+
|
|
575
|
+
1. Generate new key: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
|
|
576
|
+
2. Update connection in Versori Dashboard
|
|
577
|
+
3. Distribute new key to callers
|
|
578
|
+
4. No code deployment required!
|
|
579
|
+
|
|
580
|
+
**Rotation Schedule:**
|
|
581
|
+
|
|
582
|
+
- Development: Every 90 days
|
|
583
|
+
- Staging: Every 60 days
|
|
584
|
+
- Production: Every 30 days
|
|
585
|
+
|
|
586
|
+
### 4. Document Connection Requirements
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
/**
|
|
590
|
+
* Secure Order Processing Webhook
|
|
591
|
+
*
|
|
592
|
+
* Required Connections:
|
|
593
|
+
* 1. 'order-webhook-auth' (API Key - Incoming)
|
|
594
|
+
* - Authentication is enforced by the Versori connection prior to code execution
|
|
595
|
+
*
|
|
596
|
+
* 2. 'fluent_commerce' (OAuth2 - Outgoing)
|
|
597
|
+
* - Type: OAuth2
|
|
598
|
+
* - Purpose: Authenticate requests to Fluent API
|
|
599
|
+
*
|
|
600
|
+
* Setup:
|
|
601
|
+
* 1. Create both connections in Versori Dashboard
|
|
602
|
+
* 2. Provide X-API-Key to webhook callers
|
|
603
|
+
* 3. Deploy webhook
|
|
604
|
+
*/
|
|
605
|
+
export const secureOrderWebhook = webhook('secure-order', {
|
|
606
|
+
connection: 'order-webhook-auth',
|
|
607
|
+
// ... rest of webhook
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### 5. Log Security Events (Safely)
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
export const secureWebhook = webhook('secure', {
|
|
615
|
+
connection: 'webhook-auth',
|
|
616
|
+
response: { mode: 'sync' },
|
|
617
|
+
}).then(
|
|
618
|
+
http('process', { connection: 'fluent' }, async ctx => {
|
|
619
|
+
const { log, data, request } = ctx;
|
|
620
|
+
|
|
621
|
+
// ✅ CORRECT - Log without exposing keys
|
|
622
|
+
const req = request();
|
|
623
|
+
log.info('Authenticated request received', {
|
|
624
|
+
endpoint: req.url,
|
|
625
|
+
method: req.method,
|
|
626
|
+
hasApiKey: !!req.headers.get('x-api-key'),
|
|
627
|
+
keyPrefix: req.headers.get('x-api-key')?.substring(0, 8) + '...',
|
|
628
|
+
ipAddress: req.headers.get('x-forwarded-for'),
|
|
629
|
+
timestamp: new Date().toISOString(),
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// ❌ WRONG - Exposes full API key
|
|
633
|
+
log.info('Request', {
|
|
634
|
+
apiKey: req.headers.get('x-api-key'), // NEVER log full keys!
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
// Process request...
|
|
638
|
+
})
|
|
639
|
+
);
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### 6. Use Descriptive Connection Names
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
// ✅ CORRECT - Clear purpose
|
|
646
|
+
connection: 'order-webhook-auth';
|
|
647
|
+
connection: 'inventory-extraction-trigger';
|
|
648
|
+
connection: 'shopify-order-sync-webhook';
|
|
649
|
+
|
|
650
|
+
// ❌ WRONG - Vague names
|
|
651
|
+
connection: 'webhook1';
|
|
652
|
+
connection: 'api-key';
|
|
653
|
+
connection: 'auth';
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
## Troubleshooting
|
|
659
|
+
|
|
660
|
+
### Issue: 401 Unauthorized (Valid Key)
|
|
661
|
+
|
|
662
|
+
**Symptoms:**
|
|
663
|
+
|
|
664
|
+
- You're providing the correct API key
|
|
665
|
+
- Still getting 401 Unauthorized
|
|
666
|
+
- Code never executes
|
|
667
|
+
|
|
668
|
+
**Possible Causes:**
|
|
669
|
+
|
|
670
|
+
1. **Header name mismatch:**
|
|
671
|
+
|
|
672
|
+
```bash
|
|
673
|
+
# Check connection config - must match exactly
|
|
674
|
+
Connection: X-API-Key (configured)
|
|
675
|
+
Request: x-api-key (sent) # ❌ Case-sensitive!
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
2. **Whitespace in key:**
|
|
679
|
+
|
|
680
|
+
```bash
|
|
681
|
+
# ❌ WRONG - Extra space
|
|
682
|
+
curl -H "X-API-Key: abc123 "
|
|
683
|
+
|
|
684
|
+
# ✅ CORRECT - No whitespace
|
|
685
|
+
curl -H "X-API-Key: abc123"
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
3. **Wrong connection name:**
|
|
689
|
+
|
|
690
|
+
```typescript
|
|
691
|
+
// Webhook references: 'order-webhook-auth'
|
|
692
|
+
webhook('orders', { connection: 'order-webhook-auth' });
|
|
693
|
+
|
|
694
|
+
// But connection in UI is named: 'order-webhook' ❌
|
|
695
|
+
// Fix: Match names exactly!
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Issue: Connection Not Found
|
|
699
|
+
|
|
700
|
+
**Symptoms:**
|
|
701
|
+
|
|
702
|
+
- Error: "Connection not found"
|
|
703
|
+
- Webhook fails to start
|
|
704
|
+
|
|
705
|
+
**Solution:**
|
|
706
|
+
|
|
707
|
+
1. Verify connection exists in Versori Dashboard
|
|
708
|
+
2. Check connection name matches exactly (case-sensitive)
|
|
709
|
+
3. Ensure connection is saved and active
|
|
710
|
+
|
|
711
|
+
### Issue: Auth Headers Not Added (Outgoing)
|
|
712
|
+
|
|
713
|
+
**Symptoms:**
|
|
714
|
+
|
|
715
|
+
- External API returns 401
|
|
716
|
+
- Auth headers missing from request
|
|
717
|
+
- Outgoing API call fails
|
|
718
|
+
|
|
719
|
+
**Solution:**
|
|
720
|
+
|
|
721
|
+
1. Verify `connection` parameter specified in `http()` options:
|
|
722
|
+
|
|
723
|
+
```typescript
|
|
724
|
+
// ✅ CORRECT
|
|
725
|
+
.then(http('call-api', { connection: 'external_api' }, async (ctx) => {
|
|
726
|
+
await ctx.fetch('https://api.external.com/data');
|
|
727
|
+
}))
|
|
728
|
+
|
|
729
|
+
// ❌ WRONG - Missing connection
|
|
730
|
+
.then(http('call-api', async (ctx) => {
|
|
731
|
+
await ctx.fetch('https://api.external.com/data');
|
|
732
|
+
}))
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
2. Check connection configuration in Versori Dashboard
|
|
736
|
+
3. Verify connection type matches API requirements
|
|
737
|
+
|
|
738
|
+
### Issue: Need Different Keys Per Environment
|
|
739
|
+
|
|
740
|
+
**Solution:** Use environment-specific connections:
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
// Development environment
|
|
744
|
+
webhook('orders-dev', { connection: 'order-webhook-auth-dev' });
|
|
745
|
+
|
|
746
|
+
// Production environment
|
|
747
|
+
webhook('orders-prod', { connection: 'order-webhook-auth-prod' });
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
Configure different keys in Versori Dashboard for each environment.
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## Summary
|
|
755
|
+
|
|
756
|
+
### Key Takeaways
|
|
757
|
+
|
|
758
|
+
**Connection-Based Authentication (Recommended):**
|
|
759
|
+
|
|
760
|
+
- ✅ Zero validation code required
|
|
761
|
+
- ✅ Platform validates before code runs
|
|
762
|
+
- ✅ Configure once in Versori Dashboard
|
|
763
|
+
- ✅ Reference by name: `{ connection: 'webhook-auth' }`
|
|
764
|
+
- ✅ Works for incoming AND outgoing requests
|
|
765
|
+
- ✅ Rotate keys in UI without code changes
|
|
766
|
+
- ✅ Automatic 401 rejection for invalid requests
|
|
767
|
+
|
|
768
|
+
**The Magic Line:**
|
|
769
|
+
|
|
770
|
+
```typescript
|
|
771
|
+
webhook('my-webhook', {
|
|
772
|
+
connection: 'webhook-auth', // ← This ONE line enables platform validation
|
|
773
|
+
});
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
### Quick Decision Guide
|
|
777
|
+
|
|
778
|
+
| Scenario | Pattern | Code Required |
|
|
779
|
+
| ------------------------------- | ----------------------- | ------------- |
|
|
780
|
+
| **Incoming webhook needs auth** | Connection-based | Zero |
|
|
781
|
+
| **Webhook calls external API** | Connection-based | Zero |
|
|
782
|
+
| **Both incoming + outgoing** | Connection-based (both) | Zero |
|
|
783
|
+
| **Custom auth algorithm** | Manual validation | Moderate |
|
|
784
|
+
|
|
785
|
+
### Setup Checklist
|
|
786
|
+
|
|
787
|
+
- [ ] Generate strong API key (64+ characters)
|
|
788
|
+
- [ ] Create connection in Versori Dashboard
|
|
789
|
+
- [ ] Configure API Key type and header name
|
|
790
|
+
- [ ] Add connection to webhook definition
|
|
791
|
+
- [ ] Distribute key to webhook callers
|
|
792
|
+
- [ ] Test with valid/invalid keys
|
|
793
|
+
- [ ] Document connection requirements
|
|
794
|
+
- [ ] Set up key rotation schedule
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
## Related Documentation
|
|
799
|
+
|
|
800
|
+
- [Module 5: Connection Management](./modules/platforms-versori-05-connections.md) - Detailed connection configuration
|
|
801
|
+
- [Webhook Validation Guide](../../../02-CORE-GUIDES/webhook-validation/webhook-validation-readme.md) - Cryptographic signature validation (Fluent webhooks)
|
|
802
|
+
- [Module 3: Versori Integration](../../../02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md) - Combining API keys with signatures
|
|
803
|
+
- [KV State Management Pattern](../../../01-TEMPLATES/versori/patterns/kv-state-management.md) - Request deduplication
|
|
804
|
+
- [XML Response Patterns](../../../01-TEMPLATES/versori/patterns/xml-response-patterns.md) - Custom response formats
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
**Document Version:** 4.0 (Final - Connection-Based Only)
|
|
809
|
+
**Maintained By:** FC Connect SDK Team
|
|
810
|
+
|
|
811
|
+
**Changelog:**
|
|
812
|
+
|
|
813
|
+
- v4.0: **Cleanup** - Focused on connection-based patterns
|
|
814
|
+
- v3.0: Major rewrite - Documented connection-based pattern
|
|
815
|
+
- v2.0: Clarified use cases
|
|
816
|
+
- v1.0: Initial version
|