@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,637 +1,637 @@
|
|
|
1
|
-
# Module 3: Intermediate Scenarios
|
|
2
|
-
|
|
3
|
-
**Level:** Intermediate
|
|
4
|
-
**Estimated Time:** 45 minutes
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This module covers intermediate connector scenarios including S3 Parquet processing, JSON order creation, and advanced validation patterns. You'll learn how to handle different file formats and more complex data structures.
|
|
9
|
-
|
|
10
|
-
## Learning Objectives
|
|
11
|
-
|
|
12
|
-
By the end of this module, you will:
|
|
13
|
-
|
|
14
|
-
- ✅ Build S3 Parquet to Fluent product catalog sync
|
|
15
|
-
- ✅ Process SFTP JSON files for order creation
|
|
16
|
-
- ✅ Implement schema-based validation
|
|
17
|
-
- ✅ Handle nested data transformations
|
|
18
|
-
- ✅ Use GraphQL mutations for complex entity creation
|
|
19
|
-
- ✅ Implement proper enrichment and data augmentation
|
|
20
|
-
|
|
21
|
-
## Scenario 2: S3 Parquet to Fluent Product Catalog
|
|
22
|
-
|
|
23
|
-
**Goal:** Read product data from Parquet files in S3, enrich with additional data, and update Fluent product catalog.
|
|
24
|
-
|
|
25
|
-
**Complexity:** Medium
|
|
26
|
-
**Components:** S3DataSource, ParquetParserService, UniversalMapper, FluentClient
|
|
27
|
-
**Estimated Lines:** ~200 lines
|
|
28
|
-
|
|
29
|
-
### Problem Statement
|
|
30
|
-
|
|
31
|
-
Your data warehouse exports product catalog as Parquet files to S3 daily. You need to:
|
|
32
|
-
|
|
33
|
-
1. Read Parquet files from S3
|
|
34
|
-
2. Parse columnar format efficiently
|
|
35
|
-
3. Enrich with calculated fields
|
|
36
|
-
4. Transform nested attributes
|
|
37
|
-
5. Send to Fluent as product updates
|
|
38
|
-
|
|
39
|
-
### Complete Implementation
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
import {
|
|
43
|
-
createClient,
|
|
44
|
-
S3DataSource,
|
|
45
|
-
ParquetParserService,
|
|
46
|
-
UniversalMapper,
|
|
47
|
-
createConsoleLogger,
|
|
48
|
-
toStructuredLogger
|
|
49
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
50
|
-
|
|
51
|
-
// Configuration
|
|
52
|
-
const config = {
|
|
53
|
-
s3: {
|
|
54
|
-
bucketName: 'product-data-lake',
|
|
55
|
-
region: 'us-east-1',
|
|
56
|
-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
57
|
-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
58
|
-
prefix: 'products/daily/',
|
|
59
|
-
},
|
|
60
|
-
fluent: {
|
|
61
|
-
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
62
|
-
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
63
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
64
|
-
username: process.env.FLUENT_USERNAME!,
|
|
65
|
-
password: process.env.FLUENT_PASSWORD!,
|
|
66
|
-
retailerId: process.env.FLUENT_RETAILER_ID!,
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const logger = toStructuredLogger(createConsoleLogger(), {
|
|
71
|
-
logLevel: 'info'
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Initialize S3 Data Source
|
|
75
|
-
const s3Source = new S3DataSource(
|
|
76
|
-
{
|
|
77
|
-
type: 'S3_PARQUET',
|
|
78
|
-
connectionId: 's3-products',
|
|
79
|
-
name: 'Product Data Lake',
|
|
80
|
-
settings: {
|
|
81
|
-
...config.s3,
|
|
82
|
-
filePattern: '*.parquet',
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
logger
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// Initialize Parquet Parser
|
|
89
|
-
const parquetParser = new ParquetParserService(logger);
|
|
90
|
-
|
|
91
|
-
// Field Mapping with enrichment
|
|
92
|
-
const fieldMapper = new UniversalMapper({
|
|
93
|
-
fields: {
|
|
94
|
-
ref: {
|
|
95
|
-
source: 'product_id',
|
|
96
|
-
resolver: value => `PROD-${value}`,
|
|
97
|
-
},
|
|
98
|
-
name: {
|
|
99
|
-
source: 'product_name',
|
|
100
|
-
resolver: 'sdk.trim',
|
|
101
|
-
},
|
|
102
|
-
type: {
|
|
103
|
-
source: 'category',
|
|
104
|
-
resolver: 'sdk.uppercase',
|
|
105
|
-
},
|
|
106
|
-
standardPrice: {
|
|
107
|
-
source: 'price',
|
|
108
|
-
resolver: value => ({
|
|
109
|
-
value: parseFloat(value),
|
|
110
|
-
currency: 'USD',
|
|
111
|
-
}),
|
|
112
|
-
},
|
|
113
|
-
'attributes.weight': {
|
|
114
|
-
source: 'weight',
|
|
115
|
-
resolver: value => ({
|
|
116
|
-
value: parseFloat(value),
|
|
117
|
-
unit: 'kg',
|
|
118
|
-
}),
|
|
119
|
-
},
|
|
120
|
-
'attributes.dimensions': {
|
|
121
|
-
source: 'dimensions',
|
|
122
|
-
resolver: value => {
|
|
123
|
-
const [l, w, h] = value.split('x').map(Number);
|
|
124
|
-
return {
|
|
125
|
-
length: l,
|
|
126
|
-
width: w,
|
|
127
|
-
height: h,
|
|
128
|
-
unit: 'cm',
|
|
129
|
-
};
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Create Fluent Client
|
|
136
|
-
const fluentClient = await createClient({ config: config.fluent });
|
|
137
|
-
|
|
138
|
-
async function syncProductCatalog() {
|
|
139
|
-
logger.info('Starting product catalog sync from S3 Parquet files');
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
// List Parquet files from S3
|
|
143
|
-
const files = await s3Source.listFiles({
|
|
144
|
-
prefix: 'products/daily/',
|
|
145
|
-
filePattern: '*.parquet',
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
logger.info(`Found ${files.length} Parquet files`);
|
|
149
|
-
|
|
150
|
-
for (const file of files) {
|
|
151
|
-
logger.info(`Processing: ${file.name}`);
|
|
152
|
-
|
|
153
|
-
// Download Parquet file
|
|
154
|
-
const buffer = await s3Source.downloadFile(file.name);
|
|
155
|
-
|
|
156
|
-
// Parse Parquet data
|
|
157
|
-
const records = await parquetParser.parse(buffer, {
|
|
158
|
-
columns: ['product_id', 'product_name', 'category', 'price', 'weight', 'dimensions'],
|
|
159
|
-
maxRows: 10000,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
logger.info(`Parsed ${records.length} products`);
|
|
163
|
-
|
|
164
|
-
// Transform records
|
|
165
|
-
const products = [];
|
|
166
|
-
for (const record of records) {
|
|
167
|
-
const result = await fieldMapper.map(record);
|
|
168
|
-
if (!result.success) {
|
|
169
|
-
logger.warn('Mapping errors', result.errors);
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Add additional enrichment
|
|
174
|
-
products.push({
|
|
175
|
-
...result.data,
|
|
176
|
-
status: 'ACTIVE',
|
|
177
|
-
gtin: generateGTIN(result.data.ref),
|
|
178
|
-
catalogueRef: 'MAIN_CATALOG',
|
|
179
|
-
attributes: {
|
|
180
|
-
...result.data.attributes,
|
|
181
|
-
source: 'S3_PARQUET',
|
|
182
|
-
lastUpdated: new Date().toISOString(),
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// GraphQL mutation for product creation/update
|
|
188
|
-
const mutation = `
|
|
189
|
-
mutation UpsertProducts($products: [ProductInput]!) {
|
|
190
|
-
upsertProducts(input: { products: $products }) {
|
|
191
|
-
created
|
|
192
|
-
updated
|
|
193
|
-
failed
|
|
194
|
-
errors {
|
|
195
|
-
ref
|
|
196
|
-
message
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
`;
|
|
201
|
-
|
|
202
|
-
const result = await fluentClient.graphql({ query: mutation, variables: { products } });
|
|
203
|
-
|
|
204
|
-
logger.info('Product sync result:', result);
|
|
205
|
-
|
|
206
|
-
// Archive processed file
|
|
207
|
-
await s3Source.moveFile(
|
|
208
|
-
file.name,
|
|
209
|
-
`products/archive/${new Date().toISOString().split('T')[0]}/${file.name}`
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
logger.info('Product catalog sync completed');
|
|
214
|
-
} catch (error) {
|
|
215
|
-
logger.error('Product sync failed:', error);
|
|
216
|
-
throw error;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Helper function for GTIN generation
|
|
221
|
-
function generateGTIN(ref: string): string {
|
|
222
|
-
// Simple GTIN generation (in production, use proper algorithm)
|
|
223
|
-
const hash = ref.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
224
|
-
return `0${String(hash).padStart(13, '0')}`.slice(0, 14);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Execute
|
|
228
|
-
syncProductCatalog();
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Key Concepts: Parquet Processing
|
|
232
|
-
|
|
233
|
-
**Why Parquet?**
|
|
234
|
-
|
|
235
|
-
- Columnar format (efficient for analytics)
|
|
236
|
-
- Compressed (smaller file sizes)
|
|
237
|
-
- Typed data (enforces schema)
|
|
238
|
-
- Fast reading (only read needed columns)
|
|
239
|
-
|
|
240
|
-
**Reading Parquet:**
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
const records = await parquetParser.parse(buffer, {
|
|
244
|
-
columns: ['product_id', 'product_name', 'price'], // Only read these columns
|
|
245
|
-
maxRows: 10000, // Limit for safety
|
|
246
|
-
});
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
**Nested Field Mapping:**
|
|
250
|
-
|
|
251
|
-
```typescript
|
|
252
|
-
// Map flat field to nested structure
|
|
253
|
-
'attributes.weight': {
|
|
254
|
-
source: 'weight',
|
|
255
|
-
resolver: (value) => ({
|
|
256
|
-
value: parseFloat(value),
|
|
257
|
-
unit: 'kg'
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Result: { attributes: { weight: { value: 10.5, unit: 'kg' } } }
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## Scenario 3: SFTP JSON to Fluent Order Creation
|
|
265
|
-
|
|
266
|
-
**Goal:** Process order JSON files from SFTP and create orders in Fluent Commerce.
|
|
267
|
-
|
|
268
|
-
**Complexity:** Medium
|
|
269
|
-
**Components:** SftpDataSource, JSONParserService, SchemaValidationService
|
|
270
|
-
**Estimated Lines:** ~300 lines
|
|
271
|
-
|
|
272
|
-
### Problem Statement
|
|
273
|
-
|
|
274
|
-
Your e-commerce platform exports orders as JSON files to SFTP. Each order contains:
|
|
275
|
-
|
|
276
|
-
- Order ID and customer details
|
|
277
|
-
- Line items with SKUs and quantities
|
|
278
|
-
- Shipping address
|
|
279
|
-
- Pricing information
|
|
280
|
-
|
|
281
|
-
You need to validate the structure and create orders in Fluent.
|
|
282
|
-
|
|
283
|
-
### JSON Order Format
|
|
284
|
-
|
|
285
|
-
```json
|
|
286
|
-
{
|
|
287
|
-
"orderId": "ORD-12345",
|
|
288
|
-
"customer": {
|
|
289
|
-
"email": "customer@example.com",
|
|
290
|
-
"firstName": "John",
|
|
291
|
-
"lastName": "Doe",
|
|
292
|
-
"phone": "+1234567890"
|
|
293
|
-
},
|
|
294
|
-
"items": [
|
|
295
|
-
{
|
|
296
|
-
"sku": "PROD-001",
|
|
297
|
-
"quantity": 2,
|
|
298
|
-
"price": 29.99
|
|
299
|
-
}
|
|
300
|
-
],
|
|
301
|
-
"total": 59.98,
|
|
302
|
-
"tax": 5.4,
|
|
303
|
-
"shippingAddress": {
|
|
304
|
-
"street": "123 Main St",
|
|
305
|
-
"city": "New York",
|
|
306
|
-
"postcode": "10001",
|
|
307
|
-
"country": "US"
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### Complete Implementation
|
|
313
|
-
|
|
314
|
-
```typescript
|
|
315
|
-
import {
|
|
316
|
-
createClient,
|
|
317
|
-
SftpDataSource,
|
|
318
|
-
SchemaValidationService,
|
|
319
|
-
createConsoleLogger,
|
|
320
|
-
toStructuredLogger
|
|
321
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
322
|
-
|
|
323
|
-
const logger = toStructuredLogger(createConsoleLogger(), {
|
|
324
|
-
logLevel: 'info'
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
// SFTP Configuration for JSON files
|
|
328
|
-
const sftpSource = new SftpDataSource(
|
|
329
|
-
{
|
|
330
|
-
type: 'SFTP_JSON',
|
|
331
|
-
connectionId: 'orders-sftp',
|
|
332
|
-
name: 'Orders SFTP',
|
|
333
|
-
settings: {
|
|
334
|
-
host: process.env.SFTP_HOST!,
|
|
335
|
-
username: process.env.SFTP_USERNAME!,
|
|
336
|
-
password: process.env.SFTP_PASSWORD!,
|
|
337
|
-
remotePath: '/orders/new',
|
|
338
|
-
filePattern: 'ORDER_*.json',
|
|
339
|
-
jsonValidate: true,
|
|
340
|
-
jsonFormat: 'json',
|
|
341
|
-
},
|
|
342
|
-
},
|
|
343
|
-
logger
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
// Fluent Client
|
|
347
|
-
const fluentClient = await createClient({
|
|
348
|
-
config: {
|
|
349
|
-
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
350
|
-
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
351
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
352
|
-
username: process.env.FLUENT_USERNAME!,
|
|
353
|
-
password: process.env.FLUENT_PASSWORD!,
|
|
354
|
-
retailerId: process.env.FLUENT_RETAILER_ID!,
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
// Custom validation function for order data
|
|
359
|
-
// Note: SchemaValidationService validates GraphQL payloads against Fluent schema
|
|
360
|
-
// For JSON data validation, use custom logic or third-party libraries
|
|
361
|
-
function validateOrder(order: any): { valid: boolean; errors: string[] } {
|
|
362
|
-
const errors: string[] = [];
|
|
363
|
-
|
|
364
|
-
if (!order.orderId) errors.push('orderId is required');
|
|
365
|
-
if (!order.customer?.email) errors.push('customer.email is required');
|
|
366
|
-
if (!order.items || order.items.length === 0) errors.push('items array is required');
|
|
367
|
-
if (order.total === undefined) errors.push('total is required');
|
|
368
|
-
|
|
369
|
-
return { valid: errors.length === 0, errors };
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Initialize GraphQL schema validator (for validating mutations to Fluent)
|
|
373
|
-
const schemaValidator = new SchemaValidationService(fluentClient);
|
|
374
|
-
|
|
375
|
-
async function processOrders() {
|
|
376
|
-
logger.info('Starting order processing from SFTP');
|
|
377
|
-
|
|
378
|
-
try {
|
|
379
|
-
// List JSON order files
|
|
380
|
-
const files = await sftpSource.listFiles({
|
|
381
|
-
filePattern: 'ORDER_*.json',
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
logger.info(`Found ${files.length} order files`);
|
|
385
|
-
|
|
386
|
-
for (const file of files) {
|
|
387
|
-
logger.info(`Processing order file: ${file.name}`);
|
|
388
|
-
|
|
389
|
-
try {
|
|
390
|
-
// Download JSON file
|
|
391
|
-
const content = await sftpSource.downloadFile(file.name);
|
|
392
|
-
|
|
393
|
-
// Parse JSON
|
|
394
|
-
const orderData = JSON.parse(content.toString());
|
|
395
|
-
|
|
396
|
-
// Validate order data
|
|
397
|
-
const validationResult = validateOrder(orderData);
|
|
398
|
-
if (!validationResult.valid) {
|
|
399
|
-
logger.error('Order validation failed:', validationResult.errors);
|
|
400
|
-
throw new Error(`Invalid order data: ${validationResult.errors.join(', ')}`);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Transform to Fluent order format
|
|
404
|
-
const fluentOrder = {
|
|
405
|
-
ref: orderData.orderId,
|
|
406
|
-
type: 'HD',
|
|
407
|
-
retailer: { id: process.env.FLUENT_RETAILER_ID },
|
|
408
|
-
customer: {
|
|
409
|
-
email: orderData.customer.email,
|
|
410
|
-
firstName: orderData.customer.firstName,
|
|
411
|
-
lastName: orderData.customer.lastName,
|
|
412
|
-
phone: orderData.customer.phone,
|
|
413
|
-
},
|
|
414
|
-
fulfilmentChoice: {
|
|
415
|
-
deliveryType: 'STANDARD',
|
|
416
|
-
deliveryAddress: {
|
|
417
|
-
street: orderData.shippingAddress.street,
|
|
418
|
-
city: orderData.shippingAddress.city,
|
|
419
|
-
postcode: orderData.shippingAddress.postcode,
|
|
420
|
-
state: orderData.shippingAddress.state || '',
|
|
421
|
-
country: orderData.shippingAddress.country,
|
|
422
|
-
},
|
|
423
|
-
},
|
|
424
|
-
items: orderData.items.map((item, index) => ({
|
|
425
|
-
ref: `${orderData.orderId}-${index + 1}`,
|
|
426
|
-
productRef: item.sku,
|
|
427
|
-
quantity: item.quantity,
|
|
428
|
-
price: item.price,
|
|
429
|
-
totalPrice: item.quantity * item.price,
|
|
430
|
-
currency: 'USD',
|
|
431
|
-
})),
|
|
432
|
-
totalPrice: orderData.total,
|
|
433
|
-
totalTaxPrice: orderData.tax || 0,
|
|
434
|
-
attributes: {
|
|
435
|
-
source: 'SFTP_JSON',
|
|
436
|
-
originalFile: file.name,
|
|
437
|
-
processedAt: new Date().toISOString(),
|
|
438
|
-
},
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
// Direct GraphQL mutation
|
|
442
|
-
const mutation = `
|
|
443
|
-
mutation CreateOrder($input: CreateOrderInput!) {
|
|
444
|
-
createOrder(input: $input) {
|
|
445
|
-
id
|
|
446
|
-
ref
|
|
447
|
-
status
|
|
448
|
-
createdOn
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
`;
|
|
452
|
-
|
|
453
|
-
const mutationResult = await fluentClient.graphql({
|
|
454
|
-
query: mutation,
|
|
455
|
-
variables: { input: fluentOrder },
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
logger.info('Order created via mutation:', mutationResult);
|
|
459
|
-
|
|
460
|
-
// Archive processed file
|
|
461
|
-
await sftpSource.moveFile(
|
|
462
|
-
`/orders/new/${file.name}`,
|
|
463
|
-
`/orders/processed/${file.name}`,
|
|
464
|
-
false
|
|
465
|
-
);
|
|
466
|
-
} catch (error) {
|
|
467
|
-
logger.error(`Failed to process order ${file.name}:`, error);
|
|
468
|
-
|
|
469
|
-
// Move to error folder
|
|
470
|
-
await sftpSource.moveFile(`/orders/new/${file.name}`, `/orders/failed/${file.name}`, true);
|
|
471
|
-
|
|
472
|
-
// Create error report
|
|
473
|
-
const errorReport = {
|
|
474
|
-
file: file.name,
|
|
475
|
-
error: (error as Error).message,
|
|
476
|
-
timestamp: new Date().toISOString(),
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
await sftpSource.uploadFile(
|
|
480
|
-
`/orders/errors/${file.name}.error.json`,
|
|
481
|
-
JSON.stringify(errorReport)
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
logger.info('Order processing completed');
|
|
487
|
-
} catch (error) {
|
|
488
|
-
logger.error('Order processing failed:', error);
|
|
489
|
-
throw error;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// Execute
|
|
494
|
-
processOrders();
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### Key Concepts: JSON Processing and Validation
|
|
498
|
-
|
|
499
|
-
**Schema-Based Validation:**
|
|
500
|
-
|
|
501
|
-
```typescript
|
|
502
|
-
const orderSchema = {
|
|
503
|
-
type: 'object',
|
|
504
|
-
required: ['orderId', 'customer', 'items'],
|
|
505
|
-
properties: {
|
|
506
|
-
orderId: { type: 'string' },
|
|
507
|
-
items: {
|
|
508
|
-
type: 'array',
|
|
509
|
-
minItems: 1,
|
|
510
|
-
items: {
|
|
511
|
-
required: ['sku', 'quantity'],
|
|
512
|
-
properties: {
|
|
513
|
-
sku: { type: 'string' },
|
|
514
|
-
quantity: { type: 'number', minimum: 1 },
|
|
515
|
-
},
|
|
516
|
-
},
|
|
517
|
-
},
|
|
518
|
-
},
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
// Custom validation function (JSON schema validation not built into SDK)
|
|
522
|
-
function validateOrder(data: any) {
|
|
523
|
-
const errors: string[] = [];
|
|
524
|
-
if (!data.orderId) errors.push('orderId required');
|
|
525
|
-
if (!data.items?.length) errors.push('items array required');
|
|
526
|
-
return { valid: errors.length === 0, errors };
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const result = validateOrder(orderData);
|
|
530
|
-
if (!result.valid) {
|
|
531
|
-
console.error('Validation errors:', result.errors);
|
|
532
|
-
}
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
**Nested Data Transformation:**
|
|
536
|
-
|
|
537
|
-
```typescript
|
|
538
|
-
// Transform nested items array
|
|
539
|
-
items: orderData.items.map((item, index) => ({
|
|
540
|
-
ref: `${orderData.orderId}-${index + 1}`, // Generate item ref
|
|
541
|
-
productRef: item.sku,
|
|
542
|
-
quantity: item.quantity,
|
|
543
|
-
price: item.price,
|
|
544
|
-
totalPrice: item.quantity * item.price, // Calculate total
|
|
545
|
-
currency: 'USD',
|
|
546
|
-
}));
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
**Error Reporting:**
|
|
550
|
-
|
|
551
|
-
```typescript
|
|
552
|
-
catch (error) {
|
|
553
|
-
// Create detailed error report
|
|
554
|
-
const errorReport = {
|
|
555
|
-
file: file.name,
|
|
556
|
-
error: error.message,
|
|
557
|
-
timestamp: new Date().toISOString(),
|
|
558
|
-
orderData: content.toString() // Include original data
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
// Save error report for investigation
|
|
562
|
-
await sftpSource.uploadFile(
|
|
563
|
-
`/orders/errors/${file.name}.error.json`,
|
|
564
|
-
JSON.stringify(errorReport)
|
|
565
|
-
);
|
|
566
|
-
}
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
## Comparison: Batch API vs GraphQL Mutations
|
|
570
|
-
|
|
571
|
-
| Feature | Batch API | GraphQL Mutations |
|
|
572
|
-
| --------------------- | ----------------------------- | ------------------------------------------ |
|
|
573
|
-
| **Best For** | High-volume inventory updates | Complex entity creation (orders, products) |
|
|
574
|
-
| **Entity Types** | INVENTORY only | All entity types |
|
|
575
|
-
| **Batch Size** | Up to 10,000 records | Typically 50-100 at a time |
|
|
576
|
-
| **Field Flexibility** | Limited fields | Full entity schema |
|
|
577
|
-
| **Validation** | Server-side | Schema validation |
|
|
578
|
-
| **Performance** | Optimized for bulk | Better for complex data |
|
|
579
|
-
| **Error Handling** | Batch-level errors | Detailed field-level errors |
|
|
580
|
-
|
|
581
|
-
## Practice Exercise
|
|
582
|
-
|
|
583
|
-
**Challenge:** Add data enrichment to the product sync
|
|
584
|
-
|
|
585
|
-
**Requirements:**
|
|
586
|
-
|
|
587
|
-
1. Calculate product availability from external API
|
|
588
|
-
2. Add image URLs from CDN (based on product ID)
|
|
589
|
-
3. Add category hierarchy lookup
|
|
590
|
-
4. Include custom attributes for searchability
|
|
591
|
-
|
|
592
|
-
**Solution approach:**
|
|
593
|
-
|
|
594
|
-
```typescript
|
|
595
|
-
// Enrichment function
|
|
596
|
-
async function enrichProduct(product: any) {
|
|
597
|
-
// 1. Fetch availability from external API
|
|
598
|
-
const availability = await fetchAvailability(product.ref);
|
|
599
|
-
|
|
600
|
-
// 2. Generate CDN image URLs
|
|
601
|
-
const images = [
|
|
602
|
-
`https://cdn.example.com/products/${product.ref}/main.jpg`,
|
|
603
|
-
`https://cdn.example.com/products/${product.ref}/thumb.jpg`,
|
|
604
|
-
];
|
|
605
|
-
|
|
606
|
-
// 3. Lookup category hierarchy
|
|
607
|
-
const categoryPath = await lookupCategoryHierarchy(product.type);
|
|
608
|
-
|
|
609
|
-
return {
|
|
610
|
-
...product,
|
|
611
|
-
availability,
|
|
612
|
-
images,
|
|
613
|
-
categories: categoryPath,
|
|
614
|
-
attributes: {
|
|
615
|
-
...product.attributes,
|
|
616
|
-
searchable: true,
|
|
617
|
-
enrichedAt: new Date().toISOString(),
|
|
618
|
-
},
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// Apply enrichment
|
|
623
|
-
const enrichedProducts = await Promise.all(products.map(p => enrichProduct(p)));
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
## Key Takeaways
|
|
627
|
-
|
|
628
|
-
- 🎯 Parquet format is efficient for large datasets (columnar, compressed)
|
|
629
|
-
- 🎯 JSON Schema validation catches structural errors early
|
|
630
|
-
- 🎯 Nested data transformations require careful mapping
|
|
631
|
-
- 🎯 GraphQL mutations provide full flexibility for complex entities
|
|
632
|
-
- 🎯 Enrichment adds value (calculated fields, external data)
|
|
633
|
-
- 🎯 Error reports should include context for debugging
|
|
634
|
-
|
|
635
|
-
## Next Steps
|
|
636
|
-
|
|
637
|
-
Continue to [Module 4: Advanced Scenarios](./connector-scenarios-04-advanced-scenarios.md) to learn state management, multi-source aggregation, and streaming patterns.
|
|
1
|
+
# Module 3: Intermediate Scenarios
|
|
2
|
+
|
|
3
|
+
**Level:** Intermediate
|
|
4
|
+
**Estimated Time:** 45 minutes
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
This module covers intermediate connector scenarios including S3 Parquet processing, JSON order creation, and advanced validation patterns. You'll learn how to handle different file formats and more complex data structures.
|
|
9
|
+
|
|
10
|
+
## Learning Objectives
|
|
11
|
+
|
|
12
|
+
By the end of this module, you will:
|
|
13
|
+
|
|
14
|
+
- ✅ Build S3 Parquet to Fluent product catalog sync
|
|
15
|
+
- ✅ Process SFTP JSON files for order creation
|
|
16
|
+
- ✅ Implement schema-based validation
|
|
17
|
+
- ✅ Handle nested data transformations
|
|
18
|
+
- ✅ Use GraphQL mutations for complex entity creation
|
|
19
|
+
- ✅ Implement proper enrichment and data augmentation
|
|
20
|
+
|
|
21
|
+
## Scenario 2: S3 Parquet to Fluent Product Catalog
|
|
22
|
+
|
|
23
|
+
**Goal:** Read product data from Parquet files in S3, enrich with additional data, and update Fluent product catalog.
|
|
24
|
+
|
|
25
|
+
**Complexity:** Medium
|
|
26
|
+
**Components:** S3DataSource, ParquetParserService, UniversalMapper, FluentClient
|
|
27
|
+
**Estimated Lines:** ~200 lines
|
|
28
|
+
|
|
29
|
+
### Problem Statement
|
|
30
|
+
|
|
31
|
+
Your data warehouse exports product catalog as Parquet files to S3 daily. You need to:
|
|
32
|
+
|
|
33
|
+
1. Read Parquet files from S3
|
|
34
|
+
2. Parse columnar format efficiently
|
|
35
|
+
3. Enrich with calculated fields
|
|
36
|
+
4. Transform nested attributes
|
|
37
|
+
5. Send to Fluent as product updates
|
|
38
|
+
|
|
39
|
+
### Complete Implementation
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import {
|
|
43
|
+
createClient,
|
|
44
|
+
S3DataSource,
|
|
45
|
+
ParquetParserService,
|
|
46
|
+
UniversalMapper,
|
|
47
|
+
createConsoleLogger,
|
|
48
|
+
toStructuredLogger
|
|
49
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
50
|
+
|
|
51
|
+
// Configuration
|
|
52
|
+
const config = {
|
|
53
|
+
s3: {
|
|
54
|
+
bucketName: 'product-data-lake',
|
|
55
|
+
region: 'us-east-1',
|
|
56
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
57
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
58
|
+
prefix: 'products/daily/',
|
|
59
|
+
},
|
|
60
|
+
fluent: {
|
|
61
|
+
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
62
|
+
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
63
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
64
|
+
username: process.env.FLUENT_USERNAME!,
|
|
65
|
+
password: process.env.FLUENT_PASSWORD!,
|
|
66
|
+
retailerId: process.env.FLUENT_RETAILER_ID!,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const logger = toStructuredLogger(createConsoleLogger(), {
|
|
71
|
+
logLevel: 'info'
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Initialize S3 Data Source
|
|
75
|
+
const s3Source = new S3DataSource(
|
|
76
|
+
{
|
|
77
|
+
type: 'S3_PARQUET',
|
|
78
|
+
connectionId: 's3-products',
|
|
79
|
+
name: 'Product Data Lake',
|
|
80
|
+
settings: {
|
|
81
|
+
...config.s3,
|
|
82
|
+
filePattern: '*.parquet',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
logger
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Initialize Parquet Parser
|
|
89
|
+
const parquetParser = new ParquetParserService(logger);
|
|
90
|
+
|
|
91
|
+
// Field Mapping with enrichment
|
|
92
|
+
const fieldMapper = new UniversalMapper({
|
|
93
|
+
fields: {
|
|
94
|
+
ref: {
|
|
95
|
+
source: 'product_id',
|
|
96
|
+
resolver: value => `PROD-${value}`,
|
|
97
|
+
},
|
|
98
|
+
name: {
|
|
99
|
+
source: 'product_name',
|
|
100
|
+
resolver: 'sdk.trim',
|
|
101
|
+
},
|
|
102
|
+
type: {
|
|
103
|
+
source: 'category',
|
|
104
|
+
resolver: 'sdk.uppercase',
|
|
105
|
+
},
|
|
106
|
+
standardPrice: {
|
|
107
|
+
source: 'price',
|
|
108
|
+
resolver: value => ({
|
|
109
|
+
value: parseFloat(value),
|
|
110
|
+
currency: 'USD',
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
'attributes.weight': {
|
|
114
|
+
source: 'weight',
|
|
115
|
+
resolver: value => ({
|
|
116
|
+
value: parseFloat(value),
|
|
117
|
+
unit: 'kg',
|
|
118
|
+
}),
|
|
119
|
+
},
|
|
120
|
+
'attributes.dimensions': {
|
|
121
|
+
source: 'dimensions',
|
|
122
|
+
resolver: value => {
|
|
123
|
+
const [l, w, h] = value.split('x').map(Number);
|
|
124
|
+
return {
|
|
125
|
+
length: l,
|
|
126
|
+
width: w,
|
|
127
|
+
height: h,
|
|
128
|
+
unit: 'cm',
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Create Fluent Client
|
|
136
|
+
const fluentClient = await createClient({ config: config.fluent });
|
|
137
|
+
|
|
138
|
+
async function syncProductCatalog() {
|
|
139
|
+
logger.info('Starting product catalog sync from S3 Parquet files');
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
// List Parquet files from S3
|
|
143
|
+
const files = await s3Source.listFiles({
|
|
144
|
+
prefix: 'products/daily/',
|
|
145
|
+
filePattern: '*.parquet',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
logger.info(`Found ${files.length} Parquet files`);
|
|
149
|
+
|
|
150
|
+
for (const file of files) {
|
|
151
|
+
logger.info(`Processing: ${file.name}`);
|
|
152
|
+
|
|
153
|
+
// Download Parquet file
|
|
154
|
+
const buffer = await s3Source.downloadFile(file.name);
|
|
155
|
+
|
|
156
|
+
// Parse Parquet data
|
|
157
|
+
const records = await parquetParser.parse(buffer, {
|
|
158
|
+
columns: ['product_id', 'product_name', 'category', 'price', 'weight', 'dimensions'],
|
|
159
|
+
maxRows: 10000,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
logger.info(`Parsed ${records.length} products`);
|
|
163
|
+
|
|
164
|
+
// Transform records
|
|
165
|
+
const products = [];
|
|
166
|
+
for (const record of records) {
|
|
167
|
+
const result = await fieldMapper.map(record);
|
|
168
|
+
if (!result.success) {
|
|
169
|
+
logger.warn('Mapping errors', result.errors);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Add additional enrichment
|
|
174
|
+
products.push({
|
|
175
|
+
...result.data,
|
|
176
|
+
status: 'ACTIVE',
|
|
177
|
+
gtin: generateGTIN(result.data.ref),
|
|
178
|
+
catalogueRef: 'MAIN_CATALOG',
|
|
179
|
+
attributes: {
|
|
180
|
+
...result.data.attributes,
|
|
181
|
+
source: 'S3_PARQUET',
|
|
182
|
+
lastUpdated: new Date().toISOString(),
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// GraphQL mutation for product creation/update
|
|
188
|
+
const mutation = `
|
|
189
|
+
mutation UpsertProducts($products: [ProductInput]!) {
|
|
190
|
+
upsertProducts(input: { products: $products }) {
|
|
191
|
+
created
|
|
192
|
+
updated
|
|
193
|
+
failed
|
|
194
|
+
errors {
|
|
195
|
+
ref
|
|
196
|
+
message
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
const result = await fluentClient.graphql({ query: mutation, variables: { products } });
|
|
203
|
+
|
|
204
|
+
logger.info('Product sync result:', result);
|
|
205
|
+
|
|
206
|
+
// Archive processed file
|
|
207
|
+
await s3Source.moveFile(
|
|
208
|
+
file.name,
|
|
209
|
+
`products/archive/${new Date().toISOString().split('T')[0]}/${file.name}`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
logger.info('Product catalog sync completed');
|
|
214
|
+
} catch (error) {
|
|
215
|
+
logger.error('Product sync failed:', error);
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Helper function for GTIN generation
|
|
221
|
+
function generateGTIN(ref: string): string {
|
|
222
|
+
// Simple GTIN generation (in production, use proper algorithm)
|
|
223
|
+
const hash = ref.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
224
|
+
return `0${String(hash).padStart(13, '0')}`.slice(0, 14);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Execute
|
|
228
|
+
syncProductCatalog();
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Key Concepts: Parquet Processing
|
|
232
|
+
|
|
233
|
+
**Why Parquet?**
|
|
234
|
+
|
|
235
|
+
- Columnar format (efficient for analytics)
|
|
236
|
+
- Compressed (smaller file sizes)
|
|
237
|
+
- Typed data (enforces schema)
|
|
238
|
+
- Fast reading (only read needed columns)
|
|
239
|
+
|
|
240
|
+
**Reading Parquet:**
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
const records = await parquetParser.parse(buffer, {
|
|
244
|
+
columns: ['product_id', 'product_name', 'price'], // Only read these columns
|
|
245
|
+
maxRows: 10000, // Limit for safety
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Nested Field Mapping:**
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
// Map flat field to nested structure
|
|
253
|
+
'attributes.weight': {
|
|
254
|
+
source: 'weight',
|
|
255
|
+
resolver: (value) => ({
|
|
256
|
+
value: parseFloat(value),
|
|
257
|
+
unit: 'kg'
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Result: { attributes: { weight: { value: 10.5, unit: 'kg' } } }
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Scenario 3: SFTP JSON to Fluent Order Creation
|
|
265
|
+
|
|
266
|
+
**Goal:** Process order JSON files from SFTP and create orders in Fluent Commerce.
|
|
267
|
+
|
|
268
|
+
**Complexity:** Medium
|
|
269
|
+
**Components:** SftpDataSource, JSONParserService, SchemaValidationService
|
|
270
|
+
**Estimated Lines:** ~300 lines
|
|
271
|
+
|
|
272
|
+
### Problem Statement
|
|
273
|
+
|
|
274
|
+
Your e-commerce platform exports orders as JSON files to SFTP. Each order contains:
|
|
275
|
+
|
|
276
|
+
- Order ID and customer details
|
|
277
|
+
- Line items with SKUs and quantities
|
|
278
|
+
- Shipping address
|
|
279
|
+
- Pricing information
|
|
280
|
+
|
|
281
|
+
You need to validate the structure and create orders in Fluent.
|
|
282
|
+
|
|
283
|
+
### JSON Order Format
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"orderId": "ORD-12345",
|
|
288
|
+
"customer": {
|
|
289
|
+
"email": "customer@example.com",
|
|
290
|
+
"firstName": "John",
|
|
291
|
+
"lastName": "Doe",
|
|
292
|
+
"phone": "+1234567890"
|
|
293
|
+
},
|
|
294
|
+
"items": [
|
|
295
|
+
{
|
|
296
|
+
"sku": "PROD-001",
|
|
297
|
+
"quantity": 2,
|
|
298
|
+
"price": 29.99
|
|
299
|
+
}
|
|
300
|
+
],
|
|
301
|
+
"total": 59.98,
|
|
302
|
+
"tax": 5.4,
|
|
303
|
+
"shippingAddress": {
|
|
304
|
+
"street": "123 Main St",
|
|
305
|
+
"city": "New York",
|
|
306
|
+
"postcode": "10001",
|
|
307
|
+
"country": "US"
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Complete Implementation
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import {
|
|
316
|
+
createClient,
|
|
317
|
+
SftpDataSource,
|
|
318
|
+
SchemaValidationService,
|
|
319
|
+
createConsoleLogger,
|
|
320
|
+
toStructuredLogger
|
|
321
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
322
|
+
|
|
323
|
+
const logger = toStructuredLogger(createConsoleLogger(), {
|
|
324
|
+
logLevel: 'info'
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// SFTP Configuration for JSON files
|
|
328
|
+
const sftpSource = new SftpDataSource(
|
|
329
|
+
{
|
|
330
|
+
type: 'SFTP_JSON',
|
|
331
|
+
connectionId: 'orders-sftp',
|
|
332
|
+
name: 'Orders SFTP',
|
|
333
|
+
settings: {
|
|
334
|
+
host: process.env.SFTP_HOST!,
|
|
335
|
+
username: process.env.SFTP_USERNAME!,
|
|
336
|
+
password: process.env.SFTP_PASSWORD!,
|
|
337
|
+
remotePath: '/orders/new',
|
|
338
|
+
filePattern: 'ORDER_*.json',
|
|
339
|
+
jsonValidate: true,
|
|
340
|
+
jsonFormat: 'json',
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
logger
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
// Fluent Client
|
|
347
|
+
const fluentClient = await createClient({
|
|
348
|
+
config: {
|
|
349
|
+
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
350
|
+
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
351
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
352
|
+
username: process.env.FLUENT_USERNAME!,
|
|
353
|
+
password: process.env.FLUENT_PASSWORD!,
|
|
354
|
+
retailerId: process.env.FLUENT_RETAILER_ID!,
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Custom validation function for order data
|
|
359
|
+
// Note: SchemaValidationService validates GraphQL payloads against Fluent schema
|
|
360
|
+
// For JSON data validation, use custom logic or third-party libraries
|
|
361
|
+
function validateOrder(order: any): { valid: boolean; errors: string[] } {
|
|
362
|
+
const errors: string[] = [];
|
|
363
|
+
|
|
364
|
+
if (!order.orderId) errors.push('orderId is required');
|
|
365
|
+
if (!order.customer?.email) errors.push('customer.email is required');
|
|
366
|
+
if (!order.items || order.items.length === 0) errors.push('items array is required');
|
|
367
|
+
if (order.total === undefined) errors.push('total is required');
|
|
368
|
+
|
|
369
|
+
return { valid: errors.length === 0, errors };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Initialize GraphQL schema validator (for validating mutations to Fluent)
|
|
373
|
+
const schemaValidator = new SchemaValidationService(fluentClient);
|
|
374
|
+
|
|
375
|
+
async function processOrders() {
|
|
376
|
+
logger.info('Starting order processing from SFTP');
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
// List JSON order files
|
|
380
|
+
const files = await sftpSource.listFiles({
|
|
381
|
+
filePattern: 'ORDER_*.json',
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
logger.info(`Found ${files.length} order files`);
|
|
385
|
+
|
|
386
|
+
for (const file of files) {
|
|
387
|
+
logger.info(`Processing order file: ${file.name}`);
|
|
388
|
+
|
|
389
|
+
try {
|
|
390
|
+
// Download JSON file
|
|
391
|
+
const content = await sftpSource.downloadFile(file.name);
|
|
392
|
+
|
|
393
|
+
// Parse JSON
|
|
394
|
+
const orderData = JSON.parse(content.toString());
|
|
395
|
+
|
|
396
|
+
// Validate order data
|
|
397
|
+
const validationResult = validateOrder(orderData);
|
|
398
|
+
if (!validationResult.valid) {
|
|
399
|
+
logger.error('Order validation failed:', validationResult.errors);
|
|
400
|
+
throw new Error(`Invalid order data: ${validationResult.errors.join(', ')}`);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Transform to Fluent order format
|
|
404
|
+
const fluentOrder = {
|
|
405
|
+
ref: orderData.orderId,
|
|
406
|
+
type: 'HD',
|
|
407
|
+
retailer: { id: process.env.FLUENT_RETAILER_ID },
|
|
408
|
+
customer: {
|
|
409
|
+
email: orderData.customer.email,
|
|
410
|
+
firstName: orderData.customer.firstName,
|
|
411
|
+
lastName: orderData.customer.lastName,
|
|
412
|
+
phone: orderData.customer.phone,
|
|
413
|
+
},
|
|
414
|
+
fulfilmentChoice: {
|
|
415
|
+
deliveryType: 'STANDARD',
|
|
416
|
+
deliveryAddress: {
|
|
417
|
+
street: orderData.shippingAddress.street,
|
|
418
|
+
city: orderData.shippingAddress.city,
|
|
419
|
+
postcode: orderData.shippingAddress.postcode,
|
|
420
|
+
state: orderData.shippingAddress.state || '',
|
|
421
|
+
country: orderData.shippingAddress.country,
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
items: orderData.items.map((item, index) => ({
|
|
425
|
+
ref: `${orderData.orderId}-${index + 1}`,
|
|
426
|
+
productRef: item.sku,
|
|
427
|
+
quantity: item.quantity,
|
|
428
|
+
price: item.price,
|
|
429
|
+
totalPrice: item.quantity * item.price,
|
|
430
|
+
currency: 'USD',
|
|
431
|
+
})),
|
|
432
|
+
totalPrice: orderData.total,
|
|
433
|
+
totalTaxPrice: orderData.tax || 0,
|
|
434
|
+
attributes: {
|
|
435
|
+
source: 'SFTP_JSON',
|
|
436
|
+
originalFile: file.name,
|
|
437
|
+
processedAt: new Date().toISOString(),
|
|
438
|
+
},
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// Direct GraphQL mutation
|
|
442
|
+
const mutation = `
|
|
443
|
+
mutation CreateOrder($input: CreateOrderInput!) {
|
|
444
|
+
createOrder(input: $input) {
|
|
445
|
+
id
|
|
446
|
+
ref
|
|
447
|
+
status
|
|
448
|
+
createdOn
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
`;
|
|
452
|
+
|
|
453
|
+
const mutationResult = await fluentClient.graphql({
|
|
454
|
+
query: mutation,
|
|
455
|
+
variables: { input: fluentOrder },
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
logger.info('Order created via mutation:', mutationResult);
|
|
459
|
+
|
|
460
|
+
// Archive processed file
|
|
461
|
+
await sftpSource.moveFile(
|
|
462
|
+
`/orders/new/${file.name}`,
|
|
463
|
+
`/orders/processed/${file.name}`,
|
|
464
|
+
false
|
|
465
|
+
);
|
|
466
|
+
} catch (error) {
|
|
467
|
+
logger.error(`Failed to process order ${file.name}:`, error);
|
|
468
|
+
|
|
469
|
+
// Move to error folder
|
|
470
|
+
await sftpSource.moveFile(`/orders/new/${file.name}`, `/orders/failed/${file.name}`, true);
|
|
471
|
+
|
|
472
|
+
// Create error report
|
|
473
|
+
const errorReport = {
|
|
474
|
+
file: file.name,
|
|
475
|
+
error: (error as Error).message,
|
|
476
|
+
timestamp: new Date().toISOString(),
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
await sftpSource.uploadFile(
|
|
480
|
+
`/orders/errors/${file.name}.error.json`,
|
|
481
|
+
JSON.stringify(errorReport)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
logger.info('Order processing completed');
|
|
487
|
+
} catch (error) {
|
|
488
|
+
logger.error('Order processing failed:', error);
|
|
489
|
+
throw error;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Execute
|
|
494
|
+
processOrders();
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Key Concepts: JSON Processing and Validation
|
|
498
|
+
|
|
499
|
+
**Schema-Based Validation:**
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
const orderSchema = {
|
|
503
|
+
type: 'object',
|
|
504
|
+
required: ['orderId', 'customer', 'items'],
|
|
505
|
+
properties: {
|
|
506
|
+
orderId: { type: 'string' },
|
|
507
|
+
items: {
|
|
508
|
+
type: 'array',
|
|
509
|
+
minItems: 1,
|
|
510
|
+
items: {
|
|
511
|
+
required: ['sku', 'quantity'],
|
|
512
|
+
properties: {
|
|
513
|
+
sku: { type: 'string' },
|
|
514
|
+
quantity: { type: 'number', minimum: 1 },
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
// Custom validation function (JSON schema validation not built into SDK)
|
|
522
|
+
function validateOrder(data: any) {
|
|
523
|
+
const errors: string[] = [];
|
|
524
|
+
if (!data.orderId) errors.push('orderId required');
|
|
525
|
+
if (!data.items?.length) errors.push('items array required');
|
|
526
|
+
return { valid: errors.length === 0, errors };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const result = validateOrder(orderData);
|
|
530
|
+
if (!result.valid) {
|
|
531
|
+
console.error('Validation errors:', result.errors);
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Nested Data Transformation:**
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
// Transform nested items array
|
|
539
|
+
items: orderData.items.map((item, index) => ({
|
|
540
|
+
ref: `${orderData.orderId}-${index + 1}`, // Generate item ref
|
|
541
|
+
productRef: item.sku,
|
|
542
|
+
quantity: item.quantity,
|
|
543
|
+
price: item.price,
|
|
544
|
+
totalPrice: item.quantity * item.price, // Calculate total
|
|
545
|
+
currency: 'USD',
|
|
546
|
+
}));
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Error Reporting:**
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
catch (error) {
|
|
553
|
+
// Create detailed error report
|
|
554
|
+
const errorReport = {
|
|
555
|
+
file: file.name,
|
|
556
|
+
error: error.message,
|
|
557
|
+
timestamp: new Date().toISOString(),
|
|
558
|
+
orderData: content.toString() // Include original data
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
// Save error report for investigation
|
|
562
|
+
await sftpSource.uploadFile(
|
|
563
|
+
`/orders/errors/${file.name}.error.json`,
|
|
564
|
+
JSON.stringify(errorReport)
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Comparison: Batch API vs GraphQL Mutations
|
|
570
|
+
|
|
571
|
+
| Feature | Batch API | GraphQL Mutations |
|
|
572
|
+
| --------------------- | ----------------------------- | ------------------------------------------ |
|
|
573
|
+
| **Best For** | High-volume inventory updates | Complex entity creation (orders, products) |
|
|
574
|
+
| **Entity Types** | INVENTORY only | All entity types |
|
|
575
|
+
| **Batch Size** | Up to 10,000 records | Typically 50-100 at a time |
|
|
576
|
+
| **Field Flexibility** | Limited fields | Full entity schema |
|
|
577
|
+
| **Validation** | Server-side | Schema validation |
|
|
578
|
+
| **Performance** | Optimized for bulk | Better for complex data |
|
|
579
|
+
| **Error Handling** | Batch-level errors | Detailed field-level errors |
|
|
580
|
+
|
|
581
|
+
## Practice Exercise
|
|
582
|
+
|
|
583
|
+
**Challenge:** Add data enrichment to the product sync
|
|
584
|
+
|
|
585
|
+
**Requirements:**
|
|
586
|
+
|
|
587
|
+
1. Calculate product availability from external API
|
|
588
|
+
2. Add image URLs from CDN (based on product ID)
|
|
589
|
+
3. Add category hierarchy lookup
|
|
590
|
+
4. Include custom attributes for searchability
|
|
591
|
+
|
|
592
|
+
**Solution approach:**
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
// Enrichment function
|
|
596
|
+
async function enrichProduct(product: any) {
|
|
597
|
+
// 1. Fetch availability from external API
|
|
598
|
+
const availability = await fetchAvailability(product.ref);
|
|
599
|
+
|
|
600
|
+
// 2. Generate CDN image URLs
|
|
601
|
+
const images = [
|
|
602
|
+
`https://cdn.example.com/products/${product.ref}/main.jpg`,
|
|
603
|
+
`https://cdn.example.com/products/${product.ref}/thumb.jpg`,
|
|
604
|
+
];
|
|
605
|
+
|
|
606
|
+
// 3. Lookup category hierarchy
|
|
607
|
+
const categoryPath = await lookupCategoryHierarchy(product.type);
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
...product,
|
|
611
|
+
availability,
|
|
612
|
+
images,
|
|
613
|
+
categories: categoryPath,
|
|
614
|
+
attributes: {
|
|
615
|
+
...product.attributes,
|
|
616
|
+
searchable: true,
|
|
617
|
+
enrichedAt: new Date().toISOString(),
|
|
618
|
+
},
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Apply enrichment
|
|
623
|
+
const enrichedProducts = await Promise.all(products.map(p => enrichProduct(p)));
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
## Key Takeaways
|
|
627
|
+
|
|
628
|
+
- 🎯 Parquet format is efficient for large datasets (columnar, compressed)
|
|
629
|
+
- 🎯 JSON Schema validation catches structural errors early
|
|
630
|
+
- 🎯 Nested data transformations require careful mapping
|
|
631
|
+
- 🎯 GraphQL mutations provide full flexibility for complex entities
|
|
632
|
+
- 🎯 Enrichment adds value (calculated fields, external data)
|
|
633
|
+
- 🎯 Error reports should include context for debugging
|
|
634
|
+
|
|
635
|
+
## Next Steps
|
|
636
|
+
|
|
637
|
+
Continue to [Module 4: Advanced Scenarios](./connector-scenarios-04-advanced-scenarios.md) to learn state management, multi-source aggregation, and streaming patterns.
|