@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
- package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
|
@@ -1,835 +1,835 @@
|
|
|
1
|
-
# Versori: Complete Bidirectional Connector
|
|
2
|
-
|
|
3
|
-
**FC Connect SDK Use Case Guide**
|
|
4
|
-
|
|
5
|
-
> **SDK**: [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)
|
|
6
|
-
> **Version**: ^0.1.27 or later
|
|
7
|
-
>
|
|
8
|
-
> **Status**: ✅ VALIDATED - All Versori syntax verified for SDK ^0.1.27
|
|
9
|
-
|
|
10
|
-
**Context**: Build a complete Versori connector with multiple workflows (ingestion + extraction) and shared resolvers
|
|
11
|
-
|
|
12
|
-
**Complexity**: High
|
|
13
|
-
|
|
14
|
-
**Runtime**: Versori Platform
|
|
15
|
-
|
|
16
|
-
**Estimated Lines**: ~800 lines
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Validation Summary
|
|
21
|
-
|
|
22
|
-
This document has been comprehensively validated for correct Versori Platform syntax:
|
|
23
|
-
|
|
24
|
-
### Fixed Issues (SDK ^0.1.27)
|
|
25
|
-
- ✅ **Schedule syntax**: Changed to string cron expression (was object)
|
|
26
|
-
- ✅ **SDK version**: Updated from ^0.1.19 to ^0.1.27
|
|
27
|
-
- ✅ **@versori/run**: Updated to "latest" (removed version pinning)
|
|
28
|
-
- ✅ **Buffer imports**: Added explicit imports for all examples
|
|
29
|
-
- ✅ **Webhook responses**: Correct onSuccess/onError pattern with Response objects
|
|
30
|
-
- ✅ **Auto-pagination**: Using `pagination` object (not `config`)
|
|
31
|
-
- ✅ **Logging patterns**: Native `ctx.log` (not LoggingService)
|
|
32
|
-
- ✅ **Client factory**: createClient() with context detection
|
|
33
|
-
|
|
34
|
-
### New Content Added
|
|
35
|
-
- ✅ Complete webhook workflow example with XML ingestion
|
|
36
|
-
- ✅ Complete scheduled workflow example with order extraction
|
|
37
|
-
- ✅ HTTP workflow example with manual triggers
|
|
38
|
-
- ✅ Comprehensive syntax validation section (7 critical rules)
|
|
39
|
-
- ✅ All examples use real FC Connect SDK patterns
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## What You'll Build
|
|
44
|
-
|
|
45
|
-
- Bidirectional connector (SFCC ↔ Fluent)
|
|
46
|
-
- Multiple Versori workflows (ingestion and extraction)
|
|
47
|
-
- Shared resolver library for data transformation
|
|
48
|
-
- Proper index.ts export structure
|
|
49
|
-
- Package.json configuration for Versori
|
|
50
|
-
- Mapping configurations (XML → GraphQL and GraphQL → XML)
|
|
51
|
-
- Testing utilities
|
|
52
|
-
|
|
53
|
-
## SDK Methods Used
|
|
54
|
-
|
|
55
|
-
- `createClient()` - Universal client factory with context detection
|
|
56
|
-
- `GraphQLMutationMapper` - XML/JSON → GraphQL mutation transformation
|
|
57
|
-
- `UniversalMapper` - GraphQL → XML/JSON transformation
|
|
58
|
-
- `XMLParserService` - XML parsing with attribute support
|
|
59
|
-
- `XMLBuilder` - XML serialization with proper formatting
|
|
60
|
-
- Custom resolvers - Domain-specific transformation logic
|
|
61
|
-
- `helpers.get()` - Safe path navigation in data structures
|
|
62
|
-
- `helpers.fluentClient` - Access Fluent API from resolvers
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Versori Workflows Structure
|
|
67
|
-
|
|
68
|
-
**Key Concept**: Versori workflows are organized by **trigger type** at the first level, then by **specific workflow** with descriptive file names.
|
|
69
|
-
|
|
70
|
-
**Trigger Types:**
|
|
71
|
-
- **`webhook()`** → HTTP-based triggers (event-driven) - Creates HTTP endpoints
|
|
72
|
-
- **`schedule()`** → Time-based triggers (cron expressions) - NOT exposed as HTTP endpoints
|
|
73
|
-
- **`http()`** → External API calls (chained from webhook/schedule)
|
|
74
|
-
- **`fn()`** → Internal processing (chained from webhook/schedule)
|
|
75
|
-
|
|
76
|
-
### Recommended Project Structure
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
dual-workflow-connector/
|
|
80
|
-
├── index.ts # Entry point - exports all workflows
|
|
81
|
-
└── src/
|
|
82
|
-
├── workflows/
|
|
83
|
-
│ ├── webhook/
|
|
84
|
-
│ │ └── order-ingestion.ts # Webhook: Receive orders
|
|
85
|
-
│ │
|
|
86
|
-
│ └── scheduled/
|
|
87
|
-
│ └── order-extraction.ts # Scheduled: Extract orders
|
|
88
|
-
│
|
|
89
|
-
├── services/
|
|
90
|
-
│ └── order-processing.service.ts # Shared orchestration logic (reusable)
|
|
91
|
-
│
|
|
92
|
-
└── config/
|
|
93
|
-
└── order-mapping.json # Mapping configuration
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**Benefits:**
|
|
97
|
-
- ✅ Clear trigger separation (`webhook/` vs `scheduled/`)
|
|
98
|
-
- ✅ Descriptive file names (easy to browse and understand)
|
|
99
|
-
- ✅ Scalable (add new workflows without cluttering)
|
|
100
|
-
- ✅ Reusable code in `services/` (DRY principle)
|
|
101
|
-
- ✅ Easy to modify individual workflows without affecting others
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Complete Working Code
|
|
106
|
-
|
|
107
|
-
**Note**: This is a comprehensive pattern document. For the complete implementation with detailed code examples, please refer to:
|
|
108
|
-
|
|
109
|
-
- **Full Implementation**: See `connectors/versori-sfcc-connector/` directory
|
|
110
|
-
- **Mapping Examples**: `connectors/versori-sfcc-connector/mappings/`
|
|
111
|
-
- **Resolver Patterns**: `connectors/versori-sfcc-connector/src/resolvers/`
|
|
112
|
-
- **Testing Scripts**: `connectors/versori-sfcc-connector/test-local-e2e.ts`
|
|
113
|
-
|
|
114
|
-
## Key Architecture Patterns
|
|
115
|
-
|
|
116
|
-
### 1. Package.json Structure
|
|
117
|
-
|
|
118
|
-
Configure multiple workflows in a single connector:
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"name": "versori-sfcc-fluent-connector",
|
|
123
|
-
"version": "1.0.0",
|
|
124
|
-
"versori": {
|
|
125
|
-
"workflows": {
|
|
126
|
-
"sfcc-to-fluent-order-create": "./workflows/sfcc-to-fluent-order-create.ts",
|
|
127
|
-
"fluent-to-sfcc-order-detail": "./workflows/fluent-to-sfcc-order-detail.ts"
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
"dependencies": {
|
|
131
|
-
"@fluentcommerce/fc-connect-sdk": "^0.1.39",
|
|
132
|
-
"@versori/run": "latest"
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 2. Index.ts - Workflow Exports
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
/**
|
|
141
|
-
* Entry point - Export all workflows for Versori platform
|
|
142
|
-
*
|
|
143
|
-
* MemoryInterpreter Pattern:
|
|
144
|
-
* Each workflow uses schedule().then(http()) to ensure proper
|
|
145
|
-
* memory allocation and connection handling in Versori runtime.
|
|
146
|
-
*/
|
|
147
|
-
|
|
148
|
-
// Ingestion: SFCC → Fluent Commerce (Create Order)
|
|
149
|
-
export { sfccToFluentOrderCreate } from './workflows/webhook/order-ingestion';
|
|
150
|
-
|
|
151
|
-
// Extraction: Fluent Commerce → SFCC XML (Order Detail)
|
|
152
|
-
export { fluentToSfccOrderDetail } from './workflows/scheduled/order-extraction';
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### 3. Shared Resolvers Organization
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
// src/resolvers/index.ts
|
|
159
|
-
import { orderResolvers } from './order-resolvers';
|
|
160
|
-
import { itemResolvers } from './item-resolvers';
|
|
161
|
-
import { paymentResolvers } from './payment-resolvers';
|
|
162
|
-
import { extractionResolvers } from './extraction-resolvers';
|
|
163
|
-
|
|
164
|
-
export const allResolvers = {
|
|
165
|
-
...orderResolvers,
|
|
166
|
-
...itemResolvers,
|
|
167
|
-
...paymentResolvers,
|
|
168
|
-
...extractionResolvers,
|
|
169
|
-
};
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 4. Bidirectional Data Flow
|
|
173
|
-
|
|
174
|
-
**Ingestion Flow** (External System → Fluent):
|
|
175
|
-
|
|
176
|
-
```
|
|
177
|
-
XML/JSON Input → Parse → Named Nodes → GraphQLMutationMapper → Fluent API
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Extraction Flow** (Fluent → External System):
|
|
181
|
-
|
|
182
|
-
```
|
|
183
|
-
GraphQL Query → Fluent Data → UniversalMapper → XMLBuilder → XML Output
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
## Workflow Implementation Examples
|
|
187
|
-
|
|
188
|
-
### Webhook Workflow: XML Order Ingestion
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
// workflows/webhook/order-ingestion.ts
|
|
192
|
-
import { webhook } from '@versori/run';
|
|
193
|
-
import { createClient, GraphQLMutationMapper, XMLParserService } from '@fluentcommerce/fc-connect-sdk';
|
|
194
|
-
import { Buffer } from 'node:buffer';
|
|
195
|
-
import { allResolvers } from '../../src/resolvers';
|
|
196
|
-
import mappingConfig from '../../mappings/sfcc-to-fluent-order-mapping.json' with { type: 'json' };
|
|
197
|
-
|
|
198
|
-
export const sfccToFluentOrderCreate = webhook('sfcc-order-ingestion', {
|
|
199
|
-
response: {
|
|
200
|
-
mode: 'sync',
|
|
201
|
-
onSuccess: (ctx) => new Response(
|
|
202
|
-
`<Response><Status>SUCCESS</Status><OrderRef>${ctx.data.orderRef}</OrderRef></Response>`,
|
|
203
|
-
{
|
|
204
|
-
status: 200,
|
|
205
|
-
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
206
|
-
}
|
|
207
|
-
),
|
|
208
|
-
onError: (ctx) => new Response(
|
|
209
|
-
`<Response><Status>ERROR</Status><Message>${ctx.error?.message}</Message></Response>`,
|
|
210
|
-
{
|
|
211
|
-
status: 500,
|
|
212
|
-
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
213
|
-
}
|
|
214
|
-
),
|
|
215
|
-
},
|
|
216
|
-
}, async (ctx) => {
|
|
217
|
-
const { log, data } = ctx;
|
|
218
|
-
const startTime = Date.now();
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
log.info('📦 [OrderIngestion] Processing SFCC order XML webhook');
|
|
222
|
-
|
|
223
|
-
// 1. Parse XML payload
|
|
224
|
-
const parser = new XMLParserService(log);
|
|
225
|
-
const xmlContent = typeof data === 'string' ? data : Buffer.from(data).toString('utf-8');
|
|
226
|
-
const parsedOrder = await parser.parse(xmlContent);
|
|
227
|
-
|
|
228
|
-
log.info('✅ [OrderIngestion] Parsed order data', { orderRef: parsedOrder.order?.['@id'] });
|
|
229
|
-
|
|
230
|
-
// 2. Initialize Fluent client (auto-detects Versori context)
|
|
231
|
-
const client = await createClient(ctx);
|
|
232
|
-
|
|
233
|
-
// 3. Map XML → GraphQL mutation
|
|
234
|
-
const mapper = new GraphQLMutationMapper(
|
|
235
|
-
mappingConfig,
|
|
236
|
-
client,
|
|
237
|
-
log,
|
|
238
|
-
{ customResolvers: allResolvers }
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
const { mutation, variables } = await mapper.generateMutation(parsedOrder);
|
|
242
|
-
|
|
243
|
-
log.info('🔄 [OrderIngestion] Generated mutation for order', {
|
|
244
|
-
variables: JSON.stringify(variables)
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// 4. Execute mutation
|
|
248
|
-
const result = await client.graphql({ query: mutation, variables });
|
|
249
|
-
|
|
250
|
-
const duration = Date.now() - startTime;
|
|
251
|
-
log.info('✅ [OrderIngestion] Order created successfully', {
|
|
252
|
-
orderId: result.data.createOrder.id,
|
|
253
|
-
duration: `${duration}ms`
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
success: true,
|
|
258
|
-
orderRef: result.data.createOrder.ref,
|
|
259
|
-
orderId: result.data.createOrder.id,
|
|
260
|
-
createdAt: new Date().toISOString(),
|
|
261
|
-
duration,
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
} catch (error) {
|
|
265
|
-
const duration = Date.now() - startTime;
|
|
266
|
-
log.error('❌ [OrderIngestion] Order ingestion failed', {
|
|
267
|
-
error: error instanceof Error ? error.message : String(error),
|
|
268
|
-
errorType: error instanceof Error ? error.constructor.name : 'Error',
|
|
269
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
270
|
-
duration: `${duration}ms`,
|
|
271
|
-
recommendation: error.message?.includes('authentication') || error.message?.includes('401')
|
|
272
|
-
? 'Verify fluent_commerce connection and OAuth2 credentials in Connections section'
|
|
273
|
-
: error.message?.includes('mutation') || error.message?.includes('GraphQL')
|
|
274
|
-
? 'Check GraphQL mutation syntax and order payload structure'
|
|
275
|
-
: error.message?.includes('mapping') || error.message?.includes('field')
|
|
276
|
-
? 'Check mapping configuration and verify order data structure'
|
|
277
|
-
: error.message?.includes('connection') || error.message?.includes('timeout')
|
|
278
|
-
? 'Check network connectivity and Fluent Commerce API availability'
|
|
279
|
-
: 'Review error details and check order ingestion payload'
|
|
280
|
-
});
|
|
281
|
-
throw error;
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### Scheduled Workflow: Daily Order Extraction
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
// workflows/scheduled/order-extraction.ts
|
|
290
|
-
import { schedule, http } from '@versori/run';
|
|
291
|
-
import { createClient, UniversalMapper, SftpDataSource, JobTracker, XMLBuilder } from '@fluentcommerce/fc-connect-sdk';
|
|
292
|
-
import { Buffer } from 'node:buffer';
|
|
293
|
-
import { allResolvers } from '../../src/resolvers';
|
|
294
|
-
import extractionMapping from '../../mappings/fluent-to-sfcc-xml-mapping.json' with { type: 'json' };
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* MemoryInterpreter Pattern: schedule().then(http())
|
|
298
|
-
* This pattern ensures proper memory allocation in Versori runtime
|
|
299
|
-
*/
|
|
300
|
-
export const fluentToSfccOrderDetail = schedule('daily-order-extraction', '0 2 * * *').then(
|
|
301
|
-
http('run-order-extraction', { connection: 'fluent_commerce' }, async (ctx) => {
|
|
302
|
-
const { log, activation, openKv } = ctx;
|
|
303
|
-
const startTime = Date.now();
|
|
304
|
-
const jobId = `order-extraction-${Date.now()}`;
|
|
305
|
-
const tracker = new JobTracker(openKv(':project:'), log);
|
|
306
|
-
|
|
307
|
-
try {
|
|
308
|
-
log.info('🚀 [OrderExtraction] Starting daily order extraction workflow', { jobId });
|
|
309
|
-
|
|
310
|
-
await tracker.createJob(jobId, {
|
|
311
|
-
triggeredBy: 'schedule',
|
|
312
|
-
stage: 'initialization',
|
|
313
|
-
startTime,
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
// 1. Initialize Fluent client
|
|
317
|
-
const client = await createClient(ctx);
|
|
318
|
-
|
|
319
|
-
// Set retailerId if needed for certain operations
|
|
320
|
-
const retailerId = activation.getVariable('fluentRetailerId');
|
|
321
|
-
if (retailerId) {
|
|
322
|
-
client.setRetailerId(retailerId);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
log.info('✅ [OrderExtraction] Client initialized');
|
|
326
|
-
|
|
327
|
-
// 2. Query orders (with auto-pagination)
|
|
328
|
-
const query = `
|
|
329
|
-
query GetOrders($first: Int, $after: String) {
|
|
330
|
-
orders(first: $first, after: $after, createdOn: { from: "${getYesterday()}" }) {
|
|
331
|
-
edges {
|
|
332
|
-
node {
|
|
333
|
-
id
|
|
334
|
-
ref
|
|
335
|
-
type
|
|
336
|
-
status
|
|
337
|
-
totalPrice
|
|
338
|
-
totalTax
|
|
339
|
-
customer {
|
|
340
|
-
firstName
|
|
341
|
-
lastName
|
|
342
|
-
email
|
|
343
|
-
}
|
|
344
|
-
items {
|
|
345
|
-
edges {
|
|
346
|
-
node {
|
|
347
|
-
ref
|
|
348
|
-
quantity
|
|
349
|
-
price
|
|
350
|
-
totalPrice
|
|
351
|
-
productRef
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
cursor
|
|
357
|
-
}
|
|
358
|
-
pageInfo {
|
|
359
|
-
hasNextPage
|
|
360
|
-
endCursor
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
`;
|
|
365
|
-
|
|
366
|
-
await tracker.updateJob(jobId, { stage: 'querying', status: 'processing' });
|
|
367
|
-
|
|
368
|
-
const orders: any[] = [];
|
|
369
|
-
const result = await client.graphql({
|
|
370
|
-
query,
|
|
371
|
-
variables: { first: 100 },
|
|
372
|
-
pagination: { maxPages: 50 }
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
// Collect all orders
|
|
376
|
-
result.data.orders.edges.forEach(edge => orders.push(edge.node));
|
|
377
|
-
|
|
378
|
-
log.info(`📊 [OrderExtraction] Extracted ${orders.length} orders from Fluent`);
|
|
379
|
-
|
|
380
|
-
// 3. Transform orders to SFCC XML format
|
|
381
|
-
await tracker.updateJob(jobId, { stage: 'transforming' });
|
|
382
|
-
|
|
383
|
-
const mapper = new UniversalMapper(
|
|
384
|
-
extractionMapping,
|
|
385
|
-
{ customResolvers: allResolvers }
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
const xmlOrders = await Promise.all(
|
|
389
|
-
orders.map(async (order) => {
|
|
390
|
-
const mapped = await mapper.map(order);
|
|
391
|
-
return mapped.data;
|
|
392
|
-
})
|
|
393
|
-
);
|
|
394
|
-
|
|
395
|
-
log.info('🔄 [OrderExtraction] Mapped orders to SFCC format', { count: xmlOrders.length });
|
|
396
|
-
|
|
397
|
-
// 4. Build XML document
|
|
398
|
-
const xmlBuilder = new XMLBuilder({
|
|
399
|
-
ignoreAttributes: false,
|
|
400
|
-
attributeNamePrefix: '@',
|
|
401
|
-
format: true,
|
|
402
|
-
indentBy: ' ',
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
const xmlDocument = {
|
|
406
|
-
'?xml': { '@version': '1.0', '@encoding': 'UTF-8' },
|
|
407
|
-
OrderExport: {
|
|
408
|
-
'@xmlns': 'http://www.demandware.com/xml/impex/order/2006-10-31',
|
|
409
|
-
Order: xmlOrders,
|
|
410
|
-
},
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
const xmlContent = xmlBuilder.build(xmlDocument);
|
|
414
|
-
|
|
415
|
-
log.info('📝 [OrderExtraction] Built XML document', { size: xmlContent.length });
|
|
416
|
-
|
|
417
|
-
// 5. Upload to SFTP
|
|
418
|
-
await tracker.updateJob(jobId, { stage: 'uploading' });
|
|
419
|
-
|
|
420
|
-
const sftpConfig = {
|
|
421
|
-
type: 'SFTP_XML' as const,
|
|
422
|
-
connectionId: 'sftp-order-export',
|
|
423
|
-
name: 'order-export',
|
|
424
|
-
settings: {
|
|
425
|
-
host: activation.getVariable('sftpHost'),
|
|
426
|
-
port: parseInt(activation.getVariable('sftpPort') || '22', 10),
|
|
427
|
-
username: activation.getVariable('sftpUsername'),
|
|
428
|
-
password: activation.getVariable('sftpPassword'),
|
|
429
|
-
remotePath: '/outbound/orders/',
|
|
430
|
-
encoding: 'utf8' as const,
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
const sftp = new SftpDataSource(sftpConfig, log);
|
|
435
|
-
|
|
436
|
-
// Validate connection before proceeding
|
|
437
|
-
await sftp.validateConnection();
|
|
438
|
-
log.info('✅ [OrderExtraction] SFTP connection validated');
|
|
439
|
-
|
|
440
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
441
|
-
const filename = `/outbound/orders/order-export-${timestamp}.xml`;
|
|
442
|
-
|
|
443
|
-
await sftp.uploadFile(
|
|
444
|
-
'utf8',
|
|
445
|
-
Buffer.from(xmlContent, 'utf-8'),
|
|
446
|
-
filename
|
|
447
|
-
);
|
|
448
|
-
|
|
449
|
-
await sftp.dispose();
|
|
450
|
-
|
|
451
|
-
const duration = Date.now() - startTime;
|
|
452
|
-
log.info('✅ [OrderExtraction] Upload complete', {
|
|
453
|
-
filename,
|
|
454
|
-
orderCount: orders.length,
|
|
455
|
-
duration: `${duration}ms`
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
await tracker.markCompleted(jobId, {
|
|
459
|
-
orderCount: orders.length,
|
|
460
|
-
filename,
|
|
461
|
-
duration,
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
return {
|
|
465
|
-
success: true,
|
|
466
|
-
orderCount: orders.length,
|
|
467
|
-
filename,
|
|
468
|
-
timestamp,
|
|
469
|
-
duration,
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
} catch (error) {
|
|
473
|
-
const duration = Date.now() - startTime;
|
|
474
|
-
log.error('❌ [OrderExtraction] Order extraction failed', {
|
|
475
|
-
error: error instanceof Error ? error.message : String(error),
|
|
476
|
-
errorType: error instanceof Error ? error.constructor.name : 'Error',
|
|
477
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
478
|
-
duration: `${duration}ms`,
|
|
479
|
-
recommendation: error.message?.includes('authentication') || error.message?.includes('401')
|
|
480
|
-
? 'Verify fluent_commerce connection and OAuth2 credentials in Connections section'
|
|
481
|
-
: error.message?.includes('query') || error.message?.includes('GraphQL')
|
|
482
|
-
? 'Check GraphQL query syntax and extraction parameters'
|
|
483
|
-
: error.message?.includes('connection') || error.message?.includes('timeout')
|
|
484
|
-
? 'Check network connectivity and Fluent Commerce API availability'
|
|
485
|
-
: 'Review error details and check extraction workflow configuration'
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
await tracker.markFailed(jobId, error instanceof Error ? error.message : String(error));
|
|
489
|
-
throw error;
|
|
490
|
-
}
|
|
491
|
-
})
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
// Helper function
|
|
495
|
-
function getYesterday(): string {
|
|
496
|
-
const date = new Date();
|
|
497
|
-
date.setDate(date.getDate() - 1);
|
|
498
|
-
return date.toISOString();
|
|
499
|
-
}
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
### HTTP Workflow: Manual Trigger with Parameters
|
|
503
|
-
|
|
504
|
-
```typescript
|
|
505
|
-
// workflows/http/manual-order-sync.ts
|
|
506
|
-
import { http } from '@versori/run';
|
|
507
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
508
|
-
|
|
509
|
-
export const manualOrderSync = http(
|
|
510
|
-
'manual-order-sync',
|
|
511
|
-
{ connection: 'fluent_commerce' },
|
|
512
|
-
async (ctx) => {
|
|
513
|
-
const { log, activation } = ctx;
|
|
514
|
-
const startTime = Date.now();
|
|
515
|
-
|
|
516
|
-
// Parse query parameters from request
|
|
517
|
-
const url = new URL(ctx.request().url);
|
|
518
|
-
const orderRef = url.searchParams.get('orderRef');
|
|
519
|
-
const dateFrom = url.searchParams.get('dateFrom');
|
|
520
|
-
|
|
521
|
-
if (!orderRef && !dateFrom) {
|
|
522
|
-
return new Response(
|
|
523
|
-
JSON.stringify({ error: 'Missing required parameter: orderRef or dateFrom' }),
|
|
524
|
-
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
try {
|
|
529
|
-
log.info('🔄 [ManualSync] Manual sync triggered', { orderRef, dateFrom });
|
|
530
|
-
|
|
531
|
-
const client = await createClient(ctx);
|
|
532
|
-
|
|
533
|
-
// Set retailerId if needed
|
|
534
|
-
const retailerId = activation.getVariable('fluentRetailerId');
|
|
535
|
-
if (retailerId) {
|
|
536
|
-
client.setRetailerId(retailerId);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// Build dynamic query based on parameters
|
|
540
|
-
let filter = '';
|
|
541
|
-
if (orderRef) {
|
|
542
|
-
filter = `ref: "${orderRef}"`;
|
|
543
|
-
} else if (dateFrom) {
|
|
544
|
-
filter = `createdOn: { from: "${dateFrom}" }`;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
const query = `
|
|
548
|
-
query GetOrders {
|
|
549
|
-
orders(first: 100, ${filter}) {
|
|
550
|
-
edges {
|
|
551
|
-
node {
|
|
552
|
-
id
|
|
553
|
-
ref
|
|
554
|
-
status
|
|
555
|
-
totalPrice
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
`;
|
|
561
|
-
|
|
562
|
-
const result = await client.graphql({ query });
|
|
563
|
-
const orders = result.data.orders.edges.map(e => e.node);
|
|
564
|
-
|
|
565
|
-
const duration = Date.now() - startTime;
|
|
566
|
-
log.info('✅ [ManualSync] Orders retrieved', {
|
|
567
|
-
count: orders.length,
|
|
568
|
-
duration: `${duration}ms`
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
return {
|
|
572
|
-
success: true,
|
|
573
|
-
orderCount: orders.length,
|
|
574
|
-
orders: orders.map(o => ({ ref: o.ref, status: o.status })),
|
|
575
|
-
duration,
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
} catch (error) {
|
|
579
|
-
const duration = Date.now() - startTime;
|
|
580
|
-
log.error('❌ [ManualSync] Manual sync failed', {
|
|
581
|
-
error: error instanceof Error ? error.message : String(error),
|
|
582
|
-
errorType: error instanceof Error ? error.constructor.name : 'Error',
|
|
583
|
-
duration: `${duration}ms`,
|
|
584
|
-
recommendation: error.message?.includes('authentication') || error.message?.includes('401')
|
|
585
|
-
? 'Verify fluent_commerce connection and OAuth2 credentials in Connections section'
|
|
586
|
-
: error.message?.includes('query') || error.message?.includes('GraphQL')
|
|
587
|
-
? 'Check GraphQL query syntax and query parameters'
|
|
588
|
-
: error.message?.includes('connection') || error.message?.includes('timeout')
|
|
589
|
-
? 'Check network connectivity and Fluent Commerce API availability'
|
|
590
|
-
: 'Review error details and check manual sync parameters'
|
|
591
|
-
});
|
|
592
|
-
return {
|
|
593
|
-
success: false,
|
|
594
|
-
error: error.message,
|
|
595
|
-
duration,
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
);
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
## Project Structure
|
|
603
|
-
|
|
604
|
-
```
|
|
605
|
-
versori-sfcc-connector/
|
|
606
|
-
├── package.json
|
|
607
|
-
├── index.ts
|
|
608
|
-
├── tsconfig.json
|
|
609
|
-
├── workflows/
|
|
610
|
-
│ ├── sfcc-to-fluent-order-create.ts
|
|
611
|
-
│ └── fluent-to-sfcc-order-detail.ts
|
|
612
|
-
├── src/
|
|
613
|
-
│ └── resolvers/
|
|
614
|
-
│ ├── index.ts
|
|
615
|
-
│ ├── types.ts
|
|
616
|
-
│ ├── order-resolvers.ts
|
|
617
|
-
│ ├── item-resolvers.ts
|
|
618
|
-
│ ├── payment-resolvers.ts
|
|
619
|
-
│ └── extraction-resolvers.ts
|
|
620
|
-
├── mappings/
|
|
621
|
-
│ ├── sfcc-to-fluent-order-mapping.json
|
|
622
|
-
│ └── fluent-to-sfcc-xml-mapping.json
|
|
623
|
-
├── data/
|
|
624
|
-
│ └── sample-sfcc-order.xml
|
|
625
|
-
└── test-local-e2e.ts
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
## Versori Syntax Validation
|
|
629
|
-
|
|
630
|
-
### Critical Syntax Rules (SDK ^0.1.27)
|
|
631
|
-
|
|
632
|
-
#### 1. Schedule Cron Expression (String, NOT Object)
|
|
633
|
-
|
|
634
|
-
```typescript
|
|
635
|
-
// ✅ CORRECT: String cron expression
|
|
636
|
-
export default schedule(
|
|
637
|
-
'workflow-name',
|
|
638
|
-
'0 2 * * *', // String cron expression
|
|
639
|
-
{ connection: 'fluent_commerce' },
|
|
640
|
-
async (ctx) => { /* ... */ }
|
|
641
|
-
);
|
|
642
|
-
|
|
643
|
-
// ❌ WRONG: Object cron expression (not supported)
|
|
644
|
-
export default schedule(
|
|
645
|
-
'workflow-name',
|
|
646
|
-
{ cron: '0 2 * * *' }, // Don't use object form
|
|
647
|
-
{ connection: 'fluent_commerce' },
|
|
648
|
-
async (ctx) => { /* ... */ }
|
|
649
|
-
);
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
**Supported Cron Formats:**
|
|
653
|
-
- `'0 2 * * *'` - Daily at 2 AM
|
|
654
|
-
- `'*/15 * * * *'` - Every 15 minutes
|
|
655
|
-
- `'0 */6 * * *'` - Every 6 hours
|
|
656
|
-
- `'0 0 * * 1'` - Weekly on Monday
|
|
657
|
-
- `'0 9 1 * *'` - Monthly on 1st at 9 AM
|
|
658
|
-
|
|
659
|
-
#### 2. Buffer Import (Required in Deno/Versori)
|
|
660
|
-
|
|
661
|
-
```typescript
|
|
662
|
-
// ✅ CORRECT: Explicit import
|
|
663
|
-
import { Buffer } from 'node:buffer';
|
|
664
|
-
|
|
665
|
-
// ❌ WRONG: Buffer is not global in Deno
|
|
666
|
-
const buffer = Buffer.from(data); // Error without import
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
#### 3. SDK Version Specification
|
|
670
|
-
|
|
671
|
-
```json
|
|
672
|
-
// ✅ CORRECT: Use caret for latest features
|
|
673
|
-
{
|
|
674
|
-
"dependencies": {
|
|
675
|
-
"@fluentcommerce/fc-connect-sdk": "^0.1.39",
|
|
676
|
-
"@versori/run": "latest"
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// ⚠️ OUTDATED: Old versions missing features
|
|
681
|
-
{
|
|
682
|
-
"dependencies": {
|
|
683
|
-
"@fluentcommerce/fc-connect-sdk": "^0.1.39",
|
|
684
|
-
"@versori/run": "latest" // Use specific version
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
```
|
|
688
|
-
|
|
689
|
-
#### 4. Webhook Response Patterns
|
|
690
|
-
|
|
691
|
-
```typescript
|
|
692
|
-
// ✅ CORRECT: Custom XML/HTML response
|
|
693
|
-
export default webhook('name', {
|
|
694
|
-
response: {
|
|
695
|
-
mode: 'sync',
|
|
696
|
-
onSuccess: (ctx) => new Response(
|
|
697
|
-
'<xml>...</xml>',
|
|
698
|
-
{
|
|
699
|
-
status: 200,
|
|
700
|
-
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
701
|
-
}
|
|
702
|
-
),
|
|
703
|
-
onError: (ctx) => new Response(
|
|
704
|
-
'<Error>...</Error>',
|
|
705
|
-
{
|
|
706
|
-
status: 500,
|
|
707
|
-
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
708
|
-
}
|
|
709
|
-
),
|
|
710
|
-
},
|
|
711
|
-
}, async (ctx) => {
|
|
712
|
-
// Return data object (used in onSuccess handler)
|
|
713
|
-
return { orderRef: '12345' };
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
// ❌ WRONG: Returning Response directly (ignores response config)
|
|
717
|
-
export default webhook('name', {}, async (ctx) => {
|
|
718
|
-
return new Response('<xml>...</xml>'); // Don't do this
|
|
719
|
-
});
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
#### 5. Logging Best Practices
|
|
723
|
-
|
|
724
|
-
```typescript
|
|
725
|
-
// ✅ CORRECT: Use native log from context
|
|
726
|
-
export default http('name', { connection: 'fluent' }, async (ctx) => {
|
|
727
|
-
const { log } = ctx;
|
|
728
|
-
|
|
729
|
-
log('Message', { metadata: 'value' });
|
|
730
|
-
log('Error occurred', { error: error.message, stack: error.stack });
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
// ❌ WRONG: Don't use console.log
|
|
734
|
-
export default http('name', { connection: 'fluent' }, async (ctx) => {
|
|
735
|
-
console.log('Message'); // Won't appear in Versori logs
|
|
736
|
-
});
|
|
737
|
-
|
|
738
|
-
// ❌ WRONG: Don't use LoggingService in Versori
|
|
739
|
-
import { LoggingService } from '@fluentcommerce/fc-connect-sdk';
|
|
740
|
-
const logger = new LoggingService(); // Unnecessary overhead
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
#### 6. Connection Access Patterns
|
|
744
|
-
|
|
745
|
-
```typescript
|
|
746
|
-
// ✅ CORRECT: Use createClient() for auto-detection
|
|
747
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
748
|
-
|
|
749
|
-
export default http('name', { connection: 'fluent_commerce' }, async (ctx) => {
|
|
750
|
-
const client = await createClient(ctx); // Auto-configures from connection
|
|
751
|
-
|
|
752
|
-
// Client is ready to use
|
|
753
|
-
const result = await client.graphql({ query, variables });
|
|
754
|
-
});
|
|
755
|
-
|
|
756
|
-
// ❌ WRONG: Manual FluentClient instantiation (misses Versori context)
|
|
757
|
-
import { FluentClient } from '@fluentcommerce/fc-connect-sdk';
|
|
758
|
-
|
|
759
|
-
export default http('name', { connection: 'fluent' }, async (ctx) => {
|
|
760
|
-
const client = new FluentClient({ /* manual config */ }); // Don't do this
|
|
761
|
-
});
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
#### 7. Auto-Pagination Syntax
|
|
765
|
-
|
|
766
|
-
```typescript
|
|
767
|
-
// ✅ CORRECT: pagination object (not config)
|
|
768
|
-
const result = await client.graphql({
|
|
769
|
-
query: myQuery,
|
|
770
|
-
variables: { first: 100 },
|
|
771
|
-
pagination: { // NOT 'config'
|
|
772
|
-
maxPages: 50,
|
|
773
|
-
pageSize: 100,
|
|
774
|
-
}
|
|
775
|
-
});
|
|
776
|
-
|
|
777
|
-
// ❌ WRONG: config object (old API)
|
|
778
|
-
const result = await client.graphql({
|
|
779
|
-
query: myQuery,
|
|
780
|
-
variables: { first: 100 },
|
|
781
|
-
config: { // Don't use 'config'
|
|
782
|
-
maxPages: 50
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
## Common Patterns
|
|
788
|
-
|
|
789
|
-
### Pattern 1: Multi-Workflow Index Structure
|
|
790
|
-
|
|
791
|
-
Use `package.json` versori.workflows configuration + clean index.ts exports for Versori workflow discovery.
|
|
792
|
-
|
|
793
|
-
### Pattern 2: Shared Resolvers Library
|
|
794
|
-
|
|
795
|
-
Organize resolvers by domain (order, item, payment, extraction) and export combined map for reuse across workflows.
|
|
796
|
-
|
|
797
|
-
### Pattern 3: Custom Response Handlers
|
|
798
|
-
|
|
799
|
-
For XML/HTML responses, use custom `onSuccess` and `onError` handlers that return `Response` objects.
|
|
800
|
-
|
|
801
|
-
### Pattern 4: Async Resolvers
|
|
802
|
-
|
|
803
|
-
Declare resolvers as `async` when querying Fluent API or external services within transformation logic.
|
|
804
|
-
|
|
805
|
-
### Pattern 5: Testing Multi-Workflow Connectors
|
|
806
|
-
|
|
807
|
-
Create local testing scripts that mock Versori activation, log, and connections for end-to-end validation.
|
|
808
|
-
|
|
809
|
-
## Related Guides
|
|
810
|
-
|
|
811
|
-
- **[Versori: Basic Ingestion Workflow](../workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md)**
|
|
812
|
-
- **[Versori: XML Processing](./xml-response-patterns.md)**
|
|
813
|
-
- **[Universal Mapping Guide](../../../02-CORE-GUIDES/advanced-services/advanced-services-readme.md)**
|
|
814
|
-
- **[GraphQL Mutation Mapper](../../../02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md)**
|
|
815
|
-
- **SFCC Connector**: `connectors/versori-sfcc-connector/` for complete reference implementation
|
|
816
|
-
|
|
817
|
-
## Next Steps
|
|
818
|
-
|
|
819
|
-
1. Review the complete SFCC connector implementation
|
|
820
|
-
2. Adapt mapping configurations for your use case
|
|
821
|
-
3. Implement domain-specific resolvers
|
|
822
|
-
4. Test workflows with sample data
|
|
823
|
-
5. Deploy to Versori platform
|
|
824
|
-
6. Monitor and iterate
|
|
825
|
-
|
|
826
|
-
## Production Checklist
|
|
827
|
-
|
|
828
|
-
- [ ] All workflows tested with real data
|
|
829
|
-
- [ ] Error handling covers all edge cases
|
|
830
|
-
- [ ] Logging includes sufficient detail for debugging
|
|
831
|
-
- [ ] Environment variables documented
|
|
832
|
-
- [ ] Resolver logic handles null/undefined values
|
|
833
|
-
- [ ] Package.json versori.workflows correctly configured
|
|
834
|
-
- [ ] TypeScript compilation succeeds with no errors
|
|
835
|
-
- [ ] All custom resolvers have JSDoc comments
|
|
1
|
+
# Versori: Complete Bidirectional Connector
|
|
2
|
+
|
|
3
|
+
**FC Connect SDK Use Case Guide**
|
|
4
|
+
|
|
5
|
+
> **SDK**: [@fluentcommerce/fc-connect-sdk](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)
|
|
6
|
+
> **Version**: ^0.1.27 or later
|
|
7
|
+
>
|
|
8
|
+
> **Status**: ✅ VALIDATED - All Versori syntax verified for SDK ^0.1.27
|
|
9
|
+
|
|
10
|
+
**Context**: Build a complete Versori connector with multiple workflows (ingestion + extraction) and shared resolvers
|
|
11
|
+
|
|
12
|
+
**Complexity**: High
|
|
13
|
+
|
|
14
|
+
**Runtime**: Versori Platform
|
|
15
|
+
|
|
16
|
+
**Estimated Lines**: ~800 lines
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Validation Summary
|
|
21
|
+
|
|
22
|
+
This document has been comprehensively validated for correct Versori Platform syntax:
|
|
23
|
+
|
|
24
|
+
### Fixed Issues (SDK ^0.1.27)
|
|
25
|
+
- ✅ **Schedule syntax**: Changed to string cron expression (was object)
|
|
26
|
+
- ✅ **SDK version**: Updated from ^0.1.19 to ^0.1.27
|
|
27
|
+
- ✅ **@versori/run**: Updated to "latest" (removed version pinning)
|
|
28
|
+
- ✅ **Buffer imports**: Added explicit imports for all examples
|
|
29
|
+
- ✅ **Webhook responses**: Correct onSuccess/onError pattern with Response objects
|
|
30
|
+
- ✅ **Auto-pagination**: Using `pagination` object (not `config`)
|
|
31
|
+
- ✅ **Logging patterns**: Native `ctx.log` (not LoggingService)
|
|
32
|
+
- ✅ **Client factory**: createClient() with context detection
|
|
33
|
+
|
|
34
|
+
### New Content Added
|
|
35
|
+
- ✅ Complete webhook workflow example with XML ingestion
|
|
36
|
+
- ✅ Complete scheduled workflow example with order extraction
|
|
37
|
+
- ✅ HTTP workflow example with manual triggers
|
|
38
|
+
- ✅ Comprehensive syntax validation section (7 critical rules)
|
|
39
|
+
- ✅ All examples use real FC Connect SDK patterns
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## What You'll Build
|
|
44
|
+
|
|
45
|
+
- Bidirectional connector (SFCC ↔ Fluent)
|
|
46
|
+
- Multiple Versori workflows (ingestion and extraction)
|
|
47
|
+
- Shared resolver library for data transformation
|
|
48
|
+
- Proper index.ts export structure
|
|
49
|
+
- Package.json configuration for Versori
|
|
50
|
+
- Mapping configurations (XML → GraphQL and GraphQL → XML)
|
|
51
|
+
- Testing utilities
|
|
52
|
+
|
|
53
|
+
## SDK Methods Used
|
|
54
|
+
|
|
55
|
+
- `createClient()` - Universal client factory with context detection
|
|
56
|
+
- `GraphQLMutationMapper` - XML/JSON → GraphQL mutation transformation
|
|
57
|
+
- `UniversalMapper` - GraphQL → XML/JSON transformation
|
|
58
|
+
- `XMLParserService` - XML parsing with attribute support
|
|
59
|
+
- `XMLBuilder` - XML serialization with proper formatting
|
|
60
|
+
- Custom resolvers - Domain-specific transformation logic
|
|
61
|
+
- `helpers.get()` - Safe path navigation in data structures
|
|
62
|
+
- `helpers.fluentClient` - Access Fluent API from resolvers
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Versori Workflows Structure
|
|
67
|
+
|
|
68
|
+
**Key Concept**: Versori workflows are organized by **trigger type** at the first level, then by **specific workflow** with descriptive file names.
|
|
69
|
+
|
|
70
|
+
**Trigger Types:**
|
|
71
|
+
- **`webhook()`** → HTTP-based triggers (event-driven) - Creates HTTP endpoints
|
|
72
|
+
- **`schedule()`** → Time-based triggers (cron expressions) - NOT exposed as HTTP endpoints
|
|
73
|
+
- **`http()`** → External API calls (chained from webhook/schedule)
|
|
74
|
+
- **`fn()`** → Internal processing (chained from webhook/schedule)
|
|
75
|
+
|
|
76
|
+
### Recommended Project Structure
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
dual-workflow-connector/
|
|
80
|
+
├── index.ts # Entry point - exports all workflows
|
|
81
|
+
└── src/
|
|
82
|
+
├── workflows/
|
|
83
|
+
│ ├── webhook/
|
|
84
|
+
│ │ └── order-ingestion.ts # Webhook: Receive orders
|
|
85
|
+
│ │
|
|
86
|
+
│ └── scheduled/
|
|
87
|
+
│ └── order-extraction.ts # Scheduled: Extract orders
|
|
88
|
+
│
|
|
89
|
+
├── services/
|
|
90
|
+
│ └── order-processing.service.ts # Shared orchestration logic (reusable)
|
|
91
|
+
│
|
|
92
|
+
└── config/
|
|
93
|
+
└── order-mapping.json # Mapping configuration
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Benefits:**
|
|
97
|
+
- ✅ Clear trigger separation (`webhook/` vs `scheduled/`)
|
|
98
|
+
- ✅ Descriptive file names (easy to browse and understand)
|
|
99
|
+
- ✅ Scalable (add new workflows without cluttering)
|
|
100
|
+
- ✅ Reusable code in `services/` (DRY principle)
|
|
101
|
+
- ✅ Easy to modify individual workflows without affecting others
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Complete Working Code
|
|
106
|
+
|
|
107
|
+
**Note**: This is a comprehensive pattern document. For the complete implementation with detailed code examples, please refer to:
|
|
108
|
+
|
|
109
|
+
- **Full Implementation**: See `connectors/versori-sfcc-connector/` directory
|
|
110
|
+
- **Mapping Examples**: `connectors/versori-sfcc-connector/mappings/`
|
|
111
|
+
- **Resolver Patterns**: `connectors/versori-sfcc-connector/src/resolvers/`
|
|
112
|
+
- **Testing Scripts**: `connectors/versori-sfcc-connector/test-local-e2e.ts`
|
|
113
|
+
|
|
114
|
+
## Key Architecture Patterns
|
|
115
|
+
|
|
116
|
+
### 1. Package.json Structure
|
|
117
|
+
|
|
118
|
+
Configure multiple workflows in a single connector:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"name": "versori-sfcc-fluent-connector",
|
|
123
|
+
"version": "1.0.0",
|
|
124
|
+
"versori": {
|
|
125
|
+
"workflows": {
|
|
126
|
+
"sfcc-to-fluent-order-create": "./workflows/sfcc-to-fluent-order-create.ts",
|
|
127
|
+
"fluent-to-sfcc-order-detail": "./workflows/fluent-to-sfcc-order-detail.ts"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"dependencies": {
|
|
131
|
+
"@fluentcommerce/fc-connect-sdk": "^0.1.39",
|
|
132
|
+
"@versori/run": "latest"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 2. Index.ts - Workflow Exports
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
/**
|
|
141
|
+
* Entry point - Export all workflows for Versori platform
|
|
142
|
+
*
|
|
143
|
+
* MemoryInterpreter Pattern:
|
|
144
|
+
* Each workflow uses schedule().then(http()) to ensure proper
|
|
145
|
+
* memory allocation and connection handling in Versori runtime.
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
// Ingestion: SFCC → Fluent Commerce (Create Order)
|
|
149
|
+
export { sfccToFluentOrderCreate } from './workflows/webhook/order-ingestion';
|
|
150
|
+
|
|
151
|
+
// Extraction: Fluent Commerce → SFCC XML (Order Detail)
|
|
152
|
+
export { fluentToSfccOrderDetail } from './workflows/scheduled/order-extraction';
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 3. Shared Resolvers Organization
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// src/resolvers/index.ts
|
|
159
|
+
import { orderResolvers } from './order-resolvers';
|
|
160
|
+
import { itemResolvers } from './item-resolvers';
|
|
161
|
+
import { paymentResolvers } from './payment-resolvers';
|
|
162
|
+
import { extractionResolvers } from './extraction-resolvers';
|
|
163
|
+
|
|
164
|
+
export const allResolvers = {
|
|
165
|
+
...orderResolvers,
|
|
166
|
+
...itemResolvers,
|
|
167
|
+
...paymentResolvers,
|
|
168
|
+
...extractionResolvers,
|
|
169
|
+
};
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 4. Bidirectional Data Flow
|
|
173
|
+
|
|
174
|
+
**Ingestion Flow** (External System → Fluent):
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
XML/JSON Input → Parse → Named Nodes → GraphQLMutationMapper → Fluent API
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Extraction Flow** (Fluent → External System):
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
GraphQL Query → Fluent Data → UniversalMapper → XMLBuilder → XML Output
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Workflow Implementation Examples
|
|
187
|
+
|
|
188
|
+
### Webhook Workflow: XML Order Ingestion
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// workflows/webhook/order-ingestion.ts
|
|
192
|
+
import { webhook } from '@versori/run';
|
|
193
|
+
import { createClient, GraphQLMutationMapper, XMLParserService } from '@fluentcommerce/fc-connect-sdk';
|
|
194
|
+
import { Buffer } from 'node:buffer';
|
|
195
|
+
import { allResolvers } from '../../src/resolvers';
|
|
196
|
+
import mappingConfig from '../../mappings/sfcc-to-fluent-order-mapping.json' with { type: 'json' };
|
|
197
|
+
|
|
198
|
+
export const sfccToFluentOrderCreate = webhook('sfcc-order-ingestion', {
|
|
199
|
+
response: {
|
|
200
|
+
mode: 'sync',
|
|
201
|
+
onSuccess: (ctx) => new Response(
|
|
202
|
+
`<Response><Status>SUCCESS</Status><OrderRef>${ctx.data.orderRef}</OrderRef></Response>`,
|
|
203
|
+
{
|
|
204
|
+
status: 200,
|
|
205
|
+
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
onError: (ctx) => new Response(
|
|
209
|
+
`<Response><Status>ERROR</Status><Message>${ctx.error?.message}</Message></Response>`,
|
|
210
|
+
{
|
|
211
|
+
status: 500,
|
|
212
|
+
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
213
|
+
}
|
|
214
|
+
),
|
|
215
|
+
},
|
|
216
|
+
}, async (ctx) => {
|
|
217
|
+
const { log, data } = ctx;
|
|
218
|
+
const startTime = Date.now();
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
log.info('📦 [OrderIngestion] Processing SFCC order XML webhook');
|
|
222
|
+
|
|
223
|
+
// 1. Parse XML payload
|
|
224
|
+
const parser = new XMLParserService(log);
|
|
225
|
+
const xmlContent = typeof data === 'string' ? data : Buffer.from(data).toString('utf-8');
|
|
226
|
+
const parsedOrder = await parser.parse(xmlContent);
|
|
227
|
+
|
|
228
|
+
log.info('✅ [OrderIngestion] Parsed order data', { orderRef: parsedOrder.order?.['@id'] });
|
|
229
|
+
|
|
230
|
+
// 2. Initialize Fluent client (auto-detects Versori context)
|
|
231
|
+
const client = await createClient(ctx);
|
|
232
|
+
|
|
233
|
+
// 3. Map XML → GraphQL mutation
|
|
234
|
+
const mapper = new GraphQLMutationMapper(
|
|
235
|
+
mappingConfig,
|
|
236
|
+
client,
|
|
237
|
+
log,
|
|
238
|
+
{ customResolvers: allResolvers }
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const { mutation, variables } = await mapper.generateMutation(parsedOrder);
|
|
242
|
+
|
|
243
|
+
log.info('🔄 [OrderIngestion] Generated mutation for order', {
|
|
244
|
+
variables: JSON.stringify(variables)
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// 4. Execute mutation
|
|
248
|
+
const result = await client.graphql({ query: mutation, variables });
|
|
249
|
+
|
|
250
|
+
const duration = Date.now() - startTime;
|
|
251
|
+
log.info('✅ [OrderIngestion] Order created successfully', {
|
|
252
|
+
orderId: result.data.createOrder.id,
|
|
253
|
+
duration: `${duration}ms`
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
success: true,
|
|
258
|
+
orderRef: result.data.createOrder.ref,
|
|
259
|
+
orderId: result.data.createOrder.id,
|
|
260
|
+
createdAt: new Date().toISOString(),
|
|
261
|
+
duration,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
} catch (error) {
|
|
265
|
+
const duration = Date.now() - startTime;
|
|
266
|
+
log.error('❌ [OrderIngestion] Order ingestion failed', {
|
|
267
|
+
error: error instanceof Error ? error.message : String(error),
|
|
268
|
+
errorType: error instanceof Error ? error.constructor.name : 'Error',
|
|
269
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
270
|
+
duration: `${duration}ms`,
|
|
271
|
+
recommendation: error.message?.includes('authentication') || error.message?.includes('401')
|
|
272
|
+
? 'Verify fluent_commerce connection and OAuth2 credentials in Connections section'
|
|
273
|
+
: error.message?.includes('mutation') || error.message?.includes('GraphQL')
|
|
274
|
+
? 'Check GraphQL mutation syntax and order payload structure'
|
|
275
|
+
: error.message?.includes('mapping') || error.message?.includes('field')
|
|
276
|
+
? 'Check mapping configuration and verify order data structure'
|
|
277
|
+
: error.message?.includes('connection') || error.message?.includes('timeout')
|
|
278
|
+
? 'Check network connectivity and Fluent Commerce API availability'
|
|
279
|
+
: 'Review error details and check order ingestion payload'
|
|
280
|
+
});
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Scheduled Workflow: Daily Order Extraction
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
// workflows/scheduled/order-extraction.ts
|
|
290
|
+
import { schedule, http } from '@versori/run';
|
|
291
|
+
import { createClient, UniversalMapper, SftpDataSource, JobTracker, XMLBuilder } from '@fluentcommerce/fc-connect-sdk';
|
|
292
|
+
import { Buffer } from 'node:buffer';
|
|
293
|
+
import { allResolvers } from '../../src/resolvers';
|
|
294
|
+
import extractionMapping from '../../mappings/fluent-to-sfcc-xml-mapping.json' with { type: 'json' };
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* MemoryInterpreter Pattern: schedule().then(http())
|
|
298
|
+
* This pattern ensures proper memory allocation in Versori runtime
|
|
299
|
+
*/
|
|
300
|
+
export const fluentToSfccOrderDetail = schedule('daily-order-extraction', '0 2 * * *').then(
|
|
301
|
+
http('run-order-extraction', { connection: 'fluent_commerce' }, async (ctx) => {
|
|
302
|
+
const { log, activation, openKv } = ctx;
|
|
303
|
+
const startTime = Date.now();
|
|
304
|
+
const jobId = `order-extraction-${Date.now()}`;
|
|
305
|
+
const tracker = new JobTracker(openKv(':project:'), log);
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
log.info('🚀 [OrderExtraction] Starting daily order extraction workflow', { jobId });
|
|
309
|
+
|
|
310
|
+
await tracker.createJob(jobId, {
|
|
311
|
+
triggeredBy: 'schedule',
|
|
312
|
+
stage: 'initialization',
|
|
313
|
+
startTime,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// 1. Initialize Fluent client
|
|
317
|
+
const client = await createClient(ctx);
|
|
318
|
+
|
|
319
|
+
// Set retailerId if needed for certain operations
|
|
320
|
+
const retailerId = activation.getVariable('fluentRetailerId');
|
|
321
|
+
if (retailerId) {
|
|
322
|
+
client.setRetailerId(retailerId);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
log.info('✅ [OrderExtraction] Client initialized');
|
|
326
|
+
|
|
327
|
+
// 2. Query orders (with auto-pagination)
|
|
328
|
+
const query = `
|
|
329
|
+
query GetOrders($first: Int, $after: String) {
|
|
330
|
+
orders(first: $first, after: $after, createdOn: { from: "${getYesterday()}" }) {
|
|
331
|
+
edges {
|
|
332
|
+
node {
|
|
333
|
+
id
|
|
334
|
+
ref
|
|
335
|
+
type
|
|
336
|
+
status
|
|
337
|
+
totalPrice
|
|
338
|
+
totalTax
|
|
339
|
+
customer {
|
|
340
|
+
firstName
|
|
341
|
+
lastName
|
|
342
|
+
email
|
|
343
|
+
}
|
|
344
|
+
items {
|
|
345
|
+
edges {
|
|
346
|
+
node {
|
|
347
|
+
ref
|
|
348
|
+
quantity
|
|
349
|
+
price
|
|
350
|
+
totalPrice
|
|
351
|
+
productRef
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
cursor
|
|
357
|
+
}
|
|
358
|
+
pageInfo {
|
|
359
|
+
hasNextPage
|
|
360
|
+
endCursor
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
`;
|
|
365
|
+
|
|
366
|
+
await tracker.updateJob(jobId, { stage: 'querying', status: 'processing' });
|
|
367
|
+
|
|
368
|
+
const orders: any[] = [];
|
|
369
|
+
const result = await client.graphql({
|
|
370
|
+
query,
|
|
371
|
+
variables: { first: 100 },
|
|
372
|
+
pagination: { maxPages: 50 }
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Collect all orders
|
|
376
|
+
result.data.orders.edges.forEach(edge => orders.push(edge.node));
|
|
377
|
+
|
|
378
|
+
log.info(`📊 [OrderExtraction] Extracted ${orders.length} orders from Fluent`);
|
|
379
|
+
|
|
380
|
+
// 3. Transform orders to SFCC XML format
|
|
381
|
+
await tracker.updateJob(jobId, { stage: 'transforming' });
|
|
382
|
+
|
|
383
|
+
const mapper = new UniversalMapper(
|
|
384
|
+
extractionMapping,
|
|
385
|
+
{ customResolvers: allResolvers }
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
const xmlOrders = await Promise.all(
|
|
389
|
+
orders.map(async (order) => {
|
|
390
|
+
const mapped = await mapper.map(order);
|
|
391
|
+
return mapped.data;
|
|
392
|
+
})
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
log.info('🔄 [OrderExtraction] Mapped orders to SFCC format', { count: xmlOrders.length });
|
|
396
|
+
|
|
397
|
+
// 4. Build XML document
|
|
398
|
+
const xmlBuilder = new XMLBuilder({
|
|
399
|
+
ignoreAttributes: false,
|
|
400
|
+
attributeNamePrefix: '@',
|
|
401
|
+
format: true,
|
|
402
|
+
indentBy: ' ',
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const xmlDocument = {
|
|
406
|
+
'?xml': { '@version': '1.0', '@encoding': 'UTF-8' },
|
|
407
|
+
OrderExport: {
|
|
408
|
+
'@xmlns': 'http://www.demandware.com/xml/impex/order/2006-10-31',
|
|
409
|
+
Order: xmlOrders,
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const xmlContent = xmlBuilder.build(xmlDocument);
|
|
414
|
+
|
|
415
|
+
log.info('📝 [OrderExtraction] Built XML document', { size: xmlContent.length });
|
|
416
|
+
|
|
417
|
+
// 5. Upload to SFTP
|
|
418
|
+
await tracker.updateJob(jobId, { stage: 'uploading' });
|
|
419
|
+
|
|
420
|
+
const sftpConfig = {
|
|
421
|
+
type: 'SFTP_XML' as const,
|
|
422
|
+
connectionId: 'sftp-order-export',
|
|
423
|
+
name: 'order-export',
|
|
424
|
+
settings: {
|
|
425
|
+
host: activation.getVariable('sftpHost'),
|
|
426
|
+
port: parseInt(activation.getVariable('sftpPort') || '22', 10),
|
|
427
|
+
username: activation.getVariable('sftpUsername'),
|
|
428
|
+
password: activation.getVariable('sftpPassword'),
|
|
429
|
+
remotePath: '/outbound/orders/',
|
|
430
|
+
encoding: 'utf8' as const,
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const sftp = new SftpDataSource(sftpConfig, log);
|
|
435
|
+
|
|
436
|
+
// Validate connection before proceeding
|
|
437
|
+
await sftp.validateConnection();
|
|
438
|
+
log.info('✅ [OrderExtraction] SFTP connection validated');
|
|
439
|
+
|
|
440
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
441
|
+
const filename = `/outbound/orders/order-export-${timestamp}.xml`;
|
|
442
|
+
|
|
443
|
+
await sftp.uploadFile(
|
|
444
|
+
'utf8',
|
|
445
|
+
Buffer.from(xmlContent, 'utf-8'),
|
|
446
|
+
filename
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
await sftp.dispose();
|
|
450
|
+
|
|
451
|
+
const duration = Date.now() - startTime;
|
|
452
|
+
log.info('✅ [OrderExtraction] Upload complete', {
|
|
453
|
+
filename,
|
|
454
|
+
orderCount: orders.length,
|
|
455
|
+
duration: `${duration}ms`
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
await tracker.markCompleted(jobId, {
|
|
459
|
+
orderCount: orders.length,
|
|
460
|
+
filename,
|
|
461
|
+
duration,
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
success: true,
|
|
466
|
+
orderCount: orders.length,
|
|
467
|
+
filename,
|
|
468
|
+
timestamp,
|
|
469
|
+
duration,
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
} catch (error) {
|
|
473
|
+
const duration = Date.now() - startTime;
|
|
474
|
+
log.error('❌ [OrderExtraction] Order extraction failed', {
|
|
475
|
+
error: error instanceof Error ? error.message : String(error),
|
|
476
|
+
errorType: error instanceof Error ? error.constructor.name : 'Error',
|
|
477
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
478
|
+
duration: `${duration}ms`,
|
|
479
|
+
recommendation: error.message?.includes('authentication') || error.message?.includes('401')
|
|
480
|
+
? 'Verify fluent_commerce connection and OAuth2 credentials in Connections section'
|
|
481
|
+
: error.message?.includes('query') || error.message?.includes('GraphQL')
|
|
482
|
+
? 'Check GraphQL query syntax and extraction parameters'
|
|
483
|
+
: error.message?.includes('connection') || error.message?.includes('timeout')
|
|
484
|
+
? 'Check network connectivity and Fluent Commerce API availability'
|
|
485
|
+
: 'Review error details and check extraction workflow configuration'
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
await tracker.markFailed(jobId, error instanceof Error ? error.message : String(error));
|
|
489
|
+
throw error;
|
|
490
|
+
}
|
|
491
|
+
})
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
// Helper function
|
|
495
|
+
function getYesterday(): string {
|
|
496
|
+
const date = new Date();
|
|
497
|
+
date.setDate(date.getDate() - 1);
|
|
498
|
+
return date.toISOString();
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### HTTP Workflow: Manual Trigger with Parameters
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
// workflows/http/manual-order-sync.ts
|
|
506
|
+
import { http } from '@versori/run';
|
|
507
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
508
|
+
|
|
509
|
+
export const manualOrderSync = http(
|
|
510
|
+
'manual-order-sync',
|
|
511
|
+
{ connection: 'fluent_commerce' },
|
|
512
|
+
async (ctx) => {
|
|
513
|
+
const { log, activation } = ctx;
|
|
514
|
+
const startTime = Date.now();
|
|
515
|
+
|
|
516
|
+
// Parse query parameters from request
|
|
517
|
+
const url = new URL(ctx.request().url);
|
|
518
|
+
const orderRef = url.searchParams.get('orderRef');
|
|
519
|
+
const dateFrom = url.searchParams.get('dateFrom');
|
|
520
|
+
|
|
521
|
+
if (!orderRef && !dateFrom) {
|
|
522
|
+
return new Response(
|
|
523
|
+
JSON.stringify({ error: 'Missing required parameter: orderRef or dateFrom' }),
|
|
524
|
+
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
try {
|
|
529
|
+
log.info('🔄 [ManualSync] Manual sync triggered', { orderRef, dateFrom });
|
|
530
|
+
|
|
531
|
+
const client = await createClient(ctx);
|
|
532
|
+
|
|
533
|
+
// Set retailerId if needed
|
|
534
|
+
const retailerId = activation.getVariable('fluentRetailerId');
|
|
535
|
+
if (retailerId) {
|
|
536
|
+
client.setRetailerId(retailerId);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Build dynamic query based on parameters
|
|
540
|
+
let filter = '';
|
|
541
|
+
if (orderRef) {
|
|
542
|
+
filter = `ref: "${orderRef}"`;
|
|
543
|
+
} else if (dateFrom) {
|
|
544
|
+
filter = `createdOn: { from: "${dateFrom}" }`;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const query = `
|
|
548
|
+
query GetOrders {
|
|
549
|
+
orders(first: 100, ${filter}) {
|
|
550
|
+
edges {
|
|
551
|
+
node {
|
|
552
|
+
id
|
|
553
|
+
ref
|
|
554
|
+
status
|
|
555
|
+
totalPrice
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
`;
|
|
561
|
+
|
|
562
|
+
const result = await client.graphql({ query });
|
|
563
|
+
const orders = result.data.orders.edges.map(e => e.node);
|
|
564
|
+
|
|
565
|
+
const duration = Date.now() - startTime;
|
|
566
|
+
log.info('✅ [ManualSync] Orders retrieved', {
|
|
567
|
+
count: orders.length,
|
|
568
|
+
duration: `${duration}ms`
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
return {
|
|
572
|
+
success: true,
|
|
573
|
+
orderCount: orders.length,
|
|
574
|
+
orders: orders.map(o => ({ ref: o.ref, status: o.status })),
|
|
575
|
+
duration,
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
} catch (error) {
|
|
579
|
+
const duration = Date.now() - startTime;
|
|
580
|
+
log.error('❌ [ManualSync] Manual sync failed', {
|
|
581
|
+
error: error instanceof Error ? error.message : String(error),
|
|
582
|
+
errorType: error instanceof Error ? error.constructor.name : 'Error',
|
|
583
|
+
duration: `${duration}ms`,
|
|
584
|
+
recommendation: error.message?.includes('authentication') || error.message?.includes('401')
|
|
585
|
+
? 'Verify fluent_commerce connection and OAuth2 credentials in Connections section'
|
|
586
|
+
: error.message?.includes('query') || error.message?.includes('GraphQL')
|
|
587
|
+
? 'Check GraphQL query syntax and query parameters'
|
|
588
|
+
: error.message?.includes('connection') || error.message?.includes('timeout')
|
|
589
|
+
? 'Check network connectivity and Fluent Commerce API availability'
|
|
590
|
+
: 'Review error details and check manual sync parameters'
|
|
591
|
+
});
|
|
592
|
+
return {
|
|
593
|
+
success: false,
|
|
594
|
+
error: error.message,
|
|
595
|
+
duration,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## Project Structure
|
|
603
|
+
|
|
604
|
+
```
|
|
605
|
+
versori-sfcc-connector/
|
|
606
|
+
├── package.json
|
|
607
|
+
├── index.ts
|
|
608
|
+
├── tsconfig.json
|
|
609
|
+
├── workflows/
|
|
610
|
+
│ ├── sfcc-to-fluent-order-create.ts
|
|
611
|
+
│ └── fluent-to-sfcc-order-detail.ts
|
|
612
|
+
├── src/
|
|
613
|
+
│ └── resolvers/
|
|
614
|
+
│ ├── index.ts
|
|
615
|
+
│ ├── types.ts
|
|
616
|
+
│ ├── order-resolvers.ts
|
|
617
|
+
│ ├── item-resolvers.ts
|
|
618
|
+
│ ├── payment-resolvers.ts
|
|
619
|
+
│ └── extraction-resolvers.ts
|
|
620
|
+
├── mappings/
|
|
621
|
+
│ ├── sfcc-to-fluent-order-mapping.json
|
|
622
|
+
│ └── fluent-to-sfcc-xml-mapping.json
|
|
623
|
+
├── data/
|
|
624
|
+
│ └── sample-sfcc-order.xml
|
|
625
|
+
└── test-local-e2e.ts
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
## Versori Syntax Validation
|
|
629
|
+
|
|
630
|
+
### Critical Syntax Rules (SDK ^0.1.27)
|
|
631
|
+
|
|
632
|
+
#### 1. Schedule Cron Expression (String, NOT Object)
|
|
633
|
+
|
|
634
|
+
```typescript
|
|
635
|
+
// ✅ CORRECT: String cron expression
|
|
636
|
+
export default schedule(
|
|
637
|
+
'workflow-name',
|
|
638
|
+
'0 2 * * *', // String cron expression
|
|
639
|
+
{ connection: 'fluent_commerce' },
|
|
640
|
+
async (ctx) => { /* ... */ }
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
// ❌ WRONG: Object cron expression (not supported)
|
|
644
|
+
export default schedule(
|
|
645
|
+
'workflow-name',
|
|
646
|
+
{ cron: '0 2 * * *' }, // Don't use object form
|
|
647
|
+
{ connection: 'fluent_commerce' },
|
|
648
|
+
async (ctx) => { /* ... */ }
|
|
649
|
+
);
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Supported Cron Formats:**
|
|
653
|
+
- `'0 2 * * *'` - Daily at 2 AM
|
|
654
|
+
- `'*/15 * * * *'` - Every 15 minutes
|
|
655
|
+
- `'0 */6 * * *'` - Every 6 hours
|
|
656
|
+
- `'0 0 * * 1'` - Weekly on Monday
|
|
657
|
+
- `'0 9 1 * *'` - Monthly on 1st at 9 AM
|
|
658
|
+
|
|
659
|
+
#### 2. Buffer Import (Required in Deno/Versori)
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
// ✅ CORRECT: Explicit import
|
|
663
|
+
import { Buffer } from 'node:buffer';
|
|
664
|
+
|
|
665
|
+
// ❌ WRONG: Buffer is not global in Deno
|
|
666
|
+
const buffer = Buffer.from(data); // Error without import
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
#### 3. SDK Version Specification
|
|
670
|
+
|
|
671
|
+
```json
|
|
672
|
+
// ✅ CORRECT: Use caret for latest features
|
|
673
|
+
{
|
|
674
|
+
"dependencies": {
|
|
675
|
+
"@fluentcommerce/fc-connect-sdk": "^0.1.39",
|
|
676
|
+
"@versori/run": "latest"
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// ⚠️ OUTDATED: Old versions missing features
|
|
681
|
+
{
|
|
682
|
+
"dependencies": {
|
|
683
|
+
"@fluentcommerce/fc-connect-sdk": "^0.1.39",
|
|
684
|
+
"@versori/run": "latest" // Use specific version
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
#### 4. Webhook Response Patterns
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
// ✅ CORRECT: Custom XML/HTML response
|
|
693
|
+
export default webhook('name', {
|
|
694
|
+
response: {
|
|
695
|
+
mode: 'sync',
|
|
696
|
+
onSuccess: (ctx) => new Response(
|
|
697
|
+
'<xml>...</xml>',
|
|
698
|
+
{
|
|
699
|
+
status: 200,
|
|
700
|
+
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
701
|
+
}
|
|
702
|
+
),
|
|
703
|
+
onError: (ctx) => new Response(
|
|
704
|
+
'<Error>...</Error>',
|
|
705
|
+
{
|
|
706
|
+
status: 500,
|
|
707
|
+
headers: { 'Content-Type': 'application/xml; charset=utf-8' }
|
|
708
|
+
}
|
|
709
|
+
),
|
|
710
|
+
},
|
|
711
|
+
}, async (ctx) => {
|
|
712
|
+
// Return data object (used in onSuccess handler)
|
|
713
|
+
return { orderRef: '12345' };
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// ❌ WRONG: Returning Response directly (ignores response config)
|
|
717
|
+
export default webhook('name', {}, async (ctx) => {
|
|
718
|
+
return new Response('<xml>...</xml>'); // Don't do this
|
|
719
|
+
});
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
#### 5. Logging Best Practices
|
|
723
|
+
|
|
724
|
+
```typescript
|
|
725
|
+
// ✅ CORRECT: Use native log from context
|
|
726
|
+
export default http('name', { connection: 'fluent' }, async (ctx) => {
|
|
727
|
+
const { log } = ctx;
|
|
728
|
+
|
|
729
|
+
log('Message', { metadata: 'value' });
|
|
730
|
+
log('Error occurred', { error: error.message, stack: error.stack });
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
// ❌ WRONG: Don't use console.log
|
|
734
|
+
export default http('name', { connection: 'fluent' }, async (ctx) => {
|
|
735
|
+
console.log('Message'); // Won't appear in Versori logs
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
// ❌ WRONG: Don't use LoggingService in Versori
|
|
739
|
+
import { LoggingService } from '@fluentcommerce/fc-connect-sdk';
|
|
740
|
+
const logger = new LoggingService(); // Unnecessary overhead
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### 6. Connection Access Patterns
|
|
744
|
+
|
|
745
|
+
```typescript
|
|
746
|
+
// ✅ CORRECT: Use createClient() for auto-detection
|
|
747
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
748
|
+
|
|
749
|
+
export default http('name', { connection: 'fluent_commerce' }, async (ctx) => {
|
|
750
|
+
const client = await createClient(ctx); // Auto-configures from connection
|
|
751
|
+
|
|
752
|
+
// Client is ready to use
|
|
753
|
+
const result = await client.graphql({ query, variables });
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
// ❌ WRONG: Manual FluentClient instantiation (misses Versori context)
|
|
757
|
+
import { FluentClient } from '@fluentcommerce/fc-connect-sdk';
|
|
758
|
+
|
|
759
|
+
export default http('name', { connection: 'fluent' }, async (ctx) => {
|
|
760
|
+
const client = new FluentClient({ /* manual config */ }); // Don't do this
|
|
761
|
+
});
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
#### 7. Auto-Pagination Syntax
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
// ✅ CORRECT: pagination object (not config)
|
|
768
|
+
const result = await client.graphql({
|
|
769
|
+
query: myQuery,
|
|
770
|
+
variables: { first: 100 },
|
|
771
|
+
pagination: { // NOT 'config'
|
|
772
|
+
maxPages: 50,
|
|
773
|
+
pageSize: 100,
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
// ❌ WRONG: config object (old API)
|
|
778
|
+
const result = await client.graphql({
|
|
779
|
+
query: myQuery,
|
|
780
|
+
variables: { first: 100 },
|
|
781
|
+
config: { // Don't use 'config'
|
|
782
|
+
maxPages: 50
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
## Common Patterns
|
|
788
|
+
|
|
789
|
+
### Pattern 1: Multi-Workflow Index Structure
|
|
790
|
+
|
|
791
|
+
Use `package.json` versori.workflows configuration + clean index.ts exports for Versori workflow discovery.
|
|
792
|
+
|
|
793
|
+
### Pattern 2: Shared Resolvers Library
|
|
794
|
+
|
|
795
|
+
Organize resolvers by domain (order, item, payment, extraction) and export combined map for reuse across workflows.
|
|
796
|
+
|
|
797
|
+
### Pattern 3: Custom Response Handlers
|
|
798
|
+
|
|
799
|
+
For XML/HTML responses, use custom `onSuccess` and `onError` handlers that return `Response` objects.
|
|
800
|
+
|
|
801
|
+
### Pattern 4: Async Resolvers
|
|
802
|
+
|
|
803
|
+
Declare resolvers as `async` when querying Fluent API or external services within transformation logic.
|
|
804
|
+
|
|
805
|
+
### Pattern 5: Testing Multi-Workflow Connectors
|
|
806
|
+
|
|
807
|
+
Create local testing scripts that mock Versori activation, log, and connections for end-to-end validation.
|
|
808
|
+
|
|
809
|
+
## Related Guides
|
|
810
|
+
|
|
811
|
+
- **[Versori: Basic Ingestion Workflow](../workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md)**
|
|
812
|
+
- **[Versori: XML Processing](./xml-response-patterns.md)**
|
|
813
|
+
- **[Universal Mapping Guide](../../../02-CORE-GUIDES/advanced-services/advanced-services-readme.md)**
|
|
814
|
+
- **[GraphQL Mutation Mapper](../../../02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md)**
|
|
815
|
+
- **SFCC Connector**: `connectors/versori-sfcc-connector/` for complete reference implementation
|
|
816
|
+
|
|
817
|
+
## Next Steps
|
|
818
|
+
|
|
819
|
+
1. Review the complete SFCC connector implementation
|
|
820
|
+
2. Adapt mapping configurations for your use case
|
|
821
|
+
3. Implement domain-specific resolvers
|
|
822
|
+
4. Test workflows with sample data
|
|
823
|
+
5. Deploy to Versori platform
|
|
824
|
+
6. Monitor and iterate
|
|
825
|
+
|
|
826
|
+
## Production Checklist
|
|
827
|
+
|
|
828
|
+
- [ ] All workflows tested with real data
|
|
829
|
+
- [ ] Error handling covers all edge cases
|
|
830
|
+
- [ ] Logging includes sufficient detail for debugging
|
|
831
|
+
- [ ] Environment variables documented
|
|
832
|
+
- [ ] Resolver logic handles null/undefined values
|
|
833
|
+
- [ ] Package.json versori.workflows correctly configured
|
|
834
|
+
- [ ] TypeScript compilation succeeds with no errors
|
|
835
|
+
- [ ] All custom resolvers have JSDoc comments
|