@fluentcommerce/fc-connect-sdk 0.1.53 → 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 +30 -2
- package/README.md +39 -0
- package/dist/cjs/auth/index.d.ts +3 -0
- package/dist/cjs/auth/index.js +13 -0
- package/dist/cjs/auth/profile-loader.d.ts +18 -0
- package/dist/cjs/auth/profile-loader.js +208 -0
- package/dist/cjs/client-factory.d.ts +4 -0
- package/dist/cjs/client-factory.js +10 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/auth/index.d.ts +3 -0
- package/dist/esm/auth/index.js +2 -0
- package/dist/esm/auth/profile-loader.d.ts +18 -0
- package/dist/esm/auth/profile-loader.js +169 -0
- package/dist/esm/client-factory.d.ts +4 -0
- package/dist/esm/client-factory.js +9 -0
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +2 -1
- 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/dist/types/auth/index.d.ts +3 -0
- package/dist/types/auth/profile-loader.d.ts +18 -0
- package/dist/types/client-factory.d.ts +4 -0
- package/dist/types/index.d.ts +3 -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 -482
- 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
|
@@ -1,1086 +1,1086 @@
|
|
|
1
|
-
# Troubleshooting Quick Reference
|
|
2
|
-
|
|
3
|
-
**When things don't work - start here**
|
|
4
|
-
|
|
5
|
-
## 📋 Quick Logger Setup
|
|
6
|
-
|
|
7
|
-
**Versori Platform** - Use native `log` from context:
|
|
8
|
-
```typescript
|
|
9
|
-
const { log } = ctx; // Native Versori logger
|
|
10
|
-
const client = await createClient({ ...ctx, log });
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
**Standalone (Node.js/Deno)** - Use minimal utilities:
|
|
14
|
-
```typescript
|
|
15
|
-
import { createConsoleLogger, toStructuredLogger } from '@fluentcommerce/fc-connect-sdk';
|
|
16
|
-
|
|
17
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'debug' });
|
|
18
|
-
const client = await createClient({ config: { ...config, logger } });
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**Minimal logger snippet** (when you need Logger interface):
|
|
22
|
-
```typescript
|
|
23
|
-
const logger: import('@fluentcommerce/fc-connect-sdk').Logger = {
|
|
24
|
-
debug: (m, meta) => log.debug(m, meta),
|
|
25
|
-
info: (m, meta) => log.info(m, meta),
|
|
26
|
-
warn: (m, meta) => log.warn(m, meta),
|
|
27
|
-
error: (m, err, meta) => log.error(m, { ...(meta ?? {}), error: err?.message }),
|
|
28
|
-
};
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## 🚨 Common Errors & Fixes (90% of Issues)
|
|
32
|
-
|
|
33
|
-
### Error: `invalid key` from NATS KV (VersoriFileTracker / KV keys)
|
|
34
|
-
|
|
35
|
-
**Meaning:** Your KV key contains characters not allowed by NATS KV (e.g. `:` or spaces/brackets/parentheses).
|
|
36
|
-
|
|
37
|
-
**Allowed characters:** `a-z A-Z 0-9 _ - . = /`
|
|
38
|
-
|
|
39
|
-
**Fix (SDK ≥ current):** `VersoriFileTracker` now uses NATS-safe keys (slash-separated prefix and filename sanitization). Just pass the raw filename; the tracker will sanitize internally.
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
import { VersoriFileTracker } from '@fluentcommerce/fc-connect-sdk';
|
|
43
|
-
|
|
44
|
-
const tracker = new VersoriFileTracker(openKv(':project:'), 'fc-sdk');
|
|
45
|
-
|
|
46
|
-
// Raw basename is OK; tracker sanitizes to NATS-safe key
|
|
47
|
-
const alreadyProcessed = await tracker.wasFileProcessed('[SAMPLE] - file (1).xml');
|
|
48
|
-
if (!alreadyProcessed) {
|
|
49
|
-
// ... process ...
|
|
50
|
-
await tracker.markFileProcessed('[SAMPLE] - file (1).xml', { recordCount: 123 });
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Workaround:** Use your own dot/slash-separated keys and sanitize names before KV get/set.
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
const safe = (name: string) => name.replace(/[^A-Za-z0-9._=\/-]/g, '_');
|
|
58
|
-
await kv.set(`fc_sdk.processed_files.${safe(baseName)}`, { processedAt: new Date().toISOString() });
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
### Error: `Buffer is not defined` (Deno/Versori runtime)
|
|
64
|
-
|
|
65
|
-
**Meaning:** You're using `Buffer.from()` or `Buffer.alloc()` but haven't imported Buffer in Deno/Versori runtime.
|
|
66
|
-
|
|
67
|
-
**Why:** Unlike Node.js, Deno doesn't have `Buffer` as a global. You must explicitly import it from Node.js built-ins.
|
|
68
|
-
|
|
69
|
-
**Fix:** Add the import at the top of your file (before SDK imports):
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// ✅ CORRECT - Import Buffer for Deno/Versori
|
|
73
|
-
import { Buffer } from 'node:buffer';
|
|
74
|
-
import {
|
|
75
|
-
createClient,
|
|
76
|
-
SftpDataSource,
|
|
77
|
-
XMLBuilder,
|
|
78
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
79
|
-
|
|
80
|
-
// Now Buffer works
|
|
81
|
-
const xmlContent = '<VirtualPositions>...</VirtualPositions>';
|
|
82
|
-
await sftp.uploadFile('/path/to/file.xml', Buffer.from(xmlContent, 'utf8'));
|
|
83
|
-
|
|
84
|
-
// Decode base64 credentials
|
|
85
|
-
const decoded = Buffer.from(base64String, 'base64').toString('utf-8');
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**Common use cases requiring Buffer import:**
|
|
89
|
-
- SFTP uploads: `Buffer.from(content, 'utf8')`
|
|
90
|
-
- Base64 decode: `Buffer.from(str, 'base64').toString('utf-8')`
|
|
91
|
-
- Binary data: `Buffer.from(data)`
|
|
92
|
-
- Encoding conversion: `Buffer.from(str, 'latin1').toString('utf8')`
|
|
93
|
-
|
|
94
|
-
**Note:** All SDK templates (v0.1.22+) include this import automatically. If you're using templates from earlier versions, add it manually.
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
### Error: GraphQL errors from Fluent Commerce API
|
|
99
|
-
|
|
100
|
-
**Meaning:** The GraphQL mutation returned errors (e.g., order already exists, missing required field, server error).
|
|
101
|
-
|
|
102
|
-
**Fix:** Use error classification to determine if error is retryable:
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
import { classifyErrors } from '@fluentcommerce/fc-connect-sdk';
|
|
106
|
-
|
|
107
|
-
const result = await client.graphql({ query, variables });
|
|
108
|
-
|
|
109
|
-
if (result.errors) {
|
|
110
|
-
const classification = classifyErrors(result.errors);
|
|
111
|
-
|
|
112
|
-
log.error('GraphQL error:', {
|
|
113
|
-
errorCode: classification.errorCode,
|
|
114
|
-
retryable: classification.retryable,
|
|
115
|
-
action: classification.action,
|
|
116
|
-
message: classification.userMessage,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Don't retry non-retryable errors (e.g., C0121E = order already exists)
|
|
120
|
-
if (!classification.retryable) {
|
|
121
|
-
throw new Error(classification.userMessage);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Retry retryable errors (e.g., S0002E = server error)
|
|
125
|
-
if (classification.retryable) {
|
|
126
|
-
await delay(classification.retryDelaySeconds * 1000);
|
|
127
|
-
// retry logic...
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Common Error Codes:**
|
|
133
|
-
- **C0121E** - Order already exists (non-retryable, verify payload)
|
|
134
|
-
- **C0140E** - Missing required variables (non-retryable, fix payload)
|
|
135
|
-
- **S0002E** - Server error (retryable, retry later)
|
|
136
|
-
- **C0011E** - Rate limit exceeded (retryable, wait and retry)
|
|
137
|
-
|
|
138
|
-
See [GraphQL Error Classification Guide](../02-CORE-GUIDES/api-reference/graphql-error-classification.md) for complete error code reference.
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
### Error: `OAuth2 authentication failed` or `Token refresh failed`
|
|
143
|
-
|
|
144
|
-
**Meaning:** Your Fluent API credentials are invalid or the OAuth2 token exchange is failing.
|
|
145
|
-
|
|
146
|
-
**Why:** Common causes include wrong credentials, expired credentials, network issues, or incorrect OAuth2 endpoint.
|
|
147
|
-
|
|
148
|
-
**Fix:**
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
// ✅ CORRECT - Verify all required credentials are set
|
|
152
|
-
const client = new FluentClient({
|
|
153
|
-
baseUrl: 'https://api.fluentcommerce.com', // Or your environment URL
|
|
154
|
-
clientId: process.env.FLUENT_CLIENT_ID,
|
|
155
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET,
|
|
156
|
-
username: process.env.FLUENT_USERNAME,
|
|
157
|
-
password: process.env.FLUENT_PASSWORD,
|
|
158
|
-
retailerId: process.env.FLUENT_RETAILER_ID, // Required!
|
|
159
|
-
logger, // Enable logging to see authentication details
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Test authentication
|
|
163
|
-
try {
|
|
164
|
-
const result = await client.graphql({
|
|
165
|
-
query: 'query { viewer { id } }',
|
|
166
|
-
});
|
|
167
|
-
console.log('Authentication successful:', result);
|
|
168
|
-
} catch (error) {
|
|
169
|
-
console.error('Authentication failed:', error.message);
|
|
170
|
-
// Check: Are credentials correct? Is baseUrl correct? Is network accessible?
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Common causes:**
|
|
175
|
-
|
|
176
|
-
1. **Missing retailerId**: Required for Fluent API authentication
|
|
177
|
-
2. **Wrong baseUrl**: Should match your Fluent environment (production/staging/sandbox)
|
|
178
|
-
3. **Expired credentials**: Password may have been changed in Fluent settings
|
|
179
|
-
4. **Network issues**: Check if baseUrl is accessible from your environment
|
|
180
|
-
5. **Wrong OAuth2 grant**: SDK uses password grant for standalone, connection-based auth for Versori
|
|
181
|
-
|
|
182
|
-
**Debug checklist:**
|
|
183
|
-
|
|
184
|
-
```bash
|
|
185
|
-
# 1. Verify environment variables are set
|
|
186
|
-
echo $FLUENT_CLIENT_ID
|
|
187
|
-
echo $FLUENT_CLIENT_SECRET
|
|
188
|
-
echo $FLUENT_USERNAME
|
|
189
|
-
echo $FLUENT_RETAILER_ID
|
|
190
|
-
|
|
191
|
-
# 2. Test API endpoint is accessible
|
|
192
|
-
curl https://api.fluentcommerce.com/graphql
|
|
193
|
-
|
|
194
|
-
# 3. Enable debug logging to see OAuth2 token exchange
|
|
195
|
-
# (Add logger to client config as shown above)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
### Error: `Cannot resolve path 'order.missing-field'`
|
|
201
|
-
|
|
202
|
-
**Meaning:** Your mapping config path doesn't exist in your source data.
|
|
203
|
-
|
|
204
|
-
**Fix in 3 steps:**
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
// 1. Print your actual source data structure
|
|
208
|
-
console.log('Source data:', JSON.stringify(sourceData, null, 2));
|
|
209
|
-
|
|
210
|
-
// 2. Find the correct path in the output
|
|
211
|
-
// Looking for "customer-email"? Search the JSON output
|
|
212
|
-
|
|
213
|
-
// 3. Update your mapping config
|
|
214
|
-
{
|
|
215
|
-
"email": {
|
|
216
|
-
"source": "order.customer.email", // ✅ Correct path from step 1
|
|
217
|
-
"required": true
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
**Quick Debug:**
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
// Add this before mapping
|
|
226
|
-
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
227
|
-
|
|
228
|
-
const value = get(sourceData, 'order.customer.email');
|
|
229
|
-
console.log('Testing path:', value);
|
|
230
|
-
// undefined = wrong path, value = correct path
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
### Error: `Required field 'ref' is missing or empty`
|
|
236
|
-
|
|
237
|
-
**Meaning:** The field mapped successfully, but the value is null/undefined/empty string.
|
|
238
|
-
|
|
239
|
-
**Fix:**
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
// Option 1: Provide a default value
|
|
243
|
-
{
|
|
244
|
-
"ref": {
|
|
245
|
-
"source": "order.ref",
|
|
246
|
-
"defaultValue": "ORDER-UNKNOWN" // ✅ Fallback if missing
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Option 2: Make it optional
|
|
251
|
-
{
|
|
252
|
-
"ref": {
|
|
253
|
-
"source": "order.ref",
|
|
254
|
-
"required": false // ✅ Allow null/undefined
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Option 3: Transform empty to valid value
|
|
259
|
-
{
|
|
260
|
-
"ref": {
|
|
261
|
-
"source": "order.ref",
|
|
262
|
-
"resolver": "sdk.coalesce", // ✅ Use first non-empty value
|
|
263
|
-
"resolverConfig": {
|
|
264
|
-
"values": ["order.ref", "order.id", "ORDER-FALLBACK"]
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
### Error: `Expected array but got object at path 'items'`
|
|
273
|
-
|
|
274
|
-
**Meaning:** Your source has a single object, but GraphQL expects an array.
|
|
275
|
-
|
|
276
|
-
**Fix:**
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
{
|
|
280
|
-
"items": {
|
|
281
|
-
"_array": true,
|
|
282
|
-
"_autoWrap": true, // ✅ Automatically wrap single objects into [object]
|
|
283
|
-
"source": "order.items"
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
**Alternative - Always make it an array:**
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
{
|
|
292
|
-
"items": {
|
|
293
|
-
"source": "order.items",
|
|
294
|
-
"resolver": "custom.ensureArray"
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Custom resolver
|
|
299
|
-
const customResolvers = {
|
|
300
|
-
"custom.ensureArray": (value) => Array.isArray(value) ? value : [value]
|
|
301
|
-
};
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
### Error: Custom Resolver Failed
|
|
307
|
-
|
|
308
|
-
**Meaning:** Your custom resolver threw an error.
|
|
309
|
-
|
|
310
|
-
**Fix - Add Defensive Coding:**
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
// ❌ BAD - Will crash if value is null
|
|
314
|
-
const badResolver = value => value.toUpperCase();
|
|
315
|
-
|
|
316
|
-
// ✅ GOOD - Handle edge cases
|
|
317
|
-
const goodResolver = value => {
|
|
318
|
-
if (value == null) return null; // Handle null/undefined
|
|
319
|
-
if (typeof value !== 'string') return String(value); // Coerce to string
|
|
320
|
-
return value.toUpperCase();
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// ✅ BETTER - Use helpers
|
|
324
|
-
const bestResolver = (value, sourceData, config, helpers) => {
|
|
325
|
-
const str = helpers.toString(value); // Safe conversion
|
|
326
|
-
return str ? str.toUpperCase() : null;
|
|
327
|
-
};
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
**Debug Custom Resolvers:**
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
const myResolver = (value, sourceData, config, helpers) => {
|
|
334
|
-
// Log everything
|
|
335
|
-
console.log('Resolver input:', { value, sourceData, config });
|
|
336
|
-
|
|
337
|
-
try {
|
|
338
|
-
const result = value.toUpperCase();
|
|
339
|
-
console.log('Resolver output:', result);
|
|
340
|
-
return result;
|
|
341
|
-
} catch (error) {
|
|
342
|
-
console.error('Resolver error:', error.message);
|
|
343
|
-
throw error; // Re-throw after logging
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
---
|
|
349
|
-
|
|
350
|
-
### Error: `setAutoPadding(false) not supported for Aes128Gcm yet`
|
|
351
|
-
|
|
352
|
-
**Meaning:** SFTP connection is failing on Versori platform (Deno runtime) because AES-GCM ciphers aren't supported.
|
|
353
|
-
|
|
354
|
-
**Fix:** None needed! The SDK automatically detects Deno and uses compatible ciphers.
|
|
355
|
-
|
|
356
|
-
**Just upgrade to SDK v0.1.7+:**
|
|
357
|
-
|
|
358
|
-
```bash
|
|
359
|
-
npm install @fluentcommerce/fc-connect-sdk@latest
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
**What the SDK does:**
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
// Automatic - no configuration needed in your connector
|
|
366
|
-
const sftp = new SftpDataSource(
|
|
367
|
-
{
|
|
368
|
-
settings: {
|
|
369
|
-
host: 's-xxxxx.server.transfer.amazonaws.com',
|
|
370
|
-
// SDK auto-detects Deno and configures compatible algorithms
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
logger
|
|
374
|
-
);
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
**Verification:**
|
|
378
|
-
Check logs for: `"Deno runtime detected - using compatible SFTP algorithms (NO GCM)"`
|
|
379
|
-
|
|
380
|
-
**📖 Full details:** [Deno SFTP Compatibility Guide](../04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md)
|
|
381
|
-
|
|
382
|
-
---
|
|
383
|
-
|
|
384
|
-
## SFTP transient errors (timeouts, ECONNRESET)
|
|
385
|
-
|
|
386
|
-
Symptoms:
|
|
387
|
-
|
|
388
|
-
- Intermittent failures during SFTP upload/download/list
|
|
389
|
-
|
|
390
|
-
Fix:
|
|
391
|
-
|
|
392
|
-
- SDK includes built-in retries for SFTP operations (list, download, upload, delete, mkdir).
|
|
393
|
-
- Configure via `settings.retry` on `SftpDataSource`:
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
const sftp = new SftpDataSource(
|
|
397
|
-
{
|
|
398
|
-
type: 'SFTP_XML',
|
|
399
|
-
connectionId: 'sftp',
|
|
400
|
-
name: 'sftp',
|
|
401
|
-
settings: {
|
|
402
|
-
host,
|
|
403
|
-
port,
|
|
404
|
-
username,
|
|
405
|
-
password,
|
|
406
|
-
remotePath: '/upload',
|
|
407
|
-
filePattern: '*.xml',
|
|
408
|
-
retry: {
|
|
409
|
-
maxAttempts: 3,
|
|
410
|
-
baseDelayMs: 1000,
|
|
411
|
-
backoffFactor: 2,
|
|
412
|
-
maxDelayMs: 8000,
|
|
413
|
-
jitter: 'full',
|
|
414
|
-
reconnectOnFailure: true,
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
},
|
|
418
|
-
logger
|
|
419
|
-
);
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
Notes:
|
|
423
|
-
|
|
424
|
-
- Crypto/algorithm errors (e.g., AES-GCM unsupported) are not retryable.
|
|
425
|
-
|
|
426
|
-
---
|
|
427
|
-
|
|
428
|
-
## S3 transient HTTP errors (503, 504, 429)
|
|
429
|
-
|
|
430
|
-
Symptoms:
|
|
431
|
-
|
|
432
|
-
- Occasional 5xx or 429 from S3 presigned URL requests
|
|
433
|
-
|
|
434
|
-
Fix:
|
|
435
|
-
|
|
436
|
-
- SDK applies exponential backoff retries around HTTP fetch for S3 operations.
|
|
437
|
-
- Control attempts via `s3Config.maxAttempts` (default 3).
|
|
438
|
-
|
|
439
|
-
```typescript
|
|
440
|
-
const ds = new S3DataSource(
|
|
441
|
-
{
|
|
442
|
-
type: 'S3_JSON',
|
|
443
|
-
connectionId: 's3',
|
|
444
|
-
name: 's3',
|
|
445
|
-
settings: {},
|
|
446
|
-
s3Config: { accessKeyId, secretAccessKey, region, bucket, maxAttempts: 5 },
|
|
447
|
-
},
|
|
448
|
-
logger
|
|
449
|
-
);
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
---
|
|
453
|
-
|
|
454
|
-
## ExtractionOrchestrator errors
|
|
455
|
-
|
|
456
|
-
Symptoms:
|
|
457
|
-
|
|
458
|
-
- `ExtractionOrchestrator.extract()` fails with path resolution errors
|
|
459
|
-
- Data not extracted from nested GraphQL response
|
|
460
|
-
|
|
461
|
-
Fix:
|
|
462
|
-
|
|
463
|
-
**1. Verify `resultPath` matches your GraphQL response structure:**
|
|
464
|
-
|
|
465
|
-
```typescript
|
|
466
|
-
// ❌ WRONG - dataPath doesn't match response structure
|
|
467
|
-
const result = await orchestrator.extract({
|
|
468
|
-
query: `query { inventoryPositions { edges { node { ref } } } }`,
|
|
469
|
-
resultPath: 'inventory.edges.node', // Wrong! Should be 'inventoryPositions.edges.node'
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
// ✅ CORRECT - dataPath matches response
|
|
473
|
-
const result = await orchestrator.extract({
|
|
474
|
-
query: `query { inventoryPositions { edges { node { ref } } } }`,
|
|
475
|
-
resultPath: 'inventoryPositions.edges.node',
|
|
476
|
-
});
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
**2. Enable debug logging to see extraction process:**
|
|
480
|
-
|
|
481
|
-
```typescript
|
|
482
|
-
import { createConsoleLogger, toStructuredLogger } from '@fluentcommerce/fc-connect-sdk';
|
|
483
|
-
|
|
484
|
-
const logger = toStructuredLogger(createConsoleLogger(), {
|
|
485
|
-
logLevel: 'debug',
|
|
486
|
-
});
|
|
487
|
-
const orchestrator = new ExtractionOrchestrator(client, logger);
|
|
488
|
-
|
|
489
|
-
// You'll see logs like:
|
|
490
|
-
// [DEBUG] Extracting data from path: inventoryPositions
|
|
491
|
-
// [DEBUG] Found 100 records in current page
|
|
492
|
-
// [DEBUG] Processing page 2 of estimated 10 pages
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
**3. Check pagination configuration:**
|
|
496
|
-
|
|
497
|
-
```typescript
|
|
498
|
-
// For cursor-based pagination (most common)
|
|
499
|
-
const result = await orchestrator.extract({
|
|
500
|
-
query: `query GetData($first: Int!, $after: String) { ... }`,
|
|
501
|
-
variables: { first: 100 },
|
|
502
|
-
maxRecords: 5000, // Stop after 5000 records
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
// Query MUST include pagination variables ($first, $after) for auto-pagination
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
---
|
|
509
|
-
|
|
510
|
-
## Webhook validation errors
|
|
511
|
-
|
|
512
|
-
Symptoms:
|
|
513
|
-
|
|
514
|
-
- `client.validateWebhook()` returns `false`
|
|
515
|
-
- Signature verification failing for legitimate webhooks
|
|
516
|
-
|
|
517
|
-
Fix:
|
|
518
|
-
|
|
519
|
-
**1. Ensure you have the correct public key from Fluent:**
|
|
520
|
-
|
|
521
|
-
```typescript
|
|
522
|
-
// Get your public key from Fluent Commerce settings
|
|
523
|
-
const FLUENT_WEBHOOK_PUBLIC_KEY = process.env.FLUENT_WEBHOOK_PUBLIC_KEY;
|
|
524
|
-
|
|
525
|
-
// Configure client with public key
|
|
526
|
-
const client = new FluentClient({
|
|
527
|
-
baseUrl: 'https://api.fluentcommerce.com',
|
|
528
|
-
clientId: process.env.FLUENT_CLIENT_ID,
|
|
529
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET,
|
|
530
|
-
username: process.env.FLUENT_USERNAME,
|
|
531
|
-
password: process.env.FLUENT_PASSWORD,
|
|
532
|
-
retailerId: process.env.FLUENT_RETAILER_ID,
|
|
533
|
-
publicKey: FLUENT_WEBHOOK_PUBLIC_KEY, // Add public key for webhook validation
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
// validateWebhook returns boolean
|
|
537
|
-
const isValid = await client.validateWebhook(payload, signature, rawPayload);
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
**2. Verify you're passing the raw payload for signature validation:**
|
|
541
|
-
|
|
542
|
-
```typescript
|
|
543
|
-
// ✅ CORRECT - Pass signature and raw payload
|
|
544
|
-
const signature = headers['fluent-signature'];
|
|
545
|
-
const rawPayload = await request.text(); // Get raw body before parsing
|
|
546
|
-
const payload = JSON.parse(rawPayload);
|
|
547
|
-
|
|
548
|
-
const isValid = await client.validateWebhook(payload, signature, rawPayload);
|
|
549
|
-
|
|
550
|
-
// ❌ WRONG - Missing signature or raw payload
|
|
551
|
-
const payload = await request.json(); // Already parsed, can't verify signature
|
|
552
|
-
const isValid = await client.validateWebhook(payload); // No signature check
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
**3. Check for payload modification:**
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
// ❌ WRONG - Modifying payload before validation
|
|
559
|
-
const payload = await request.json();
|
|
560
|
-
payload.processed = true; // Modifying payload breaks signature!
|
|
561
|
-
const isValid = await client.validateWebhook(payload);
|
|
562
|
-
|
|
563
|
-
// ✅ CORRECT - Validate first, then modify
|
|
564
|
-
const rawPayload = await request.text();
|
|
565
|
-
const payload = JSON.parse(rawPayload);
|
|
566
|
-
const isValid = await client.validateWebhook(payload, signature, rawPayload);
|
|
567
|
-
if (isValid) {
|
|
568
|
-
payload.processed = true; // Now safe to modify
|
|
569
|
-
}
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
**Documentation:** See [Webhook Validation Guide](../02-CORE-GUIDES/webhook-validation/webhook-validation-readme.md)
|
|
573
|
-
|
|
574
|
-
---
|
|
575
|
-
|
|
576
|
-
## Partial batch recovery
|
|
577
|
-
|
|
578
|
-
Symptoms:
|
|
579
|
-
|
|
580
|
-
- Some records in a batch fail, but you want to retry only failures
|
|
581
|
-
- Need to track which specific records failed in a large batch
|
|
582
|
-
|
|
583
|
-
Fix:
|
|
584
|
-
|
|
585
|
-
**Use PartialBatchRecovery service:**
|
|
586
|
-
|
|
587
|
-
```typescript
|
|
588
|
-
import { PartialBatchRecovery } from '@fluentcommerce/fc-connect-sdk';
|
|
589
|
-
|
|
590
|
-
const recovery = new PartialBatchRecovery(client, logger);
|
|
591
|
-
|
|
592
|
-
// Record failures during batch processing
|
|
593
|
-
const failures: RecordFailure[] = [];
|
|
594
|
-
|
|
595
|
-
for (const record of batchRecords) {
|
|
596
|
-
try {
|
|
597
|
-
await client.graphql({ query: mutation, variables: record });
|
|
598
|
-
} catch (error) {
|
|
599
|
-
failures.push({
|
|
600
|
-
record,
|
|
601
|
-
error: error.message,
|
|
602
|
-
attemptNumber: 1,
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
// Retry only failed records
|
|
608
|
-
const recoveryResult = await recovery.retryFailedRecords({
|
|
609
|
-
jobId,
|
|
610
|
-
failures,
|
|
611
|
-
maxRetries: 3,
|
|
612
|
-
retryDelayMs: 1000,
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
console.log(`Recovered: ${recoveryResult.successCount}/${recoveryResult.totalAttempted}`);
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
---
|
|
619
|
-
|
|
620
|
-
## Job tracking issues
|
|
621
|
-
|
|
622
|
-
Symptoms:
|
|
623
|
-
|
|
624
|
-
- Need to track job lifecycle across multiple executions
|
|
625
|
-
- Want to resume job from last checkpoint
|
|
626
|
-
|
|
627
|
-
Fix:
|
|
628
|
-
|
|
629
|
-
**Use JobTracker service:**
|
|
630
|
-
|
|
631
|
-
```typescript
|
|
632
|
-
import { JobTracker, VersoriKVAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
633
|
-
|
|
634
|
-
const kvAdapter = new VersoriKVAdapter(openKv());
|
|
635
|
-
const jobTracker = new JobTracker(kvAdapter, logger);
|
|
636
|
-
|
|
637
|
-
// Create or resume job
|
|
638
|
-
const jobStatus = await jobTracker.getOrCreateJob({
|
|
639
|
-
jobId: 'daily-inventory-sync',
|
|
640
|
-
trigger: 'scheduled',
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
if (jobStatus.status === 'running') {
|
|
644
|
-
console.log('Job already running, skipping...');
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Update job status
|
|
649
|
-
await jobTracker.updateJobStatus('daily-inventory-sync', 'running');
|
|
650
|
-
|
|
651
|
-
try {
|
|
652
|
-
// Your processing logic
|
|
653
|
-
await processInventory();
|
|
654
|
-
|
|
655
|
-
await jobTracker.updateJobStatus('daily-inventory-sync', 'completed');
|
|
656
|
-
} catch (error) {
|
|
657
|
-
await jobTracker.updateJobStatus('daily-inventory-sync', 'failed', {
|
|
658
|
-
error: error.message,
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
---
|
|
664
|
-
|
|
665
|
-
## Preflight validation failures
|
|
666
|
-
|
|
667
|
-
Symptoms:
|
|
668
|
-
|
|
669
|
-
- Want to validate configuration before execution
|
|
670
|
-
- Need to check credentials, file access, etc. before running connector
|
|
671
|
-
|
|
672
|
-
Fix:
|
|
673
|
-
|
|
674
|
-
**Use PreflightValidator service:**
|
|
675
|
-
|
|
676
|
-
```typescript
|
|
677
|
-
import { PreflightValidator } from '@fluentcommerce/fc-connect-sdk';
|
|
678
|
-
|
|
679
|
-
const validator = new PreflightValidator(logger);
|
|
680
|
-
|
|
681
|
-
const validationResult = await validator.validate({
|
|
682
|
-
client,
|
|
683
|
-
s3Config: {
|
|
684
|
-
bucket: 'my-bucket',
|
|
685
|
-
region: 'us-east-1',
|
|
686
|
-
accessKeyId,
|
|
687
|
-
secretAccessKey,
|
|
688
|
-
},
|
|
689
|
-
checks: [
|
|
690
|
-
'fluent-auth', // Verify Fluent credentials
|
|
691
|
-
's3-access', // Verify S3 bucket access
|
|
692
|
-
'file-exists', // Check if source files exist
|
|
693
|
-
],
|
|
694
|
-
});
|
|
695
|
-
|
|
696
|
-
if (!validationResult.success) {
|
|
697
|
-
console.error('Preflight validation failed:', validationResult.errors);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// Safe to proceed with actual processing
|
|
702
|
-
await runConnector();
|
|
703
|
-
```
|
|
704
|
-
|
|
705
|
-
---
|
|
706
|
-
|
|
707
|
-
## 🔍 Debugging Techniques
|
|
708
|
-
|
|
709
|
-
### 1. Enable Debug Logging
|
|
710
|
-
|
|
711
|
-
```typescript
|
|
712
|
-
const logger = {
|
|
713
|
-
debug: (msg, meta) => console.log('[DEBUG]', msg, meta),
|
|
714
|
-
info: (msg, meta) => console.log('[INFO]', msg, meta),
|
|
715
|
-
warn: (msg, meta) => console.warn('[WARN]', msg, meta),
|
|
716
|
-
error: (msg, err, meta) => console.error('[ERROR]', msg, err, meta),
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
const mapper = new GraphQLMutationMapper(config, logger, { fluentClient: client });
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
**Output:**
|
|
723
|
-
|
|
724
|
-
```
|
|
725
|
-
[DEBUG] Processing node: radial { source: '...', parseAs: 'xml' }
|
|
726
|
-
[DEBUG] Applying resolver 'sdk.uppercase' to field 'ref' { fieldPath: 'input.ref' }
|
|
727
|
-
[INFO] Mapped order data { orderRef: 'ORDER-123' }
|
|
728
|
-
```
|
|
729
|
-
|
|
730
|
-
---
|
|
731
|
-
|
|
732
|
-
### 2. Inspect Intermediate Results
|
|
733
|
-
|
|
734
|
-
```typescript
|
|
735
|
-
// After parsing
|
|
736
|
-
const parsed = await parser.parse(xmlString);
|
|
737
|
-
console.log('Parsed data:', JSON.stringify(parsed, null, 2));
|
|
738
|
-
|
|
739
|
-
// After mapping (before mutation)
|
|
740
|
-
const result = await mapper.map(parsed);
|
|
741
|
-
console.log('Mapped variables:', JSON.stringify(result.variables, null, 2));
|
|
742
|
-
|
|
743
|
-
// The actual GraphQL that will be sent
|
|
744
|
-
console.log('GraphQL mutation:', result.mutation);
|
|
745
|
-
console.log('Variables:', JSON.stringify(result.variables, null, 2));
|
|
746
|
-
```
|
|
747
|
-
|
|
748
|
-
---
|
|
749
|
-
|
|
750
|
-
### 3. Test Paths Independently
|
|
751
|
-
|
|
752
|
-
```typescript
|
|
753
|
-
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
754
|
-
|
|
755
|
-
const testPaths = [
|
|
756
|
-
'order.customer.email',
|
|
757
|
-
'order.items[0].sku',
|
|
758
|
-
'order@order-no', // XML attribute
|
|
759
|
-
'$radial.Order.Items.Item[]', // Node reference with array
|
|
760
|
-
];
|
|
761
|
-
|
|
762
|
-
testPaths.forEach(path => {
|
|
763
|
-
const value = get(sourceData, path);
|
|
764
|
-
console.log(`${path} = ${JSON.stringify(value)}`);
|
|
765
|
-
});
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
---
|
|
769
|
-
|
|
770
|
-
### 4. Test Resolvers Independently
|
|
771
|
-
|
|
772
|
-
```typescript
|
|
773
|
-
import { sdkResolvers } from '@fluentcommerce/fc-connect-sdk';
|
|
774
|
-
|
|
775
|
-
// Test SDK resolver
|
|
776
|
-
const uppercase = sdkResolvers['sdk.uppercase'];
|
|
777
|
-
console.log(uppercase('hello', {}, {}, {})); // "HELLO"
|
|
778
|
-
|
|
779
|
-
// Test custom resolver
|
|
780
|
-
const myResolver = customResolvers['custom.calculateTax'];
|
|
781
|
-
const testValue = 100;
|
|
782
|
-
const testSource = { country: 'US' };
|
|
783
|
-
const result = myResolver(testValue, testSource, {}, {});
|
|
784
|
-
console.log('Tax result:', result);
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
---
|
|
788
|
-
|
|
789
|
-
## 🛠️ Debugging Workflow (Step-by-Step)
|
|
790
|
-
|
|
791
|
-
**When mapping fails, follow these steps:**
|
|
792
|
-
|
|
793
|
-
### Step 1: Verify Source Data Structure
|
|
794
|
-
|
|
795
|
-
```typescript
|
|
796
|
-
// Save actual data to file for inspection
|
|
797
|
-
fs.writeFileSync('debug-source.json', JSON.stringify(sourceData, null, 2));
|
|
798
|
-
|
|
799
|
-
// Or log to console
|
|
800
|
-
console.log('Source:', JSON.stringify(sourceData, null, 2));
|
|
801
|
-
```
|
|
802
|
-
|
|
803
|
-
✅ **Check:** Does the source data have the structure you expect?
|
|
804
|
-
|
|
805
|
-
---
|
|
806
|
-
|
|
807
|
-
### Step 2: Test Paths
|
|
808
|
-
|
|
809
|
-
```typescript
|
|
810
|
-
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
811
|
-
|
|
812
|
-
// Test each path from your mapping config
|
|
813
|
-
const paths = ['order.ref', 'order.customer.email', 'order.items[]'];
|
|
814
|
-
|
|
815
|
-
paths.forEach(path => {
|
|
816
|
-
console.log(`Testing ${path}:`, get(sourceData, path));
|
|
817
|
-
});
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
✅ **Check:** Do all paths resolve to values (not `undefined`)?
|
|
821
|
-
|
|
822
|
-
---
|
|
823
|
-
|
|
824
|
-
### Step 3: Test Resolvers
|
|
825
|
-
|
|
826
|
-
```typescript
|
|
827
|
-
// Test each custom resolver independently
|
|
828
|
-
const value = 'test-value';
|
|
829
|
-
const sourceData = {
|
|
830
|
-
/* your data */
|
|
831
|
-
};
|
|
832
|
-
|
|
833
|
-
try {
|
|
834
|
-
const result = customResolvers`'custom.myResolver'`;
|
|
835
|
-
console.log('Resolver output:', result);
|
|
836
|
-
} catch (error) {
|
|
837
|
-
console.error('Resolver failed:', error.message);
|
|
838
|
-
}
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
✅ **Check:** Do resolvers return expected values? Do they handle null/undefined?
|
|
842
|
-
|
|
843
|
-
---
|
|
844
|
-
|
|
845
|
-
### Step 4: Enable Debug Logging
|
|
846
|
-
|
|
847
|
-
```typescript
|
|
848
|
-
const logger = {
|
|
849
|
-
debug: console.log,
|
|
850
|
-
info: console.log,
|
|
851
|
-
warn: console.warn,
|
|
852
|
-
error: console.error,
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
const mapper = new GraphQLMutationMapper(config, logger, { fluentClient: client });
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
✅ **Check:** What does the debug output show? Where does it fail?
|
|
859
|
-
|
|
860
|
-
---
|
|
861
|
-
|
|
862
|
-
### Step 5: Inspect Generated Mutation
|
|
863
|
-
|
|
864
|
-
```typescript
|
|
865
|
-
const result = await mapper.map(sourceData);
|
|
866
|
-
|
|
867
|
-
// Log the actual GraphQL that will be sent
|
|
868
|
-
console.log('Mutation:', result.mutation);
|
|
869
|
-
console.log('Variables:', JSON.stringify(result.variables, null, 2));
|
|
870
|
-
|
|
871
|
-
// Save to file for detailed inspection
|
|
872
|
-
fs.writeFileSync('debug-mutation.graphql', result.mutation);
|
|
873
|
-
fs.writeFileSync('debug-variables.json', JSON.stringify(result.variables, null, 2));
|
|
874
|
-
```
|
|
875
|
-
|
|
876
|
-
✅ **Check:** Does the generated mutation match GraphQL schema? Are required fields present?
|
|
877
|
-
|
|
878
|
-
---
|
|
879
|
-
|
|
880
|
-
## 📋 Quick Debugging Checklist
|
|
881
|
-
|
|
882
|
-
Copy this checklist when troubleshooting:
|
|
883
|
-
|
|
884
|
-
```
|
|
885
|
-
□ Print source data structure to console/file
|
|
886
|
-
□ Test each mapping path with get() function
|
|
887
|
-
□ Verify required fields are not null/undefined
|
|
888
|
-
□ Test custom resolvers independently
|
|
889
|
-
□ Enable debug logging
|
|
890
|
-
□ Check generated mutation syntax
|
|
891
|
-
□ Verify variables match GraphQL schema types
|
|
892
|
-
□ Test mutation in GraphQL playground first
|
|
893
|
-
□ Check Fluent API error response for schema issues
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
---
|
|
897
|
-
|
|
898
|
-
## 🎯 Common Patterns & Solutions
|
|
899
|
-
|
|
900
|
-
### Pattern: Conditional Field Mapping
|
|
901
|
-
|
|
902
|
-
**Problem:** Only include field if condition is met.
|
|
903
|
-
|
|
904
|
-
**Solution:**
|
|
905
|
-
|
|
906
|
-
```typescript
|
|
907
|
-
{
|
|
908
|
-
"priority": {
|
|
909
|
-
"source": "order.urgency",
|
|
910
|
-
"resolver": "custom.mapPriority"
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
// Resolver
|
|
915
|
-
const customResolvers = {
|
|
916
|
-
"custom.mapPriority": (value) => {
|
|
917
|
-
if (value === 'RUSH') return 'HIGH';
|
|
918
|
-
if (value === 'STANDARD') return 'NORMAL';
|
|
919
|
-
return 'LOW'; // Default
|
|
920
|
-
}
|
|
921
|
-
};
|
|
922
|
-
```
|
|
923
|
-
|
|
924
|
-
---
|
|
925
|
-
|
|
926
|
-
### Pattern: Combine Multiple Fields
|
|
927
|
-
|
|
928
|
-
**Problem:** Create fullName from firstName + lastName.
|
|
929
|
-
|
|
930
|
-
**Solution:**
|
|
931
|
-
|
|
932
|
-
```typescript
|
|
933
|
-
{
|
|
934
|
-
"fullName": {
|
|
935
|
-
"source": "customer",
|
|
936
|
-
"resolver": "custom.fullName"
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
// Resolver
|
|
941
|
-
const customResolvers = {
|
|
942
|
-
"custom.fullName": (value, sourceData) => {
|
|
943
|
-
const { firstName, lastName } = value;
|
|
944
|
-
return `${firstName} ${lastName}`.trim();
|
|
945
|
-
}
|
|
946
|
-
};
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
---
|
|
950
|
-
|
|
951
|
-
### Pattern: Lookup from API
|
|
952
|
-
|
|
953
|
-
**Problem:** Get customer ID from email via API call.
|
|
954
|
-
|
|
955
|
-
**Solution:**
|
|
956
|
-
|
|
957
|
-
```typescript
|
|
958
|
-
{
|
|
959
|
-
"customerId": {
|
|
960
|
-
"source": "customer.email",
|
|
961
|
-
"resolver": "custom.lookupCustomer"
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
// Resolver (async allowed!)
|
|
966
|
-
const customResolvers = {
|
|
967
|
-
"custom.lookupCustomer": async (email, sourceData, config, helpers) => {
|
|
968
|
-
const client = helpers.fluentClient;
|
|
969
|
-
if (!client) throw new Error('FluentClient not available in helpers');
|
|
970
|
-
|
|
971
|
-
const result = await client.graphql({
|
|
972
|
-
query: `query GetCustomer($email: String!) {
|
|
973
|
-
customers(email: $email) {
|
|
974
|
-
edges { node { id } }
|
|
975
|
-
}
|
|
976
|
-
}`,
|
|
977
|
-
variables: { email }
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
return result.data.customers.edges[0]?.node.id || null;
|
|
981
|
-
}
|
|
982
|
-
};
|
|
983
|
-
```
|
|
984
|
-
|
|
985
|
-
---
|
|
986
|
-
|
|
987
|
-
### Pattern: Transform Array Items
|
|
988
|
-
|
|
989
|
-
**Problem:** Transform each item in an array.
|
|
990
|
-
|
|
991
|
-
**Solution:**
|
|
992
|
-
|
|
993
|
-
```typescript
|
|
994
|
-
{
|
|
995
|
-
"items": {
|
|
996
|
-
"_array": true,
|
|
997
|
-
"source": "order.items",
|
|
998
|
-
"fields": {
|
|
999
|
-
"sku": { "source": "product-id" },
|
|
1000
|
-
"quantity": {
|
|
1001
|
-
"source": "qty",
|
|
1002
|
-
"resolver": "sdk.parseInt" // Transform each item's qty
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
```
|
|
1008
|
-
|
|
1009
|
-
---
|
|
1010
|
-
|
|
1011
|
-
## 💡 Pro Tips
|
|
1012
|
-
|
|
1013
|
-
### Tip 1: Use Safe Helpers
|
|
1014
|
-
|
|
1015
|
-
```typescript
|
|
1016
|
-
// ❌ Don't do this
|
|
1017
|
-
const value = data.order.customer.email; // Crashes if order is null
|
|
1018
|
-
|
|
1019
|
-
// ✅ Use get() helper
|
|
1020
|
-
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
1021
|
-
const value = get(data, 'order.customer.email'); // Returns undefined safely
|
|
1022
|
-
|
|
1023
|
-
// Or use helpers.get() in resolvers
|
|
1024
|
-
const value = helpers.get(data, 'order.customer.email');
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
### Tip 2: Always Validate Resolver Inputs
|
|
1028
|
-
|
|
1029
|
-
```typescript
|
|
1030
|
-
const myResolver = (value, sourceData, config, helpers) => {
|
|
1031
|
-
// Validate inputs
|
|
1032
|
-
if (value == null) {
|
|
1033
|
-
helpers.logger?.warn('Resolver received null value');
|
|
1034
|
-
return null;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
// Your logic
|
|
1038
|
-
return value.toUpperCase();
|
|
1039
|
-
};
|
|
1040
|
-
```
|
|
1041
|
-
|
|
1042
|
-
### Tip 3: Use defaultValue for Required Fields
|
|
1043
|
-
|
|
1044
|
-
```typescript
|
|
1045
|
-
// Instead of crashing on missing data
|
|
1046
|
-
{
|
|
1047
|
-
"ref": {
|
|
1048
|
-
"source": "order.ref",
|
|
1049
|
-
"required": true,
|
|
1050
|
-
"defaultValue": () => `ORDER-${Date.now()}` // Generate if missing
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
```
|
|
1054
|
-
|
|
1055
|
-
### Tip 4: Save Intermediate Results
|
|
1056
|
-
|
|
1057
|
-
```typescript
|
|
1058
|
-
// Add to your workflow for debugging
|
|
1059
|
-
fs.writeFileSync('01-source-data.json', JSON.stringify(sourceData, null, 2));
|
|
1060
|
-
fs.writeFileSync('02-mapped-variables.json', JSON.stringify(result.variables, null, 2));
|
|
1061
|
-
fs.writeFileSync('03-mutation.graphql', result.mutation);
|
|
1062
|
-
fs.writeFileSync('04-response.json', JSON.stringify(response, null, 2));
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
---
|
|
1066
|
-
|
|
1067
|
-
## 🔗 Related Documentation
|
|
1068
|
-
|
|
1069
|
-
- [Error Handling Guide](../02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md) - Complete error reference
|
|
1070
|
-
- [Custom Resolvers Guide](../02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md) - How to write resolvers
|
|
1071
|
-
- [Path Syntax Reference](../02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md) - Understanding paths
|
|
1072
|
-
- [Decision Tree](./decision-tree.md) - Which approach to use
|
|
1073
|
-
|
|
1074
|
-
---
|
|
1075
|
-
|
|
1076
|
-
## 📞 Still Stuck?
|
|
1077
|
-
|
|
1078
|
-
If you've tried everything above and still have issues:
|
|
1079
|
-
|
|
1080
|
-
1. **Check Examples:** Look in `docs/01-TEMPLATES/` for similar scenarios
|
|
1081
|
-
2. **Enable Full Debug Logging:** Capture all SDK output
|
|
1082
|
-
3. **Save All Intermediate Data:** Source → Parsed → Mapped → Response
|
|
1083
|
-
4. **Test in Isolation:** Remove resolvers, simplify mapping, add back one at a time
|
|
1084
|
-
5. **Check GraphQL Schema:** Validate mutation in GraphQL playground first
|
|
1085
|
-
|
|
1086
|
-
**Remember:** 90% of issues are path resolution or null values. Start there!
|
|
1
|
+
# Troubleshooting Quick Reference
|
|
2
|
+
|
|
3
|
+
**When things don't work - start here**
|
|
4
|
+
|
|
5
|
+
## 📋 Quick Logger Setup
|
|
6
|
+
|
|
7
|
+
**Versori Platform** - Use native `log` from context:
|
|
8
|
+
```typescript
|
|
9
|
+
const { log } = ctx; // Native Versori logger
|
|
10
|
+
const client = await createClient({ ...ctx, log });
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Standalone (Node.js/Deno)** - Use minimal utilities:
|
|
14
|
+
```typescript
|
|
15
|
+
import { createConsoleLogger, toStructuredLogger } from '@fluentcommerce/fc-connect-sdk';
|
|
16
|
+
|
|
17
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'debug' });
|
|
18
|
+
const client = await createClient({ config: { ...config, logger } });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Minimal logger snippet** (when you need Logger interface):
|
|
22
|
+
```typescript
|
|
23
|
+
const logger: import('@fluentcommerce/fc-connect-sdk').Logger = {
|
|
24
|
+
debug: (m, meta) => log.debug(m, meta),
|
|
25
|
+
info: (m, meta) => log.info(m, meta),
|
|
26
|
+
warn: (m, meta) => log.warn(m, meta),
|
|
27
|
+
error: (m, err, meta) => log.error(m, { ...(meta ?? {}), error: err?.message }),
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 🚨 Common Errors & Fixes (90% of Issues)
|
|
32
|
+
|
|
33
|
+
### Error: `invalid key` from NATS KV (VersoriFileTracker / KV keys)
|
|
34
|
+
|
|
35
|
+
**Meaning:** Your KV key contains characters not allowed by NATS KV (e.g. `:` or spaces/brackets/parentheses).
|
|
36
|
+
|
|
37
|
+
**Allowed characters:** `a-z A-Z 0-9 _ - . = /`
|
|
38
|
+
|
|
39
|
+
**Fix (SDK ≥ current):** `VersoriFileTracker` now uses NATS-safe keys (slash-separated prefix and filename sanitization). Just pass the raw filename; the tracker will sanitize internally.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { VersoriFileTracker } from '@fluentcommerce/fc-connect-sdk';
|
|
43
|
+
|
|
44
|
+
const tracker = new VersoriFileTracker(openKv(':project:'), 'fc-sdk');
|
|
45
|
+
|
|
46
|
+
// Raw basename is OK; tracker sanitizes to NATS-safe key
|
|
47
|
+
const alreadyProcessed = await tracker.wasFileProcessed('[SAMPLE] - file (1).xml');
|
|
48
|
+
if (!alreadyProcessed) {
|
|
49
|
+
// ... process ...
|
|
50
|
+
await tracker.markFileProcessed('[SAMPLE] - file (1).xml', { recordCount: 123 });
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Workaround:** Use your own dot/slash-separated keys and sanitize names before KV get/set.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const safe = (name: string) => name.replace(/[^A-Za-z0-9._=\/-]/g, '_');
|
|
58
|
+
await kv.set(`fc_sdk.processed_files.${safe(baseName)}`, { processedAt: new Date().toISOString() });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Error: `Buffer is not defined` (Deno/Versori runtime)
|
|
64
|
+
|
|
65
|
+
**Meaning:** You're using `Buffer.from()` or `Buffer.alloc()` but haven't imported Buffer in Deno/Versori runtime.
|
|
66
|
+
|
|
67
|
+
**Why:** Unlike Node.js, Deno doesn't have `Buffer` as a global. You must explicitly import it from Node.js built-ins.
|
|
68
|
+
|
|
69
|
+
**Fix:** Add the import at the top of your file (before SDK imports):
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// ✅ CORRECT - Import Buffer for Deno/Versori
|
|
73
|
+
import { Buffer } from 'node:buffer';
|
|
74
|
+
import {
|
|
75
|
+
createClient,
|
|
76
|
+
SftpDataSource,
|
|
77
|
+
XMLBuilder,
|
|
78
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
79
|
+
|
|
80
|
+
// Now Buffer works
|
|
81
|
+
const xmlContent = '<VirtualPositions>...</VirtualPositions>';
|
|
82
|
+
await sftp.uploadFile('/path/to/file.xml', Buffer.from(xmlContent, 'utf8'));
|
|
83
|
+
|
|
84
|
+
// Decode base64 credentials
|
|
85
|
+
const decoded = Buffer.from(base64String, 'base64').toString('utf-8');
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Common use cases requiring Buffer import:**
|
|
89
|
+
- SFTP uploads: `Buffer.from(content, 'utf8')`
|
|
90
|
+
- Base64 decode: `Buffer.from(str, 'base64').toString('utf-8')`
|
|
91
|
+
- Binary data: `Buffer.from(data)`
|
|
92
|
+
- Encoding conversion: `Buffer.from(str, 'latin1').toString('utf8')`
|
|
93
|
+
|
|
94
|
+
**Note:** All SDK templates (v0.1.22+) include this import automatically. If you're using templates from earlier versions, add it manually.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### Error: GraphQL errors from Fluent Commerce API
|
|
99
|
+
|
|
100
|
+
**Meaning:** The GraphQL mutation returned errors (e.g., order already exists, missing required field, server error).
|
|
101
|
+
|
|
102
|
+
**Fix:** Use error classification to determine if error is retryable:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { classifyErrors } from '@fluentcommerce/fc-connect-sdk';
|
|
106
|
+
|
|
107
|
+
const result = await client.graphql({ query, variables });
|
|
108
|
+
|
|
109
|
+
if (result.errors) {
|
|
110
|
+
const classification = classifyErrors(result.errors);
|
|
111
|
+
|
|
112
|
+
log.error('GraphQL error:', {
|
|
113
|
+
errorCode: classification.errorCode,
|
|
114
|
+
retryable: classification.retryable,
|
|
115
|
+
action: classification.action,
|
|
116
|
+
message: classification.userMessage,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Don't retry non-retryable errors (e.g., C0121E = order already exists)
|
|
120
|
+
if (!classification.retryable) {
|
|
121
|
+
throw new Error(classification.userMessage);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Retry retryable errors (e.g., S0002E = server error)
|
|
125
|
+
if (classification.retryable) {
|
|
126
|
+
await delay(classification.retryDelaySeconds * 1000);
|
|
127
|
+
// retry logic...
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Common Error Codes:**
|
|
133
|
+
- **C0121E** - Order already exists (non-retryable, verify payload)
|
|
134
|
+
- **C0140E** - Missing required variables (non-retryable, fix payload)
|
|
135
|
+
- **S0002E** - Server error (retryable, retry later)
|
|
136
|
+
- **C0011E** - Rate limit exceeded (retryable, wait and retry)
|
|
137
|
+
|
|
138
|
+
See [GraphQL Error Classification Guide](../02-CORE-GUIDES/api-reference/graphql-error-classification.md) for complete error code reference.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Error: `OAuth2 authentication failed` or `Token refresh failed`
|
|
143
|
+
|
|
144
|
+
**Meaning:** Your Fluent API credentials are invalid or the OAuth2 token exchange is failing.
|
|
145
|
+
|
|
146
|
+
**Why:** Common causes include wrong credentials, expired credentials, network issues, or incorrect OAuth2 endpoint.
|
|
147
|
+
|
|
148
|
+
**Fix:**
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// ✅ CORRECT - Verify all required credentials are set
|
|
152
|
+
const client = new FluentClient({
|
|
153
|
+
baseUrl: 'https://api.fluentcommerce.com', // Or your environment URL
|
|
154
|
+
clientId: process.env.FLUENT_CLIENT_ID,
|
|
155
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET,
|
|
156
|
+
username: process.env.FLUENT_USERNAME,
|
|
157
|
+
password: process.env.FLUENT_PASSWORD,
|
|
158
|
+
retailerId: process.env.FLUENT_RETAILER_ID, // Required!
|
|
159
|
+
logger, // Enable logging to see authentication details
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Test authentication
|
|
163
|
+
try {
|
|
164
|
+
const result = await client.graphql({
|
|
165
|
+
query: 'query { viewer { id } }',
|
|
166
|
+
});
|
|
167
|
+
console.log('Authentication successful:', result);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error('Authentication failed:', error.message);
|
|
170
|
+
// Check: Are credentials correct? Is baseUrl correct? Is network accessible?
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Common causes:**
|
|
175
|
+
|
|
176
|
+
1. **Missing retailerId**: Required for Fluent API authentication
|
|
177
|
+
2. **Wrong baseUrl**: Should match your Fluent environment (production/staging/sandbox)
|
|
178
|
+
3. **Expired credentials**: Password may have been changed in Fluent settings
|
|
179
|
+
4. **Network issues**: Check if baseUrl is accessible from your environment
|
|
180
|
+
5. **Wrong OAuth2 grant**: SDK uses password grant for standalone, connection-based auth for Versori
|
|
181
|
+
|
|
182
|
+
**Debug checklist:**
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# 1. Verify environment variables are set
|
|
186
|
+
echo $FLUENT_CLIENT_ID
|
|
187
|
+
echo $FLUENT_CLIENT_SECRET
|
|
188
|
+
echo $FLUENT_USERNAME
|
|
189
|
+
echo $FLUENT_RETAILER_ID
|
|
190
|
+
|
|
191
|
+
# 2. Test API endpoint is accessible
|
|
192
|
+
curl https://api.fluentcommerce.com/graphql
|
|
193
|
+
|
|
194
|
+
# 3. Enable debug logging to see OAuth2 token exchange
|
|
195
|
+
# (Add logger to client config as shown above)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### Error: `Cannot resolve path 'order.missing-field'`
|
|
201
|
+
|
|
202
|
+
**Meaning:** Your mapping config path doesn't exist in your source data.
|
|
203
|
+
|
|
204
|
+
**Fix in 3 steps:**
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// 1. Print your actual source data structure
|
|
208
|
+
console.log('Source data:', JSON.stringify(sourceData, null, 2));
|
|
209
|
+
|
|
210
|
+
// 2. Find the correct path in the output
|
|
211
|
+
// Looking for "customer-email"? Search the JSON output
|
|
212
|
+
|
|
213
|
+
// 3. Update your mapping config
|
|
214
|
+
{
|
|
215
|
+
"email": {
|
|
216
|
+
"source": "order.customer.email", // ✅ Correct path from step 1
|
|
217
|
+
"required": true
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Quick Debug:**
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Add this before mapping
|
|
226
|
+
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
227
|
+
|
|
228
|
+
const value = get(sourceData, 'order.customer.email');
|
|
229
|
+
console.log('Testing path:', value);
|
|
230
|
+
// undefined = wrong path, value = correct path
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### Error: `Required field 'ref' is missing or empty`
|
|
236
|
+
|
|
237
|
+
**Meaning:** The field mapped successfully, but the value is null/undefined/empty string.
|
|
238
|
+
|
|
239
|
+
**Fix:**
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// Option 1: Provide a default value
|
|
243
|
+
{
|
|
244
|
+
"ref": {
|
|
245
|
+
"source": "order.ref",
|
|
246
|
+
"defaultValue": "ORDER-UNKNOWN" // ✅ Fallback if missing
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Option 2: Make it optional
|
|
251
|
+
{
|
|
252
|
+
"ref": {
|
|
253
|
+
"source": "order.ref",
|
|
254
|
+
"required": false // ✅ Allow null/undefined
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Option 3: Transform empty to valid value
|
|
259
|
+
{
|
|
260
|
+
"ref": {
|
|
261
|
+
"source": "order.ref",
|
|
262
|
+
"resolver": "sdk.coalesce", // ✅ Use first non-empty value
|
|
263
|
+
"resolverConfig": {
|
|
264
|
+
"values": ["order.ref", "order.id", "ORDER-FALLBACK"]
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
### Error: `Expected array but got object at path 'items'`
|
|
273
|
+
|
|
274
|
+
**Meaning:** Your source has a single object, but GraphQL expects an array.
|
|
275
|
+
|
|
276
|
+
**Fix:**
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
{
|
|
280
|
+
"items": {
|
|
281
|
+
"_array": true,
|
|
282
|
+
"_autoWrap": true, // ✅ Automatically wrap single objects into [object]
|
|
283
|
+
"source": "order.items"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Alternative - Always make it an array:**
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
{
|
|
292
|
+
"items": {
|
|
293
|
+
"source": "order.items",
|
|
294
|
+
"resolver": "custom.ensureArray"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Custom resolver
|
|
299
|
+
const customResolvers = {
|
|
300
|
+
"custom.ensureArray": (value) => Array.isArray(value) ? value : [value]
|
|
301
|
+
};
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### Error: Custom Resolver Failed
|
|
307
|
+
|
|
308
|
+
**Meaning:** Your custom resolver threw an error.
|
|
309
|
+
|
|
310
|
+
**Fix - Add Defensive Coding:**
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// ❌ BAD - Will crash if value is null
|
|
314
|
+
const badResolver = value => value.toUpperCase();
|
|
315
|
+
|
|
316
|
+
// ✅ GOOD - Handle edge cases
|
|
317
|
+
const goodResolver = value => {
|
|
318
|
+
if (value == null) return null; // Handle null/undefined
|
|
319
|
+
if (typeof value !== 'string') return String(value); // Coerce to string
|
|
320
|
+
return value.toUpperCase();
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// ✅ BETTER - Use helpers
|
|
324
|
+
const bestResolver = (value, sourceData, config, helpers) => {
|
|
325
|
+
const str = helpers.toString(value); // Safe conversion
|
|
326
|
+
return str ? str.toUpperCase() : null;
|
|
327
|
+
};
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Debug Custom Resolvers:**
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
const myResolver = (value, sourceData, config, helpers) => {
|
|
334
|
+
// Log everything
|
|
335
|
+
console.log('Resolver input:', { value, sourceData, config });
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
const result = value.toUpperCase();
|
|
339
|
+
console.log('Resolver output:', result);
|
|
340
|
+
return result;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error('Resolver error:', error.message);
|
|
343
|
+
throw error; // Re-throw after logging
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
### Error: `setAutoPadding(false) not supported for Aes128Gcm yet`
|
|
351
|
+
|
|
352
|
+
**Meaning:** SFTP connection is failing on Versori platform (Deno runtime) because AES-GCM ciphers aren't supported.
|
|
353
|
+
|
|
354
|
+
**Fix:** None needed! The SDK automatically detects Deno and uses compatible ciphers.
|
|
355
|
+
|
|
356
|
+
**Just upgrade to SDK v0.1.7+:**
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
npm install @fluentcommerce/fc-connect-sdk@latest
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**What the SDK does:**
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// Automatic - no configuration needed in your connector
|
|
366
|
+
const sftp = new SftpDataSource(
|
|
367
|
+
{
|
|
368
|
+
settings: {
|
|
369
|
+
host: 's-xxxxx.server.transfer.amazonaws.com',
|
|
370
|
+
// SDK auto-detects Deno and configures compatible algorithms
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
logger
|
|
374
|
+
);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Verification:**
|
|
378
|
+
Check logs for: `"Deno runtime detected - using compatible SFTP algorithms (NO GCM)"`
|
|
379
|
+
|
|
380
|
+
**📖 Full details:** [Deno SFTP Compatibility Guide](../04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md)
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## SFTP transient errors (timeouts, ECONNRESET)
|
|
385
|
+
|
|
386
|
+
Symptoms:
|
|
387
|
+
|
|
388
|
+
- Intermittent failures during SFTP upload/download/list
|
|
389
|
+
|
|
390
|
+
Fix:
|
|
391
|
+
|
|
392
|
+
- SDK includes built-in retries for SFTP operations (list, download, upload, delete, mkdir).
|
|
393
|
+
- Configure via `settings.retry` on `SftpDataSource`:
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
const sftp = new SftpDataSource(
|
|
397
|
+
{
|
|
398
|
+
type: 'SFTP_XML',
|
|
399
|
+
connectionId: 'sftp',
|
|
400
|
+
name: 'sftp',
|
|
401
|
+
settings: {
|
|
402
|
+
host,
|
|
403
|
+
port,
|
|
404
|
+
username,
|
|
405
|
+
password,
|
|
406
|
+
remotePath: '/upload',
|
|
407
|
+
filePattern: '*.xml',
|
|
408
|
+
retry: {
|
|
409
|
+
maxAttempts: 3,
|
|
410
|
+
baseDelayMs: 1000,
|
|
411
|
+
backoffFactor: 2,
|
|
412
|
+
maxDelayMs: 8000,
|
|
413
|
+
jitter: 'full',
|
|
414
|
+
reconnectOnFailure: true,
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
logger
|
|
419
|
+
);
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Notes:
|
|
423
|
+
|
|
424
|
+
- Crypto/algorithm errors (e.g., AES-GCM unsupported) are not retryable.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## S3 transient HTTP errors (503, 504, 429)
|
|
429
|
+
|
|
430
|
+
Symptoms:
|
|
431
|
+
|
|
432
|
+
- Occasional 5xx or 429 from S3 presigned URL requests
|
|
433
|
+
|
|
434
|
+
Fix:
|
|
435
|
+
|
|
436
|
+
- SDK applies exponential backoff retries around HTTP fetch for S3 operations.
|
|
437
|
+
- Control attempts via `s3Config.maxAttempts` (default 3).
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
const ds = new S3DataSource(
|
|
441
|
+
{
|
|
442
|
+
type: 'S3_JSON',
|
|
443
|
+
connectionId: 's3',
|
|
444
|
+
name: 's3',
|
|
445
|
+
settings: {},
|
|
446
|
+
s3Config: { accessKeyId, secretAccessKey, region, bucket, maxAttempts: 5 },
|
|
447
|
+
},
|
|
448
|
+
logger
|
|
449
|
+
);
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## ExtractionOrchestrator errors
|
|
455
|
+
|
|
456
|
+
Symptoms:
|
|
457
|
+
|
|
458
|
+
- `ExtractionOrchestrator.extract()` fails with path resolution errors
|
|
459
|
+
- Data not extracted from nested GraphQL response
|
|
460
|
+
|
|
461
|
+
Fix:
|
|
462
|
+
|
|
463
|
+
**1. Verify `resultPath` matches your GraphQL response structure:**
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
// ❌ WRONG - dataPath doesn't match response structure
|
|
467
|
+
const result = await orchestrator.extract({
|
|
468
|
+
query: `query { inventoryPositions { edges { node { ref } } } }`,
|
|
469
|
+
resultPath: 'inventory.edges.node', // Wrong! Should be 'inventoryPositions.edges.node'
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
// ✅ CORRECT - dataPath matches response
|
|
473
|
+
const result = await orchestrator.extract({
|
|
474
|
+
query: `query { inventoryPositions { edges { node { ref } } } }`,
|
|
475
|
+
resultPath: 'inventoryPositions.edges.node',
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**2. Enable debug logging to see extraction process:**
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
import { createConsoleLogger, toStructuredLogger } from '@fluentcommerce/fc-connect-sdk';
|
|
483
|
+
|
|
484
|
+
const logger = toStructuredLogger(createConsoleLogger(), {
|
|
485
|
+
logLevel: 'debug',
|
|
486
|
+
});
|
|
487
|
+
const orchestrator = new ExtractionOrchestrator(client, logger);
|
|
488
|
+
|
|
489
|
+
// You'll see logs like:
|
|
490
|
+
// [DEBUG] Extracting data from path: inventoryPositions
|
|
491
|
+
// [DEBUG] Found 100 records in current page
|
|
492
|
+
// [DEBUG] Processing page 2 of estimated 10 pages
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
**3. Check pagination configuration:**
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
// For cursor-based pagination (most common)
|
|
499
|
+
const result = await orchestrator.extract({
|
|
500
|
+
query: `query GetData($first: Int!, $after: String) { ... }`,
|
|
501
|
+
variables: { first: 100 },
|
|
502
|
+
maxRecords: 5000, // Stop after 5000 records
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Query MUST include pagination variables ($first, $after) for auto-pagination
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Webhook validation errors
|
|
511
|
+
|
|
512
|
+
Symptoms:
|
|
513
|
+
|
|
514
|
+
- `client.validateWebhook()` returns `false`
|
|
515
|
+
- Signature verification failing for legitimate webhooks
|
|
516
|
+
|
|
517
|
+
Fix:
|
|
518
|
+
|
|
519
|
+
**1. Ensure you have the correct public key from Fluent:**
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
// Get your public key from Fluent Commerce settings
|
|
523
|
+
const FLUENT_WEBHOOK_PUBLIC_KEY = process.env.FLUENT_WEBHOOK_PUBLIC_KEY;
|
|
524
|
+
|
|
525
|
+
// Configure client with public key
|
|
526
|
+
const client = new FluentClient({
|
|
527
|
+
baseUrl: 'https://api.fluentcommerce.com',
|
|
528
|
+
clientId: process.env.FLUENT_CLIENT_ID,
|
|
529
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET,
|
|
530
|
+
username: process.env.FLUENT_USERNAME,
|
|
531
|
+
password: process.env.FLUENT_PASSWORD,
|
|
532
|
+
retailerId: process.env.FLUENT_RETAILER_ID,
|
|
533
|
+
publicKey: FLUENT_WEBHOOK_PUBLIC_KEY, // Add public key for webhook validation
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
// validateWebhook returns boolean
|
|
537
|
+
const isValid = await client.validateWebhook(payload, signature, rawPayload);
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**2. Verify you're passing the raw payload for signature validation:**
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
// ✅ CORRECT - Pass signature and raw payload
|
|
544
|
+
const signature = headers['fluent-signature'];
|
|
545
|
+
const rawPayload = await request.text(); // Get raw body before parsing
|
|
546
|
+
const payload = JSON.parse(rawPayload);
|
|
547
|
+
|
|
548
|
+
const isValid = await client.validateWebhook(payload, signature, rawPayload);
|
|
549
|
+
|
|
550
|
+
// ❌ WRONG - Missing signature or raw payload
|
|
551
|
+
const payload = await request.json(); // Already parsed, can't verify signature
|
|
552
|
+
const isValid = await client.validateWebhook(payload); // No signature check
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
**3. Check for payload modification:**
|
|
556
|
+
|
|
557
|
+
```typescript
|
|
558
|
+
// ❌ WRONG - Modifying payload before validation
|
|
559
|
+
const payload = await request.json();
|
|
560
|
+
payload.processed = true; // Modifying payload breaks signature!
|
|
561
|
+
const isValid = await client.validateWebhook(payload);
|
|
562
|
+
|
|
563
|
+
// ✅ CORRECT - Validate first, then modify
|
|
564
|
+
const rawPayload = await request.text();
|
|
565
|
+
const payload = JSON.parse(rawPayload);
|
|
566
|
+
const isValid = await client.validateWebhook(payload, signature, rawPayload);
|
|
567
|
+
if (isValid) {
|
|
568
|
+
payload.processed = true; // Now safe to modify
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Documentation:** See [Webhook Validation Guide](../02-CORE-GUIDES/webhook-validation/webhook-validation-readme.md)
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Partial batch recovery
|
|
577
|
+
|
|
578
|
+
Symptoms:
|
|
579
|
+
|
|
580
|
+
- Some records in a batch fail, but you want to retry only failures
|
|
581
|
+
- Need to track which specific records failed in a large batch
|
|
582
|
+
|
|
583
|
+
Fix:
|
|
584
|
+
|
|
585
|
+
**Use PartialBatchRecovery service:**
|
|
586
|
+
|
|
587
|
+
```typescript
|
|
588
|
+
import { PartialBatchRecovery } from '@fluentcommerce/fc-connect-sdk';
|
|
589
|
+
|
|
590
|
+
const recovery = new PartialBatchRecovery(client, logger);
|
|
591
|
+
|
|
592
|
+
// Record failures during batch processing
|
|
593
|
+
const failures: RecordFailure[] = [];
|
|
594
|
+
|
|
595
|
+
for (const record of batchRecords) {
|
|
596
|
+
try {
|
|
597
|
+
await client.graphql({ query: mutation, variables: record });
|
|
598
|
+
} catch (error) {
|
|
599
|
+
failures.push({
|
|
600
|
+
record,
|
|
601
|
+
error: error.message,
|
|
602
|
+
attemptNumber: 1,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Retry only failed records
|
|
608
|
+
const recoveryResult = await recovery.retryFailedRecords({
|
|
609
|
+
jobId,
|
|
610
|
+
failures,
|
|
611
|
+
maxRetries: 3,
|
|
612
|
+
retryDelayMs: 1000,
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
console.log(`Recovered: ${recoveryResult.successCount}/${recoveryResult.totalAttempted}`);
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
## Job tracking issues
|
|
621
|
+
|
|
622
|
+
Symptoms:
|
|
623
|
+
|
|
624
|
+
- Need to track job lifecycle across multiple executions
|
|
625
|
+
- Want to resume job from last checkpoint
|
|
626
|
+
|
|
627
|
+
Fix:
|
|
628
|
+
|
|
629
|
+
**Use JobTracker service:**
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
import { JobTracker, VersoriKVAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
633
|
+
|
|
634
|
+
const kvAdapter = new VersoriKVAdapter(openKv());
|
|
635
|
+
const jobTracker = new JobTracker(kvAdapter, logger);
|
|
636
|
+
|
|
637
|
+
// Create or resume job
|
|
638
|
+
const jobStatus = await jobTracker.getOrCreateJob({
|
|
639
|
+
jobId: 'daily-inventory-sync',
|
|
640
|
+
trigger: 'scheduled',
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
if (jobStatus.status === 'running') {
|
|
644
|
+
console.log('Job already running, skipping...');
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Update job status
|
|
649
|
+
await jobTracker.updateJobStatus('daily-inventory-sync', 'running');
|
|
650
|
+
|
|
651
|
+
try {
|
|
652
|
+
// Your processing logic
|
|
653
|
+
await processInventory();
|
|
654
|
+
|
|
655
|
+
await jobTracker.updateJobStatus('daily-inventory-sync', 'completed');
|
|
656
|
+
} catch (error) {
|
|
657
|
+
await jobTracker.updateJobStatus('daily-inventory-sync', 'failed', {
|
|
658
|
+
error: error.message,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
## Preflight validation failures
|
|
666
|
+
|
|
667
|
+
Symptoms:
|
|
668
|
+
|
|
669
|
+
- Want to validate configuration before execution
|
|
670
|
+
- Need to check credentials, file access, etc. before running connector
|
|
671
|
+
|
|
672
|
+
Fix:
|
|
673
|
+
|
|
674
|
+
**Use PreflightValidator service:**
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
import { PreflightValidator } from '@fluentcommerce/fc-connect-sdk';
|
|
678
|
+
|
|
679
|
+
const validator = new PreflightValidator(logger);
|
|
680
|
+
|
|
681
|
+
const validationResult = await validator.validate({
|
|
682
|
+
client,
|
|
683
|
+
s3Config: {
|
|
684
|
+
bucket: 'my-bucket',
|
|
685
|
+
region: 'us-east-1',
|
|
686
|
+
accessKeyId,
|
|
687
|
+
secretAccessKey,
|
|
688
|
+
},
|
|
689
|
+
checks: [
|
|
690
|
+
'fluent-auth', // Verify Fluent credentials
|
|
691
|
+
's3-access', // Verify S3 bucket access
|
|
692
|
+
'file-exists', // Check if source files exist
|
|
693
|
+
],
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
if (!validationResult.success) {
|
|
697
|
+
console.error('Preflight validation failed:', validationResult.errors);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// Safe to proceed with actual processing
|
|
702
|
+
await runConnector();
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
## 🔍 Debugging Techniques
|
|
708
|
+
|
|
709
|
+
### 1. Enable Debug Logging
|
|
710
|
+
|
|
711
|
+
```typescript
|
|
712
|
+
const logger = {
|
|
713
|
+
debug: (msg, meta) => console.log('[DEBUG]', msg, meta),
|
|
714
|
+
info: (msg, meta) => console.log('[INFO]', msg, meta),
|
|
715
|
+
warn: (msg, meta) => console.warn('[WARN]', msg, meta),
|
|
716
|
+
error: (msg, err, meta) => console.error('[ERROR]', msg, err, meta),
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
const mapper = new GraphQLMutationMapper(config, logger, { fluentClient: client });
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**Output:**
|
|
723
|
+
|
|
724
|
+
```
|
|
725
|
+
[DEBUG] Processing node: radial { source: '...', parseAs: 'xml' }
|
|
726
|
+
[DEBUG] Applying resolver 'sdk.uppercase' to field 'ref' { fieldPath: 'input.ref' }
|
|
727
|
+
[INFO] Mapped order data { orderRef: 'ORDER-123' }
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
### 2. Inspect Intermediate Results
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
// After parsing
|
|
736
|
+
const parsed = await parser.parse(xmlString);
|
|
737
|
+
console.log('Parsed data:', JSON.stringify(parsed, null, 2));
|
|
738
|
+
|
|
739
|
+
// After mapping (before mutation)
|
|
740
|
+
const result = await mapper.map(parsed);
|
|
741
|
+
console.log('Mapped variables:', JSON.stringify(result.variables, null, 2));
|
|
742
|
+
|
|
743
|
+
// The actual GraphQL that will be sent
|
|
744
|
+
console.log('GraphQL mutation:', result.mutation);
|
|
745
|
+
console.log('Variables:', JSON.stringify(result.variables, null, 2));
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
### 3. Test Paths Independently
|
|
751
|
+
|
|
752
|
+
```typescript
|
|
753
|
+
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
754
|
+
|
|
755
|
+
const testPaths = [
|
|
756
|
+
'order.customer.email',
|
|
757
|
+
'order.items[0].sku',
|
|
758
|
+
'order@order-no', // XML attribute
|
|
759
|
+
'$radial.Order.Items.Item[]', // Node reference with array
|
|
760
|
+
];
|
|
761
|
+
|
|
762
|
+
testPaths.forEach(path => {
|
|
763
|
+
const value = get(sourceData, path);
|
|
764
|
+
console.log(`${path} = ${JSON.stringify(value)}`);
|
|
765
|
+
});
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
### 4. Test Resolvers Independently
|
|
771
|
+
|
|
772
|
+
```typescript
|
|
773
|
+
import { sdkResolvers } from '@fluentcommerce/fc-connect-sdk';
|
|
774
|
+
|
|
775
|
+
// Test SDK resolver
|
|
776
|
+
const uppercase = sdkResolvers['sdk.uppercase'];
|
|
777
|
+
console.log(uppercase('hello', {}, {}, {})); // "HELLO"
|
|
778
|
+
|
|
779
|
+
// Test custom resolver
|
|
780
|
+
const myResolver = customResolvers['custom.calculateTax'];
|
|
781
|
+
const testValue = 100;
|
|
782
|
+
const testSource = { country: 'US' };
|
|
783
|
+
const result = myResolver(testValue, testSource, {}, {});
|
|
784
|
+
console.log('Tax result:', result);
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## 🛠️ Debugging Workflow (Step-by-Step)
|
|
790
|
+
|
|
791
|
+
**When mapping fails, follow these steps:**
|
|
792
|
+
|
|
793
|
+
### Step 1: Verify Source Data Structure
|
|
794
|
+
|
|
795
|
+
```typescript
|
|
796
|
+
// Save actual data to file for inspection
|
|
797
|
+
fs.writeFileSync('debug-source.json', JSON.stringify(sourceData, null, 2));
|
|
798
|
+
|
|
799
|
+
// Or log to console
|
|
800
|
+
console.log('Source:', JSON.stringify(sourceData, null, 2));
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
✅ **Check:** Does the source data have the structure you expect?
|
|
804
|
+
|
|
805
|
+
---
|
|
806
|
+
|
|
807
|
+
### Step 2: Test Paths
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
811
|
+
|
|
812
|
+
// Test each path from your mapping config
|
|
813
|
+
const paths = ['order.ref', 'order.customer.email', 'order.items[]'];
|
|
814
|
+
|
|
815
|
+
paths.forEach(path => {
|
|
816
|
+
console.log(`Testing ${path}:`, get(sourceData, path));
|
|
817
|
+
});
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
✅ **Check:** Do all paths resolve to values (not `undefined`)?
|
|
821
|
+
|
|
822
|
+
---
|
|
823
|
+
|
|
824
|
+
### Step 3: Test Resolvers
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
// Test each custom resolver independently
|
|
828
|
+
const value = 'test-value';
|
|
829
|
+
const sourceData = {
|
|
830
|
+
/* your data */
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
try {
|
|
834
|
+
const result = customResolvers`'custom.myResolver'`;
|
|
835
|
+
console.log('Resolver output:', result);
|
|
836
|
+
} catch (error) {
|
|
837
|
+
console.error('Resolver failed:', error.message);
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
✅ **Check:** Do resolvers return expected values? Do they handle null/undefined?
|
|
842
|
+
|
|
843
|
+
---
|
|
844
|
+
|
|
845
|
+
### Step 4: Enable Debug Logging
|
|
846
|
+
|
|
847
|
+
```typescript
|
|
848
|
+
const logger = {
|
|
849
|
+
debug: console.log,
|
|
850
|
+
info: console.log,
|
|
851
|
+
warn: console.warn,
|
|
852
|
+
error: console.error,
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
const mapper = new GraphQLMutationMapper(config, logger, { fluentClient: client });
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
✅ **Check:** What does the debug output show? Where does it fail?
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
### Step 5: Inspect Generated Mutation
|
|
863
|
+
|
|
864
|
+
```typescript
|
|
865
|
+
const result = await mapper.map(sourceData);
|
|
866
|
+
|
|
867
|
+
// Log the actual GraphQL that will be sent
|
|
868
|
+
console.log('Mutation:', result.mutation);
|
|
869
|
+
console.log('Variables:', JSON.stringify(result.variables, null, 2));
|
|
870
|
+
|
|
871
|
+
// Save to file for detailed inspection
|
|
872
|
+
fs.writeFileSync('debug-mutation.graphql', result.mutation);
|
|
873
|
+
fs.writeFileSync('debug-variables.json', JSON.stringify(result.variables, null, 2));
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
✅ **Check:** Does the generated mutation match GraphQL schema? Are required fields present?
|
|
877
|
+
|
|
878
|
+
---
|
|
879
|
+
|
|
880
|
+
## 📋 Quick Debugging Checklist
|
|
881
|
+
|
|
882
|
+
Copy this checklist when troubleshooting:
|
|
883
|
+
|
|
884
|
+
```
|
|
885
|
+
□ Print source data structure to console/file
|
|
886
|
+
□ Test each mapping path with get() function
|
|
887
|
+
□ Verify required fields are not null/undefined
|
|
888
|
+
□ Test custom resolvers independently
|
|
889
|
+
□ Enable debug logging
|
|
890
|
+
□ Check generated mutation syntax
|
|
891
|
+
□ Verify variables match GraphQL schema types
|
|
892
|
+
□ Test mutation in GraphQL playground first
|
|
893
|
+
□ Check Fluent API error response for schema issues
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
---
|
|
897
|
+
|
|
898
|
+
## 🎯 Common Patterns & Solutions
|
|
899
|
+
|
|
900
|
+
### Pattern: Conditional Field Mapping
|
|
901
|
+
|
|
902
|
+
**Problem:** Only include field if condition is met.
|
|
903
|
+
|
|
904
|
+
**Solution:**
|
|
905
|
+
|
|
906
|
+
```typescript
|
|
907
|
+
{
|
|
908
|
+
"priority": {
|
|
909
|
+
"source": "order.urgency",
|
|
910
|
+
"resolver": "custom.mapPriority"
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Resolver
|
|
915
|
+
const customResolvers = {
|
|
916
|
+
"custom.mapPriority": (value) => {
|
|
917
|
+
if (value === 'RUSH') return 'HIGH';
|
|
918
|
+
if (value === 'STANDARD') return 'NORMAL';
|
|
919
|
+
return 'LOW'; // Default
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
---
|
|
925
|
+
|
|
926
|
+
### Pattern: Combine Multiple Fields
|
|
927
|
+
|
|
928
|
+
**Problem:** Create fullName from firstName + lastName.
|
|
929
|
+
|
|
930
|
+
**Solution:**
|
|
931
|
+
|
|
932
|
+
```typescript
|
|
933
|
+
{
|
|
934
|
+
"fullName": {
|
|
935
|
+
"source": "customer",
|
|
936
|
+
"resolver": "custom.fullName"
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// Resolver
|
|
941
|
+
const customResolvers = {
|
|
942
|
+
"custom.fullName": (value, sourceData) => {
|
|
943
|
+
const { firstName, lastName } = value;
|
|
944
|
+
return `${firstName} ${lastName}`.trim();
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
---
|
|
950
|
+
|
|
951
|
+
### Pattern: Lookup from API
|
|
952
|
+
|
|
953
|
+
**Problem:** Get customer ID from email via API call.
|
|
954
|
+
|
|
955
|
+
**Solution:**
|
|
956
|
+
|
|
957
|
+
```typescript
|
|
958
|
+
{
|
|
959
|
+
"customerId": {
|
|
960
|
+
"source": "customer.email",
|
|
961
|
+
"resolver": "custom.lookupCustomer"
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Resolver (async allowed!)
|
|
966
|
+
const customResolvers = {
|
|
967
|
+
"custom.lookupCustomer": async (email, sourceData, config, helpers) => {
|
|
968
|
+
const client = helpers.fluentClient;
|
|
969
|
+
if (!client) throw new Error('FluentClient not available in helpers');
|
|
970
|
+
|
|
971
|
+
const result = await client.graphql({
|
|
972
|
+
query: `query GetCustomer($email: String!) {
|
|
973
|
+
customers(email: $email) {
|
|
974
|
+
edges { node { id } }
|
|
975
|
+
}
|
|
976
|
+
}`,
|
|
977
|
+
variables: { email }
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
return result.data.customers.edges[0]?.node.id || null;
|
|
981
|
+
}
|
|
982
|
+
};
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
---
|
|
986
|
+
|
|
987
|
+
### Pattern: Transform Array Items
|
|
988
|
+
|
|
989
|
+
**Problem:** Transform each item in an array.
|
|
990
|
+
|
|
991
|
+
**Solution:**
|
|
992
|
+
|
|
993
|
+
```typescript
|
|
994
|
+
{
|
|
995
|
+
"items": {
|
|
996
|
+
"_array": true,
|
|
997
|
+
"source": "order.items",
|
|
998
|
+
"fields": {
|
|
999
|
+
"sku": { "source": "product-id" },
|
|
1000
|
+
"quantity": {
|
|
1001
|
+
"source": "qty",
|
|
1002
|
+
"resolver": "sdk.parseInt" // Transform each item's qty
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
---
|
|
1010
|
+
|
|
1011
|
+
## 💡 Pro Tips
|
|
1012
|
+
|
|
1013
|
+
### Tip 1: Use Safe Helpers
|
|
1014
|
+
|
|
1015
|
+
```typescript
|
|
1016
|
+
// ❌ Don't do this
|
|
1017
|
+
const value = data.order.customer.email; // Crashes if order is null
|
|
1018
|
+
|
|
1019
|
+
// ✅ Use get() helper
|
|
1020
|
+
import { get } from '@fluentcommerce/fc-connect-sdk';
|
|
1021
|
+
const value = get(data, 'order.customer.email'); // Returns undefined safely
|
|
1022
|
+
|
|
1023
|
+
// Or use helpers.get() in resolvers
|
|
1024
|
+
const value = helpers.get(data, 'order.customer.email');
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
### Tip 2: Always Validate Resolver Inputs
|
|
1028
|
+
|
|
1029
|
+
```typescript
|
|
1030
|
+
const myResolver = (value, sourceData, config, helpers) => {
|
|
1031
|
+
// Validate inputs
|
|
1032
|
+
if (value == null) {
|
|
1033
|
+
helpers.logger?.warn('Resolver received null value');
|
|
1034
|
+
return null;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// Your logic
|
|
1038
|
+
return value.toUpperCase();
|
|
1039
|
+
};
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
### Tip 3: Use defaultValue for Required Fields
|
|
1043
|
+
|
|
1044
|
+
```typescript
|
|
1045
|
+
// Instead of crashing on missing data
|
|
1046
|
+
{
|
|
1047
|
+
"ref": {
|
|
1048
|
+
"source": "order.ref",
|
|
1049
|
+
"required": true,
|
|
1050
|
+
"defaultValue": () => `ORDER-${Date.now()}` // Generate if missing
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
### Tip 4: Save Intermediate Results
|
|
1056
|
+
|
|
1057
|
+
```typescript
|
|
1058
|
+
// Add to your workflow for debugging
|
|
1059
|
+
fs.writeFileSync('01-source-data.json', JSON.stringify(sourceData, null, 2));
|
|
1060
|
+
fs.writeFileSync('02-mapped-variables.json', JSON.stringify(result.variables, null, 2));
|
|
1061
|
+
fs.writeFileSync('03-mutation.graphql', result.mutation);
|
|
1062
|
+
fs.writeFileSync('04-response.json', JSON.stringify(response, null, 2));
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
---
|
|
1066
|
+
|
|
1067
|
+
## 🔗 Related Documentation
|
|
1068
|
+
|
|
1069
|
+
- [Error Handling Guide](../02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md) - Complete error reference
|
|
1070
|
+
- [Custom Resolvers Guide](../02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md) - How to write resolvers
|
|
1071
|
+
- [Path Syntax Reference](../02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md) - Understanding paths
|
|
1072
|
+
- [Decision Tree](./decision-tree.md) - Which approach to use
|
|
1073
|
+
|
|
1074
|
+
---
|
|
1075
|
+
|
|
1076
|
+
## 📞 Still Stuck?
|
|
1077
|
+
|
|
1078
|
+
If you've tried everything above and still have issues:
|
|
1079
|
+
|
|
1080
|
+
1. **Check Examples:** Look in `docs/01-TEMPLATES/` for similar scenarios
|
|
1081
|
+
2. **Enable Full Debug Logging:** Capture all SDK output
|
|
1082
|
+
3. **Save All Intermediate Data:** Source → Parsed → Mapped → Response
|
|
1083
|
+
4. **Test in Isolation:** Remove resolvers, simplify mapping, add back one at a time
|
|
1084
|
+
5. **Check GraphQL Schema:** Validate mutation in GraphQL playground first
|
|
1085
|
+
|
|
1086
|
+
**Remember:** 90% of issues are path resolution or null values. Start there!
|