@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,692 +1,692 @@
|
|
|
1
|
-
# Module 7: Optimization & Best Practices
|
|
2
|
-
|
|
3
|
-
**Level:** Advanced
|
|
4
|
-
**Estimated Time:** 25 minutes
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This module covers performance optimization, caching strategies, error handling, monitoring, and production best practices for data extraction workflows.
|
|
9
|
-
|
|
10
|
-
## Learning Objectives
|
|
11
|
-
|
|
12
|
-
By the end of this module, you will:
|
|
13
|
-
- ✅ Optimize GraphQL queries for performance
|
|
14
|
-
- ✅ Implement caching strategies
|
|
15
|
-
- ✅ Handle errors and implement retry logic
|
|
16
|
-
- ✅ Monitor extraction performance
|
|
17
|
-
- ✅ Implement delta (incremental) extraction
|
|
18
|
-
- ✅ Apply production best practices
|
|
19
|
-
|
|
20
|
-
## Query Optimization
|
|
21
|
-
|
|
22
|
-
### Field Selection
|
|
23
|
-
|
|
24
|
-
**❌ BAD: Fetch all fields**
|
|
25
|
-
```typescript
|
|
26
|
-
query GetProducts {
|
|
27
|
-
products(first: 100) {
|
|
28
|
-
edges {
|
|
29
|
-
node {
|
|
30
|
-
id ref name description gtin price
|
|
31
|
-
catalogue { id ref name description }
|
|
32
|
-
attributes { name value type }
|
|
33
|
-
categories { edges { node { name path parent { name } } } }
|
|
34
|
-
inventoryPositions { edges { node { qty locationRef } } }
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**✅ GOOD: Fetch only needed fields**
|
|
42
|
-
```typescript
|
|
43
|
-
query GetProducts {
|
|
44
|
-
products(first: 100) {
|
|
45
|
-
edges {
|
|
46
|
-
node {
|
|
47
|
-
ref
|
|
48
|
-
name
|
|
49
|
-
gtin
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Page Size Tuning
|
|
57
|
-
|
|
58
|
-
| Entity Complexity | Recommended Page Size | Rationale |
|
|
59
|
-
|------------------|----------------------|-----------|
|
|
60
|
-
| Simple (5-10 fields) | 100-200 | Small payload per record |
|
|
61
|
-
| Medium (10-20 fields) | 50-100 | Moderate payload |
|
|
62
|
-
| Complex (nested relations) | 20-50 | Large payload, avoid timeouts |
|
|
63
|
-
| Very complex (deep nesting) | 10-20 | Prevent server timeouts |
|
|
64
|
-
|
|
65
|
-
### GraphQL Fragments
|
|
66
|
-
|
|
67
|
-
Reuse field selections:
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
const fragments = `
|
|
71
|
-
fragment ProductFields on Product {
|
|
72
|
-
ref
|
|
73
|
-
name
|
|
74
|
-
gtin
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
fragment LocationFields on Location {
|
|
78
|
-
ref
|
|
79
|
-
name
|
|
80
|
-
type
|
|
81
|
-
}
|
|
82
|
-
`;
|
|
83
|
-
|
|
84
|
-
const query = `
|
|
85
|
-
${fragments}
|
|
86
|
-
|
|
87
|
-
query ExtractInventory($first: Int!, $after: String) {
|
|
88
|
-
inventoryPositions(first: $first, after: $after) {
|
|
89
|
-
edges {
|
|
90
|
-
node {
|
|
91
|
-
ref
|
|
92
|
-
productRef
|
|
93
|
-
locationRef
|
|
94
|
-
qty
|
|
95
|
-
product { ...ProductFields }
|
|
96
|
-
location { ...LocationFields }
|
|
97
|
-
}
|
|
98
|
-
cursor
|
|
99
|
-
}
|
|
100
|
-
pageInfo { hasNextPage }
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Caching Strategies
|
|
107
|
-
|
|
108
|
-
### Simple In-Memory Cache
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
class ExtractionCache {
|
|
112
|
-
private cache = new Map<string, { data: any; expiry: number }>();
|
|
113
|
-
private ttl: number;
|
|
114
|
-
|
|
115
|
-
constructor(ttlMs = 3600000) { // 1 hour default
|
|
116
|
-
this.ttl = ttlMs;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
get(key: string): any | null {
|
|
120
|
-
const cached = this.cache.get(key);
|
|
121
|
-
|
|
122
|
-
if (!cached) return null;
|
|
123
|
-
|
|
124
|
-
if (cached.expiry < Date.now()) {
|
|
125
|
-
this.cache.delete(key);
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return cached.data;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
set(key: string, data: any): void {
|
|
133
|
-
this.cache.set(key, {
|
|
134
|
-
data,
|
|
135
|
-
expiry: Date.now() + this.ttl
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
invalidate(pattern?: string): void {
|
|
140
|
-
if (pattern) {
|
|
141
|
-
for (const key of this.cache.keys()) {
|
|
142
|
-
if (key.includes(pattern)) {
|
|
143
|
-
this.cache.delete(key);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} else {
|
|
147
|
-
this.cache.clear();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Usage
|
|
153
|
-
const cache = new ExtractionCache(3600000);
|
|
154
|
-
|
|
155
|
-
async function getProductWithCache(ref: string) {
|
|
156
|
-
const cacheKey = `product:${ref}`;
|
|
157
|
-
let product = cache.get(cacheKey);
|
|
158
|
-
|
|
159
|
-
if (!product) {
|
|
160
|
-
const result = await client.graphql({
|
|
161
|
-
query: `query { product(ref: "${ref}") { ref name gtin } }`
|
|
162
|
-
});
|
|
163
|
-
product = result.data.product;
|
|
164
|
-
cache.set(cacheKey, product);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return product;
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### Redis-Based Distributed Cache
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
import { createClient as createRedisClient } from 'redis';
|
|
175
|
-
|
|
176
|
-
class DistributedCache {
|
|
177
|
-
private redis: any;
|
|
178
|
-
|
|
179
|
-
async connect() {
|
|
180
|
-
this.redis = createRedisClient({
|
|
181
|
-
url: process.env.REDIS_URL
|
|
182
|
-
});
|
|
183
|
-
await this.redis.connect();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async get(key: string): Promise<any | null> {
|
|
187
|
-
const cached = await this.redis.get(key);
|
|
188
|
-
return cached ? JSON.parse(cached) : null;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async set(key: string, data: any, ttlSeconds = 3600): Promise<void> {
|
|
192
|
-
await this.redis.setEx(key, ttlSeconds, JSON.stringify(data));
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async invalidate(pattern: string): Promise<void> {
|
|
196
|
-
const keys = await this.redis.keys(pattern);
|
|
197
|
-
if (keys.length > 0) {
|
|
198
|
-
await this.redis.del(keys);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
## Delta (Incremental) Extraction
|
|
205
|
-
|
|
206
|
-
### State Management
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
import { StateService, VersoriKVAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
210
|
-
|
|
211
|
-
class DeltaExtractor {
|
|
212
|
-
constructor(
|
|
213
|
-
private client: any,
|
|
214
|
-
private stateService: StateService
|
|
215
|
-
) {}
|
|
216
|
-
|
|
217
|
-
async extractDelta(entityType: string): Promise<any[]> {
|
|
218
|
-
const stateKey = `lastExtraction_${entityType}`;
|
|
219
|
-
|
|
220
|
-
// Get last extraction timestamp
|
|
221
|
-
const lastExtraction = await this.stateService.get(stateKey);
|
|
222
|
-
const fromDate = lastExtraction || this.getDefaultFromDate();
|
|
223
|
-
|
|
224
|
-
console.log(`Extracting ${entityType} changed since ${fromDate}`);
|
|
225
|
-
|
|
226
|
-
// Query only changed records
|
|
227
|
-
const result = await this.client.graphql({
|
|
228
|
-
query: this.buildDeltaQuery(entityType),
|
|
229
|
-
variables: {
|
|
230
|
-
fromDate,
|
|
231
|
-
toDate: new Date().toISOString()
|
|
232
|
-
},
|
|
233
|
-
pagination: { maxRecords: 50000 }
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
const records = this.extractRecords(result, entityType);
|
|
237
|
-
|
|
238
|
-
// Update state
|
|
239
|
-
await this.stateService.set(stateKey, new Date().toISOString());
|
|
240
|
-
|
|
241
|
-
return records;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
private buildDeltaQuery(entityType: string): string {
|
|
245
|
-
const queries: Record<string, string> = {
|
|
246
|
-
inventory: `
|
|
247
|
-
query DeltaInventory($fromDate: DateTime!, $toDate: DateTime!) {
|
|
248
|
-
inventoryPositions(
|
|
249
|
-
updatedOn: { from: $fromDate, to: $toDate }
|
|
250
|
-
first: 100
|
|
251
|
-
) {
|
|
252
|
-
edges {
|
|
253
|
-
node { ref productRef locationRef qty status updatedOn }
|
|
254
|
-
cursor
|
|
255
|
-
}
|
|
256
|
-
pageInfo { hasNextPage }
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
`,
|
|
260
|
-
products: `
|
|
261
|
-
query DeltaProducts($fromDate: DateTime!, $toDate: DateTime!) {
|
|
262
|
-
products(
|
|
263
|
-
updatedOn: { from: $fromDate, to: $toDate }
|
|
264
|
-
first: 100
|
|
265
|
-
) {
|
|
266
|
-
edges {
|
|
267
|
-
node { ref name gtin updatedOn }
|
|
268
|
-
cursor
|
|
269
|
-
}
|
|
270
|
-
pageInfo { hasNextPage }
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
`
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
return queries[entityType] || queries.inventory;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
private extractRecords(result: any, entityType: string): any[] {
|
|
280
|
-
const paths: Record<string, string> = {
|
|
281
|
-
inventory: 'inventoryPositions',
|
|
282
|
-
products: 'products'
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
const path = paths[entityType];
|
|
286
|
-
return result.data[path]?.edges?.map((e: any) => e.node) || [];
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
private getDefaultFromDate(): string {
|
|
290
|
-
// Default to last 24 hours
|
|
291
|
-
const date = new Date();
|
|
292
|
-
date.setDate(date.getDate() - 1);
|
|
293
|
-
return date.toISOString();
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
## Error Handling & Retry Logic
|
|
299
|
-
|
|
300
|
-
### Exponential Backoff Retry
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
class RetryStrategy {
|
|
304
|
-
async executeWithRetry<T>(
|
|
305
|
-
operation: () => Promise<T>,
|
|
306
|
-
maxRetries = 3,
|
|
307
|
-
baseDelay = 1000
|
|
308
|
-
): Promise<T> {
|
|
309
|
-
let lastError: any;
|
|
310
|
-
|
|
311
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
312
|
-
try {
|
|
313
|
-
return await operation();
|
|
314
|
-
} catch (error) {
|
|
315
|
-
lastError = error;
|
|
316
|
-
console.warn(`Attempt ${attempt + 1} failed:`, error.message);
|
|
317
|
-
|
|
318
|
-
if (attempt < maxRetries - 1) {
|
|
319
|
-
const delay = baseDelay * Math.pow(2, attempt);
|
|
320
|
-
console.log(`Retrying in ${delay}ms...`);
|
|
321
|
-
await this.sleep(delay);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
throw new Error(`Operation failed after ${maxRetries} attempts: ${lastError.message}`);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
private sleep(ms: number): Promise<void> {
|
|
330
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Usage
|
|
335
|
-
const retry = new RetryStrategy();
|
|
336
|
-
|
|
337
|
-
const result = await retry.executeWithRetry(async () => {
|
|
338
|
-
return await client.graphql({ query, variables });
|
|
339
|
-
}, 3, 1000);
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Circuit Breaker Pattern
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
class CircuitBreaker {
|
|
346
|
-
private failures = 0;
|
|
347
|
-
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
|
|
348
|
-
private lastFailTime = 0;
|
|
349
|
-
|
|
350
|
-
constructor(
|
|
351
|
-
private threshold = 5,
|
|
352
|
-
private timeout = 60000 // 1 minute
|
|
353
|
-
) {}
|
|
354
|
-
|
|
355
|
-
async execute<T>(operation: () => Promise<T>): Promise<T> {
|
|
356
|
-
if (this.state === 'OPEN') {
|
|
357
|
-
if (Date.now() - this.lastFailTime > this.timeout) {
|
|
358
|
-
this.state = 'HALF_OPEN';
|
|
359
|
-
} else {
|
|
360
|
-
throw new Error('Circuit breaker is OPEN');
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
const result = await operation();
|
|
366
|
-
this.onSuccess();
|
|
367
|
-
return result;
|
|
368
|
-
} catch (error) {
|
|
369
|
-
this.onFailure();
|
|
370
|
-
throw error;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
private onSuccess(): void {
|
|
375
|
-
this.failures = 0;
|
|
376
|
-
this.state = 'CLOSED';
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
private onFailure(): void {
|
|
380
|
-
this.failures++;
|
|
381
|
-
this.lastFailTime = Date.now();
|
|
382
|
-
|
|
383
|
-
if (this.failures >= this.threshold) {
|
|
384
|
-
this.state = 'OPEN';
|
|
385
|
-
console.error('Circuit breaker opened');
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
## Performance Monitoring
|
|
392
|
-
|
|
393
|
-
### Extraction Metrics
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
interface ExtractionMetrics {
|
|
397
|
-
startTime: number;
|
|
398
|
-
endTime: number;
|
|
399
|
-
totalRecords: number;
|
|
400
|
-
totalPages: number;
|
|
401
|
-
errors: number;
|
|
402
|
-
dataSize: number;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
class ExtractionMonitor {
|
|
406
|
-
private metrics: ExtractionMetrics = {
|
|
407
|
-
startTime: 0,
|
|
408
|
-
endTime: 0,
|
|
409
|
-
totalRecords: 0,
|
|
410
|
-
totalPages: 0,
|
|
411
|
-
errors: 0,
|
|
412
|
-
dataSize: 0
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
start(): void {
|
|
416
|
-
this.metrics.startTime = Date.now();
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
recordPage(records: number): void {
|
|
420
|
-
this.metrics.totalRecords += records;
|
|
421
|
-
this.metrics.totalPages++;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
recordError(): void {
|
|
425
|
-
this.metrics.errors++;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
finish(dataSize: number): void {
|
|
429
|
-
this.metrics.endTime = Date.now();
|
|
430
|
-
this.metrics.dataSize = dataSize;
|
|
431
|
-
this.logMetrics();
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
private logMetrics(): void {
|
|
435
|
-
const duration = this.metrics.endTime - this.metrics.startTime;
|
|
436
|
-
const recordsPerSecond = (this.metrics.totalRecords / duration) * 1000;
|
|
437
|
-
const mbPerSecond = (this.metrics.dataSize / duration / 1024 / 1024) * 1000;
|
|
438
|
-
|
|
439
|
-
console.log('=== Extraction Metrics ===');
|
|
440
|
-
console.log(`Duration: ${duration}ms`);
|
|
441
|
-
console.log(`Records: ${this.metrics.totalRecords}`);
|
|
442
|
-
console.log(`Pages: ${this.metrics.totalPages}`);
|
|
443
|
-
console.log(`Errors: ${this.metrics.errors}`);
|
|
444
|
-
console.log(`Data size: ${(this.metrics.dataSize / 1024 / 1024).toFixed(2)} MB`);
|
|
445
|
-
console.log(`Throughput: ${recordsPerSecond.toFixed(0)} records/sec`);
|
|
446
|
-
console.log(`Bandwidth: ${mbPerSecond.toFixed(2)} MB/sec`);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
## Memory Management
|
|
452
|
-
|
|
453
|
-
### Streaming for Large Datasets
|
|
454
|
-
|
|
455
|
-
```typescript
|
|
456
|
-
async function* streamExtraction(query: string, pageSize = 100) {
|
|
457
|
-
let hasNextPage = true;
|
|
458
|
-
let cursor = null;
|
|
459
|
-
let pageCount = 0;
|
|
460
|
-
|
|
461
|
-
while (hasNextPage) {
|
|
462
|
-
const result = await client.graphql({
|
|
463
|
-
query,
|
|
464
|
-
variables: { first: pageSize, after: cursor }
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
const edges = result.data.inventoryPositions.edges;
|
|
468
|
-
yield edges.map(e => e.node);
|
|
469
|
-
|
|
470
|
-
hasNextPage = result.data.inventoryPositions.pageInfo.hasNextPage;
|
|
471
|
-
cursor = edges[edges.length - 1]?.cursor;
|
|
472
|
-
pageCount++;
|
|
473
|
-
|
|
474
|
-
// Force GC every 100 pages
|
|
475
|
-
if (pageCount % 100 === 0 && global.gc) {
|
|
476
|
-
global.gc();
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Process in batches
|
|
482
|
-
for await (const batch of streamExtraction(query)) {
|
|
483
|
-
await processBatch(batch);
|
|
484
|
-
// Batch is garbage collected after processing
|
|
485
|
-
}
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
## Production Best Practices
|
|
489
|
-
|
|
490
|
-
### 1. Comprehensive Logging
|
|
491
|
-
|
|
492
|
-
```typescript
|
|
493
|
-
import {
|
|
494
|
-
createConsoleLogger,
|
|
495
|
-
toStructuredLogger
|
|
496
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
497
|
-
|
|
498
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
499
|
-
|
|
500
|
-
async function productionExtraction() {
|
|
501
|
-
logger.info('Starting extraction', { entityType: 'inventory' });
|
|
502
|
-
|
|
503
|
-
try {
|
|
504
|
-
const result = await client.graphql({ query, variables, pagination });
|
|
505
|
-
|
|
506
|
-
logger.info('Extraction complete', {
|
|
507
|
-
records: result.extensions.autoPagination.totalRecords,
|
|
508
|
-
pages: result.extensions.autoPagination.totalPages,
|
|
509
|
-
duration: result.extensions.autoPagination.timeElapsed
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
return result;
|
|
513
|
-
} catch (error) {
|
|
514
|
-
logger.error('Extraction failed', error as Error, { entityType: 'inventory' });
|
|
515
|
-
throw error;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
### 2. Configuration Management
|
|
521
|
-
|
|
522
|
-
```typescript
|
|
523
|
-
interface ExtractionConfig {
|
|
524
|
-
pageSize: number;
|
|
525
|
-
maxRecords: number;
|
|
526
|
-
maxPages: number;
|
|
527
|
-
timeoutMs: number;
|
|
528
|
-
retryAttempts: number;
|
|
529
|
-
cacheEnabled: boolean;
|
|
530
|
-
cacheTtl: number;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const config: ExtractionConfig = {
|
|
534
|
-
pageSize: parseInt(process.env.PAGE_SIZE || '100'),
|
|
535
|
-
maxRecords: parseInt(process.env.MAX_RECORDS || '50000'),
|
|
536
|
-
maxPages: parseInt(process.env.MAX_PAGES || '500'),
|
|
537
|
-
timeoutMs: parseInt(process.env.TIMEOUT_MS || '300000'),
|
|
538
|
-
retryAttempts: parseInt(process.env.RETRY_ATTEMPTS || '3'),
|
|
539
|
-
cacheEnabled: process.env.CACHE_ENABLED === 'true',
|
|
540
|
-
cacheTtl: parseInt(process.env.CACHE_TTL || '3600000')
|
|
541
|
-
};
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
### 3. Health Checks
|
|
545
|
-
|
|
546
|
-
```typescript
|
|
547
|
-
async function healthCheck(): Promise<boolean> {
|
|
548
|
-
try {
|
|
549
|
-
// Simple query to verify connectivity
|
|
550
|
-
const result = await client.graphql({
|
|
551
|
-
query: `query { products(first: 1) { edges { node { ref } } } }`
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
return !!result.data;
|
|
555
|
-
} catch (error) {
|
|
556
|
-
console.error('Health check failed:', error);
|
|
557
|
-
return false;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
### 4. Rate Limiting
|
|
563
|
-
|
|
564
|
-
```typescript
|
|
565
|
-
class RateLimiter {
|
|
566
|
-
private requests = 0;
|
|
567
|
-
private resetTime = Date.now();
|
|
568
|
-
|
|
569
|
-
constructor(
|
|
570
|
-
private maxRequests = 100,
|
|
571
|
-
private windowMs = 60000 // 1 minute
|
|
572
|
-
) {}
|
|
573
|
-
|
|
574
|
-
async acquire(): Promise<void> {
|
|
575
|
-
if (Date.now() > this.resetTime) {
|
|
576
|
-
this.requests = 0;
|
|
577
|
-
this.resetTime = Date.now() + this.windowMs;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
if (this.requests >= this.maxRequests) {
|
|
581
|
-
const waitTime = this.resetTime - Date.now();
|
|
582
|
-
console.log(`Rate limit reached, waiting ${waitTime}ms`);
|
|
583
|
-
await this.sleep(waitTime);
|
|
584
|
-
this.requests = 0;
|
|
585
|
-
this.resetTime = Date.now() + this.windowMs;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
this.requests++;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
private sleep(ms: number): Promise<void> {
|
|
592
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
## Complete Production Example
|
|
598
|
-
|
|
599
|
-
```typescript
|
|
600
|
-
import {
|
|
601
|
-
createClient,
|
|
602
|
-
UniversalMapper,
|
|
603
|
-
S3DataSource,
|
|
604
|
-
StateService,
|
|
605
|
-
createConsoleLogger,
|
|
606
|
-
toStructuredLogger
|
|
607
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
608
|
-
|
|
609
|
-
async function productionExtractionWorkflow() {
|
|
610
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
611
|
-
const monitor = new ExtractionMonitor();
|
|
612
|
-
const retry = new RetryStrategy();
|
|
613
|
-
const cache = new ExtractionCache();
|
|
614
|
-
|
|
615
|
-
monitor.start();
|
|
616
|
-
|
|
617
|
-
try {
|
|
618
|
-
// Health check
|
|
619
|
-
if (!await healthCheck()) {
|
|
620
|
-
throw new Error('Health check failed');
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// Initialize services
|
|
624
|
-
const client = await createClient({ config });
|
|
625
|
-
const s3 = new S3DataSource(s3Config);
|
|
626
|
-
const state = new StateService(kvAdapter);
|
|
627
|
-
|
|
628
|
-
// Delta extraction
|
|
629
|
-
const deltaExtractor = new DeltaExtractor(client, state);
|
|
630
|
-
const records = await retry.executeWithRetry(async () => {
|
|
631
|
-
return await deltaExtractor.extractDelta('inventory');
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
logger.info(`Extracted ${records.length} changed records`);
|
|
635
|
-
monitor.recordPage(records.length);
|
|
636
|
-
|
|
637
|
-
// Transform
|
|
638
|
-
const mapper = new UniversalMapper(mappingConfig);
|
|
639
|
-
const result = await mapper.map(records);
|
|
640
|
-
|
|
641
|
-
if (!result.success) {
|
|
642
|
-
const transformError = new Error('Transformation failed');
|
|
643
|
-
logger.error('Transformation errors', transformError, { errors: result.errors });
|
|
644
|
-
throw transformError;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// Export
|
|
648
|
-
const output = JSON.stringify(result.data, null, 2);
|
|
649
|
-
await s3.uploadFile(`inventory_delta_${new Date().toISOString()}.json`, output, {
|
|
650
|
-
contentType: 'application/json',
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
monitor.finish(output.length);
|
|
654
|
-
logger.info('Workflow complete');
|
|
655
|
-
|
|
656
|
-
} catch (error) {
|
|
657
|
-
monitor.recordError();
|
|
658
|
-
logger.error('Workflow failed', error as Error);
|
|
659
|
-
throw error;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
## Key Takeaways
|
|
665
|
-
|
|
666
|
-
- 🎯 Select only needed fields to minimize payload size
|
|
667
|
-
- 🎯 Tune page sizes based on entity complexity
|
|
668
|
-
- 🎯 Implement caching for frequently accessed reference data
|
|
669
|
-
- 🎯 Use delta extraction for incremental updates
|
|
670
|
-
- 🎯 Add retry logic with exponential backoff
|
|
671
|
-
- 🎯 Monitor performance metrics (throughput, errors, duration)
|
|
672
|
-
- 🎯 Stream large datasets to avoid memory issues
|
|
673
|
-
- 🎯 Implement comprehensive logging for production
|
|
674
|
-
- 🎯 Use configuration management for flexibility
|
|
675
|
-
- 🎯 Add health checks and rate limiting
|
|
676
|
-
|
|
677
|
-
## Summary
|
|
678
|
-
|
|
679
|
-
You've completed the Data Extraction Learning Path! You now know how to:
|
|
680
|
-
- Extract data from Fluent Commerce using validated GraphQL queries
|
|
681
|
-
- Process Parquet files and enrich with GraphQL data
|
|
682
|
-
- Transform data using UniversalMapper and custom logic
|
|
683
|
-
- Export to multiple formats (JSON, CSV, XML, Parquet)
|
|
684
|
-
- Optimize for performance with caching and streaming
|
|
685
|
-
- Build production-ready extraction workflows
|
|
686
|
-
|
|
687
|
-
## Next Steps
|
|
688
|
-
|
|
689
|
-
- Explore [Auto-Pagination Guide](../../auto-pagination/) for advanced pagination patterns
|
|
690
|
-
- See [Universal Mapping Guide](../../mapping/mapping-readme.md) for complex transformations
|
|
691
|
-
- Review [Use Case Examples](../../../01-TEMPLATES/) for real-world scenarios
|
|
692
|
-
- Check [SDK Architecture](../../../04-REFERENCE/architecture/) for deeper understanding
|
|
1
|
+
# Module 7: Optimization & Best Practices
|
|
2
|
+
|
|
3
|
+
**Level:** Advanced
|
|
4
|
+
**Estimated Time:** 25 minutes
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
This module covers performance optimization, caching strategies, error handling, monitoring, and production best practices for data extraction workflows.
|
|
9
|
+
|
|
10
|
+
## Learning Objectives
|
|
11
|
+
|
|
12
|
+
By the end of this module, you will:
|
|
13
|
+
- ✅ Optimize GraphQL queries for performance
|
|
14
|
+
- ✅ Implement caching strategies
|
|
15
|
+
- ✅ Handle errors and implement retry logic
|
|
16
|
+
- ✅ Monitor extraction performance
|
|
17
|
+
- ✅ Implement delta (incremental) extraction
|
|
18
|
+
- ✅ Apply production best practices
|
|
19
|
+
|
|
20
|
+
## Query Optimization
|
|
21
|
+
|
|
22
|
+
### Field Selection
|
|
23
|
+
|
|
24
|
+
**❌ BAD: Fetch all fields**
|
|
25
|
+
```typescript
|
|
26
|
+
query GetProducts {
|
|
27
|
+
products(first: 100) {
|
|
28
|
+
edges {
|
|
29
|
+
node {
|
|
30
|
+
id ref name description gtin price
|
|
31
|
+
catalogue { id ref name description }
|
|
32
|
+
attributes { name value type }
|
|
33
|
+
categories { edges { node { name path parent { name } } } }
|
|
34
|
+
inventoryPositions { edges { node { qty locationRef } } }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**✅ GOOD: Fetch only needed fields**
|
|
42
|
+
```typescript
|
|
43
|
+
query GetProducts {
|
|
44
|
+
products(first: 100) {
|
|
45
|
+
edges {
|
|
46
|
+
node {
|
|
47
|
+
ref
|
|
48
|
+
name
|
|
49
|
+
gtin
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Page Size Tuning
|
|
57
|
+
|
|
58
|
+
| Entity Complexity | Recommended Page Size | Rationale |
|
|
59
|
+
|------------------|----------------------|-----------|
|
|
60
|
+
| Simple (5-10 fields) | 100-200 | Small payload per record |
|
|
61
|
+
| Medium (10-20 fields) | 50-100 | Moderate payload |
|
|
62
|
+
| Complex (nested relations) | 20-50 | Large payload, avoid timeouts |
|
|
63
|
+
| Very complex (deep nesting) | 10-20 | Prevent server timeouts |
|
|
64
|
+
|
|
65
|
+
### GraphQL Fragments
|
|
66
|
+
|
|
67
|
+
Reuse field selections:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const fragments = `
|
|
71
|
+
fragment ProductFields on Product {
|
|
72
|
+
ref
|
|
73
|
+
name
|
|
74
|
+
gtin
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fragment LocationFields on Location {
|
|
78
|
+
ref
|
|
79
|
+
name
|
|
80
|
+
type
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
const query = `
|
|
85
|
+
${fragments}
|
|
86
|
+
|
|
87
|
+
query ExtractInventory($first: Int!, $after: String) {
|
|
88
|
+
inventoryPositions(first: $first, after: $after) {
|
|
89
|
+
edges {
|
|
90
|
+
node {
|
|
91
|
+
ref
|
|
92
|
+
productRef
|
|
93
|
+
locationRef
|
|
94
|
+
qty
|
|
95
|
+
product { ...ProductFields }
|
|
96
|
+
location { ...LocationFields }
|
|
97
|
+
}
|
|
98
|
+
cursor
|
|
99
|
+
}
|
|
100
|
+
pageInfo { hasNextPage }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Caching Strategies
|
|
107
|
+
|
|
108
|
+
### Simple In-Memory Cache
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
class ExtractionCache {
|
|
112
|
+
private cache = new Map<string, { data: any; expiry: number }>();
|
|
113
|
+
private ttl: number;
|
|
114
|
+
|
|
115
|
+
constructor(ttlMs = 3600000) { // 1 hour default
|
|
116
|
+
this.ttl = ttlMs;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get(key: string): any | null {
|
|
120
|
+
const cached = this.cache.get(key);
|
|
121
|
+
|
|
122
|
+
if (!cached) return null;
|
|
123
|
+
|
|
124
|
+
if (cached.expiry < Date.now()) {
|
|
125
|
+
this.cache.delete(key);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return cached.data;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
set(key: string, data: any): void {
|
|
133
|
+
this.cache.set(key, {
|
|
134
|
+
data,
|
|
135
|
+
expiry: Date.now() + this.ttl
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
invalidate(pattern?: string): void {
|
|
140
|
+
if (pattern) {
|
|
141
|
+
for (const key of this.cache.keys()) {
|
|
142
|
+
if (key.includes(pattern)) {
|
|
143
|
+
this.cache.delete(key);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
this.cache.clear();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Usage
|
|
153
|
+
const cache = new ExtractionCache(3600000);
|
|
154
|
+
|
|
155
|
+
async function getProductWithCache(ref: string) {
|
|
156
|
+
const cacheKey = `product:${ref}`;
|
|
157
|
+
let product = cache.get(cacheKey);
|
|
158
|
+
|
|
159
|
+
if (!product) {
|
|
160
|
+
const result = await client.graphql({
|
|
161
|
+
query: `query { product(ref: "${ref}") { ref name gtin } }`
|
|
162
|
+
});
|
|
163
|
+
product = result.data.product;
|
|
164
|
+
cache.set(cacheKey, product);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return product;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Redis-Based Distributed Cache
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { createClient as createRedisClient } from 'redis';
|
|
175
|
+
|
|
176
|
+
class DistributedCache {
|
|
177
|
+
private redis: any;
|
|
178
|
+
|
|
179
|
+
async connect() {
|
|
180
|
+
this.redis = createRedisClient({
|
|
181
|
+
url: process.env.REDIS_URL
|
|
182
|
+
});
|
|
183
|
+
await this.redis.connect();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async get(key: string): Promise<any | null> {
|
|
187
|
+
const cached = await this.redis.get(key);
|
|
188
|
+
return cached ? JSON.parse(cached) : null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async set(key: string, data: any, ttlSeconds = 3600): Promise<void> {
|
|
192
|
+
await this.redis.setEx(key, ttlSeconds, JSON.stringify(data));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async invalidate(pattern: string): Promise<void> {
|
|
196
|
+
const keys = await this.redis.keys(pattern);
|
|
197
|
+
if (keys.length > 0) {
|
|
198
|
+
await this.redis.del(keys);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Delta (Incremental) Extraction
|
|
205
|
+
|
|
206
|
+
### State Management
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { StateService, VersoriKVAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
210
|
+
|
|
211
|
+
class DeltaExtractor {
|
|
212
|
+
constructor(
|
|
213
|
+
private client: any,
|
|
214
|
+
private stateService: StateService
|
|
215
|
+
) {}
|
|
216
|
+
|
|
217
|
+
async extractDelta(entityType: string): Promise<any[]> {
|
|
218
|
+
const stateKey = `lastExtraction_${entityType}`;
|
|
219
|
+
|
|
220
|
+
// Get last extraction timestamp
|
|
221
|
+
const lastExtraction = await this.stateService.get(stateKey);
|
|
222
|
+
const fromDate = lastExtraction || this.getDefaultFromDate();
|
|
223
|
+
|
|
224
|
+
console.log(`Extracting ${entityType} changed since ${fromDate}`);
|
|
225
|
+
|
|
226
|
+
// Query only changed records
|
|
227
|
+
const result = await this.client.graphql({
|
|
228
|
+
query: this.buildDeltaQuery(entityType),
|
|
229
|
+
variables: {
|
|
230
|
+
fromDate,
|
|
231
|
+
toDate: new Date().toISOString()
|
|
232
|
+
},
|
|
233
|
+
pagination: { maxRecords: 50000 }
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const records = this.extractRecords(result, entityType);
|
|
237
|
+
|
|
238
|
+
// Update state
|
|
239
|
+
await this.stateService.set(stateKey, new Date().toISOString());
|
|
240
|
+
|
|
241
|
+
return records;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private buildDeltaQuery(entityType: string): string {
|
|
245
|
+
const queries: Record<string, string> = {
|
|
246
|
+
inventory: `
|
|
247
|
+
query DeltaInventory($fromDate: DateTime!, $toDate: DateTime!) {
|
|
248
|
+
inventoryPositions(
|
|
249
|
+
updatedOn: { from: $fromDate, to: $toDate }
|
|
250
|
+
first: 100
|
|
251
|
+
) {
|
|
252
|
+
edges {
|
|
253
|
+
node { ref productRef locationRef qty status updatedOn }
|
|
254
|
+
cursor
|
|
255
|
+
}
|
|
256
|
+
pageInfo { hasNextPage }
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
`,
|
|
260
|
+
products: `
|
|
261
|
+
query DeltaProducts($fromDate: DateTime!, $toDate: DateTime!) {
|
|
262
|
+
products(
|
|
263
|
+
updatedOn: { from: $fromDate, to: $toDate }
|
|
264
|
+
first: 100
|
|
265
|
+
) {
|
|
266
|
+
edges {
|
|
267
|
+
node { ref name gtin updatedOn }
|
|
268
|
+
cursor
|
|
269
|
+
}
|
|
270
|
+
pageInfo { hasNextPage }
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
`
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
return queries[entityType] || queries.inventory;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private extractRecords(result: any, entityType: string): any[] {
|
|
280
|
+
const paths: Record<string, string> = {
|
|
281
|
+
inventory: 'inventoryPositions',
|
|
282
|
+
products: 'products'
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const path = paths[entityType];
|
|
286
|
+
return result.data[path]?.edges?.map((e: any) => e.node) || [];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private getDefaultFromDate(): string {
|
|
290
|
+
// Default to last 24 hours
|
|
291
|
+
const date = new Date();
|
|
292
|
+
date.setDate(date.getDate() - 1);
|
|
293
|
+
return date.toISOString();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Error Handling & Retry Logic
|
|
299
|
+
|
|
300
|
+
### Exponential Backoff Retry
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
class RetryStrategy {
|
|
304
|
+
async executeWithRetry<T>(
|
|
305
|
+
operation: () => Promise<T>,
|
|
306
|
+
maxRetries = 3,
|
|
307
|
+
baseDelay = 1000
|
|
308
|
+
): Promise<T> {
|
|
309
|
+
let lastError: any;
|
|
310
|
+
|
|
311
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
312
|
+
try {
|
|
313
|
+
return await operation();
|
|
314
|
+
} catch (error) {
|
|
315
|
+
lastError = error;
|
|
316
|
+
console.warn(`Attempt ${attempt + 1} failed:`, error.message);
|
|
317
|
+
|
|
318
|
+
if (attempt < maxRetries - 1) {
|
|
319
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
320
|
+
console.log(`Retrying in ${delay}ms...`);
|
|
321
|
+
await this.sleep(delay);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
throw new Error(`Operation failed after ${maxRetries} attempts: ${lastError.message}`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private sleep(ms: number): Promise<void> {
|
|
330
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Usage
|
|
335
|
+
const retry = new RetryStrategy();
|
|
336
|
+
|
|
337
|
+
const result = await retry.executeWithRetry(async () => {
|
|
338
|
+
return await client.graphql({ query, variables });
|
|
339
|
+
}, 3, 1000);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Circuit Breaker Pattern
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
class CircuitBreaker {
|
|
346
|
+
private failures = 0;
|
|
347
|
+
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
|
|
348
|
+
private lastFailTime = 0;
|
|
349
|
+
|
|
350
|
+
constructor(
|
|
351
|
+
private threshold = 5,
|
|
352
|
+
private timeout = 60000 // 1 minute
|
|
353
|
+
) {}
|
|
354
|
+
|
|
355
|
+
async execute<T>(operation: () => Promise<T>): Promise<T> {
|
|
356
|
+
if (this.state === 'OPEN') {
|
|
357
|
+
if (Date.now() - this.lastFailTime > this.timeout) {
|
|
358
|
+
this.state = 'HALF_OPEN';
|
|
359
|
+
} else {
|
|
360
|
+
throw new Error('Circuit breaker is OPEN');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
try {
|
|
365
|
+
const result = await operation();
|
|
366
|
+
this.onSuccess();
|
|
367
|
+
return result;
|
|
368
|
+
} catch (error) {
|
|
369
|
+
this.onFailure();
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private onSuccess(): void {
|
|
375
|
+
this.failures = 0;
|
|
376
|
+
this.state = 'CLOSED';
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private onFailure(): void {
|
|
380
|
+
this.failures++;
|
|
381
|
+
this.lastFailTime = Date.now();
|
|
382
|
+
|
|
383
|
+
if (this.failures >= this.threshold) {
|
|
384
|
+
this.state = 'OPEN';
|
|
385
|
+
console.error('Circuit breaker opened');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Performance Monitoring
|
|
392
|
+
|
|
393
|
+
### Extraction Metrics
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
interface ExtractionMetrics {
|
|
397
|
+
startTime: number;
|
|
398
|
+
endTime: number;
|
|
399
|
+
totalRecords: number;
|
|
400
|
+
totalPages: number;
|
|
401
|
+
errors: number;
|
|
402
|
+
dataSize: number;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
class ExtractionMonitor {
|
|
406
|
+
private metrics: ExtractionMetrics = {
|
|
407
|
+
startTime: 0,
|
|
408
|
+
endTime: 0,
|
|
409
|
+
totalRecords: 0,
|
|
410
|
+
totalPages: 0,
|
|
411
|
+
errors: 0,
|
|
412
|
+
dataSize: 0
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
start(): void {
|
|
416
|
+
this.metrics.startTime = Date.now();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
recordPage(records: number): void {
|
|
420
|
+
this.metrics.totalRecords += records;
|
|
421
|
+
this.metrics.totalPages++;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
recordError(): void {
|
|
425
|
+
this.metrics.errors++;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
finish(dataSize: number): void {
|
|
429
|
+
this.metrics.endTime = Date.now();
|
|
430
|
+
this.metrics.dataSize = dataSize;
|
|
431
|
+
this.logMetrics();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private logMetrics(): void {
|
|
435
|
+
const duration = this.metrics.endTime - this.metrics.startTime;
|
|
436
|
+
const recordsPerSecond = (this.metrics.totalRecords / duration) * 1000;
|
|
437
|
+
const mbPerSecond = (this.metrics.dataSize / duration / 1024 / 1024) * 1000;
|
|
438
|
+
|
|
439
|
+
console.log('=== Extraction Metrics ===');
|
|
440
|
+
console.log(`Duration: ${duration}ms`);
|
|
441
|
+
console.log(`Records: ${this.metrics.totalRecords}`);
|
|
442
|
+
console.log(`Pages: ${this.metrics.totalPages}`);
|
|
443
|
+
console.log(`Errors: ${this.metrics.errors}`);
|
|
444
|
+
console.log(`Data size: ${(this.metrics.dataSize / 1024 / 1024).toFixed(2)} MB`);
|
|
445
|
+
console.log(`Throughput: ${recordsPerSecond.toFixed(0)} records/sec`);
|
|
446
|
+
console.log(`Bandwidth: ${mbPerSecond.toFixed(2)} MB/sec`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Memory Management
|
|
452
|
+
|
|
453
|
+
### Streaming for Large Datasets
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
async function* streamExtraction(query: string, pageSize = 100) {
|
|
457
|
+
let hasNextPage = true;
|
|
458
|
+
let cursor = null;
|
|
459
|
+
let pageCount = 0;
|
|
460
|
+
|
|
461
|
+
while (hasNextPage) {
|
|
462
|
+
const result = await client.graphql({
|
|
463
|
+
query,
|
|
464
|
+
variables: { first: pageSize, after: cursor }
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
const edges = result.data.inventoryPositions.edges;
|
|
468
|
+
yield edges.map(e => e.node);
|
|
469
|
+
|
|
470
|
+
hasNextPage = result.data.inventoryPositions.pageInfo.hasNextPage;
|
|
471
|
+
cursor = edges[edges.length - 1]?.cursor;
|
|
472
|
+
pageCount++;
|
|
473
|
+
|
|
474
|
+
// Force GC every 100 pages
|
|
475
|
+
if (pageCount % 100 === 0 && global.gc) {
|
|
476
|
+
global.gc();
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Process in batches
|
|
482
|
+
for await (const batch of streamExtraction(query)) {
|
|
483
|
+
await processBatch(batch);
|
|
484
|
+
// Batch is garbage collected after processing
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## Production Best Practices
|
|
489
|
+
|
|
490
|
+
### 1. Comprehensive Logging
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
import {
|
|
494
|
+
createConsoleLogger,
|
|
495
|
+
toStructuredLogger
|
|
496
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
497
|
+
|
|
498
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
499
|
+
|
|
500
|
+
async function productionExtraction() {
|
|
501
|
+
logger.info('Starting extraction', { entityType: 'inventory' });
|
|
502
|
+
|
|
503
|
+
try {
|
|
504
|
+
const result = await client.graphql({ query, variables, pagination });
|
|
505
|
+
|
|
506
|
+
logger.info('Extraction complete', {
|
|
507
|
+
records: result.extensions.autoPagination.totalRecords,
|
|
508
|
+
pages: result.extensions.autoPagination.totalPages,
|
|
509
|
+
duration: result.extensions.autoPagination.timeElapsed
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
return result;
|
|
513
|
+
} catch (error) {
|
|
514
|
+
logger.error('Extraction failed', error as Error, { entityType: 'inventory' });
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### 2. Configuration Management
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
interface ExtractionConfig {
|
|
524
|
+
pageSize: number;
|
|
525
|
+
maxRecords: number;
|
|
526
|
+
maxPages: number;
|
|
527
|
+
timeoutMs: number;
|
|
528
|
+
retryAttempts: number;
|
|
529
|
+
cacheEnabled: boolean;
|
|
530
|
+
cacheTtl: number;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const config: ExtractionConfig = {
|
|
534
|
+
pageSize: parseInt(process.env.PAGE_SIZE || '100'),
|
|
535
|
+
maxRecords: parseInt(process.env.MAX_RECORDS || '50000'),
|
|
536
|
+
maxPages: parseInt(process.env.MAX_PAGES || '500'),
|
|
537
|
+
timeoutMs: parseInt(process.env.TIMEOUT_MS || '300000'),
|
|
538
|
+
retryAttempts: parseInt(process.env.RETRY_ATTEMPTS || '3'),
|
|
539
|
+
cacheEnabled: process.env.CACHE_ENABLED === 'true',
|
|
540
|
+
cacheTtl: parseInt(process.env.CACHE_TTL || '3600000')
|
|
541
|
+
};
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### 3. Health Checks
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
async function healthCheck(): Promise<boolean> {
|
|
548
|
+
try {
|
|
549
|
+
// Simple query to verify connectivity
|
|
550
|
+
const result = await client.graphql({
|
|
551
|
+
query: `query { products(first: 1) { edges { node { ref } } } }`
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
return !!result.data;
|
|
555
|
+
} catch (error) {
|
|
556
|
+
console.error('Health check failed:', error);
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### 4. Rate Limiting
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
class RateLimiter {
|
|
566
|
+
private requests = 0;
|
|
567
|
+
private resetTime = Date.now();
|
|
568
|
+
|
|
569
|
+
constructor(
|
|
570
|
+
private maxRequests = 100,
|
|
571
|
+
private windowMs = 60000 // 1 minute
|
|
572
|
+
) {}
|
|
573
|
+
|
|
574
|
+
async acquire(): Promise<void> {
|
|
575
|
+
if (Date.now() > this.resetTime) {
|
|
576
|
+
this.requests = 0;
|
|
577
|
+
this.resetTime = Date.now() + this.windowMs;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (this.requests >= this.maxRequests) {
|
|
581
|
+
const waitTime = this.resetTime - Date.now();
|
|
582
|
+
console.log(`Rate limit reached, waiting ${waitTime}ms`);
|
|
583
|
+
await this.sleep(waitTime);
|
|
584
|
+
this.requests = 0;
|
|
585
|
+
this.resetTime = Date.now() + this.windowMs;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
this.requests++;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
private sleep(ms: number): Promise<void> {
|
|
592
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
## Complete Production Example
|
|
598
|
+
|
|
599
|
+
```typescript
|
|
600
|
+
import {
|
|
601
|
+
createClient,
|
|
602
|
+
UniversalMapper,
|
|
603
|
+
S3DataSource,
|
|
604
|
+
StateService,
|
|
605
|
+
createConsoleLogger,
|
|
606
|
+
toStructuredLogger
|
|
607
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
608
|
+
|
|
609
|
+
async function productionExtractionWorkflow() {
|
|
610
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
611
|
+
const monitor = new ExtractionMonitor();
|
|
612
|
+
const retry = new RetryStrategy();
|
|
613
|
+
const cache = new ExtractionCache();
|
|
614
|
+
|
|
615
|
+
monitor.start();
|
|
616
|
+
|
|
617
|
+
try {
|
|
618
|
+
// Health check
|
|
619
|
+
if (!await healthCheck()) {
|
|
620
|
+
throw new Error('Health check failed');
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Initialize services
|
|
624
|
+
const client = await createClient({ config });
|
|
625
|
+
const s3 = new S3DataSource(s3Config);
|
|
626
|
+
const state = new StateService(kvAdapter);
|
|
627
|
+
|
|
628
|
+
// Delta extraction
|
|
629
|
+
const deltaExtractor = new DeltaExtractor(client, state);
|
|
630
|
+
const records = await retry.executeWithRetry(async () => {
|
|
631
|
+
return await deltaExtractor.extractDelta('inventory');
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
logger.info(`Extracted ${records.length} changed records`);
|
|
635
|
+
monitor.recordPage(records.length);
|
|
636
|
+
|
|
637
|
+
// Transform
|
|
638
|
+
const mapper = new UniversalMapper(mappingConfig);
|
|
639
|
+
const result = await mapper.map(records);
|
|
640
|
+
|
|
641
|
+
if (!result.success) {
|
|
642
|
+
const transformError = new Error('Transformation failed');
|
|
643
|
+
logger.error('Transformation errors', transformError, { errors: result.errors });
|
|
644
|
+
throw transformError;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Export
|
|
648
|
+
const output = JSON.stringify(result.data, null, 2);
|
|
649
|
+
await s3.uploadFile(`inventory_delta_${new Date().toISOString()}.json`, output, {
|
|
650
|
+
contentType: 'application/json',
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
monitor.finish(output.length);
|
|
654
|
+
logger.info('Workflow complete');
|
|
655
|
+
|
|
656
|
+
} catch (error) {
|
|
657
|
+
monitor.recordError();
|
|
658
|
+
logger.error('Workflow failed', error as Error);
|
|
659
|
+
throw error;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
## Key Takeaways
|
|
665
|
+
|
|
666
|
+
- 🎯 Select only needed fields to minimize payload size
|
|
667
|
+
- 🎯 Tune page sizes based on entity complexity
|
|
668
|
+
- 🎯 Implement caching for frequently accessed reference data
|
|
669
|
+
- 🎯 Use delta extraction for incremental updates
|
|
670
|
+
- 🎯 Add retry logic with exponential backoff
|
|
671
|
+
- 🎯 Monitor performance metrics (throughput, errors, duration)
|
|
672
|
+
- 🎯 Stream large datasets to avoid memory issues
|
|
673
|
+
- 🎯 Implement comprehensive logging for production
|
|
674
|
+
- 🎯 Use configuration management for flexibility
|
|
675
|
+
- 🎯 Add health checks and rate limiting
|
|
676
|
+
|
|
677
|
+
## Summary
|
|
678
|
+
|
|
679
|
+
You've completed the Data Extraction Learning Path! You now know how to:
|
|
680
|
+
- Extract data from Fluent Commerce using validated GraphQL queries
|
|
681
|
+
- Process Parquet files and enrich with GraphQL data
|
|
682
|
+
- Transform data using UniversalMapper and custom logic
|
|
683
|
+
- Export to multiple formats (JSON, CSV, XML, Parquet)
|
|
684
|
+
- Optimize for performance with caching and streaming
|
|
685
|
+
- Build production-ready extraction workflows
|
|
686
|
+
|
|
687
|
+
## Next Steps
|
|
688
|
+
|
|
689
|
+
- Explore [Auto-Pagination Guide](../../auto-pagination/) for advanced pagination patterns
|
|
690
|
+
- See [Universal Mapping Guide](../../mapping/mapping-readme.md) for complex transformations
|
|
691
|
+
- Review [Use Case Examples](../../../01-TEMPLATES/) for real-world scenarios
|
|
692
|
+
- Check [SDK Architecture](../../../04-REFERENCE/architecture/) for deeper understanding
|