@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
- package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md
CHANGED
|
@@ -1,823 +1,823 @@
|
|
|
1
|
-
# Module 2: Basic Extraction
|
|
2
|
-
|
|
3
|
-
**Level:** Beginner
|
|
4
|
-
**Estimated Time:** 20 minutes
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This module teaches you how to perform basic data extraction from Fluent Commerce using validated GraphQL queries and automatic pagination.
|
|
9
|
-
|
|
10
|
-
**Note:** For most extraction use cases, the **ExtractionOrchestrator** (covered in [Module 8](./02-core-guides-extraction-08-extraction-orchestrator.md)) provides a simpler, higher-level API. This module shows the manual approach for cases where you need fine-grained control.
|
|
11
|
-
|
|
12
|
-
## Learning Objectives
|
|
13
|
-
|
|
14
|
-
By the end of this module, you will:
|
|
15
|
-
|
|
16
|
-
- ✅ Write validated GraphQL extraction queries
|
|
17
|
-
- ✅ Use auto-pagination to fetch large datasets
|
|
18
|
-
- ✅ Extract common Fluent entities (inventory, products, orders)
|
|
19
|
-
- ✅ Handle pagination responses correctly
|
|
20
|
-
- ✅ Process extracted data
|
|
21
|
-
- ✅ Understand when to use manual extraction vs ExtractionOrchestrator
|
|
22
|
-
|
|
23
|
-
## Your First Extraction Query
|
|
24
|
-
|
|
25
|
-
### Step 1: Initialize the Client
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
29
|
-
|
|
30
|
-
// Create client (auto-detects Node.js, Deno, or Versori context)
|
|
31
|
-
const client = await createClient({
|
|
32
|
-
config: {
|
|
33
|
-
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
34
|
-
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
35
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
36
|
-
username: process.env.FLUENT_USERNAME!,
|
|
37
|
-
password: process.env.FLUENT_PASSWORD!
|
|
38
|
-
// Note: retailerId is OPTIONAL for GraphQL queries (only required for Job/Event API)
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Step 2: Write a Simple Query
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
const query = `
|
|
47
|
-
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
48
|
-
virtualPositions(first: $first, after: $after) {
|
|
49
|
-
edges {
|
|
50
|
-
node {
|
|
51
|
-
id
|
|
52
|
-
ref
|
|
53
|
-
productRef
|
|
54
|
-
groupRef
|
|
55
|
-
quantity
|
|
56
|
-
status
|
|
57
|
-
createdOn
|
|
58
|
-
updatedOn
|
|
59
|
-
}
|
|
60
|
-
cursor
|
|
61
|
-
}
|
|
62
|
-
pageInfo {
|
|
63
|
-
hasNextPage
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
`;
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**Field Validation:**
|
|
71
|
-
|
|
72
|
-
- ✅ `id` - VirtualPosition.id (ID!)
|
|
73
|
-
- ✅ `ref` - VirtualPosition.ref (String!)
|
|
74
|
-
- ✅ `productRef` - VirtualPosition.productRef (String!)
|
|
75
|
-
- ✅ `groupRef` - VirtualPosition.groupRef (String)
|
|
76
|
-
- ✅ `quantity` - VirtualPosition.quantity (Int!)
|
|
77
|
-
- ✅ `status` - VirtualPosition.status (String)
|
|
78
|
-
|
|
79
|
-
> **⚠️ IMPORTANT: VirtualPosition vs InventoryPosition Field Differences**
|
|
80
|
-
>
|
|
81
|
-
> These two types have **different field names** for quantity:
|
|
82
|
-
> - **VirtualPosition**: Uses `quantity` (Int!)
|
|
83
|
-
> - **InventoryPosition**: Uses `qty` (Int!) and `onHand` (Int!)
|
|
84
|
-
>
|
|
85
|
-
> Always check the GraphQL schema when switching between entity types!
|
|
86
|
-
|
|
87
|
-
### Step 3: Execute with Auto-Pagination
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
const result = await client.graphql({
|
|
91
|
-
query,
|
|
92
|
-
variables: { first: 100 },
|
|
93
|
-
pagination: {
|
|
94
|
-
maxRecords: 10000, // Stop after 10K records
|
|
95
|
-
maxPages: 100, // OR stop after 100 pages
|
|
96
|
-
onProgress: (page, totalRecords) => {
|
|
97
|
-
console.log(`Fetched page ${page}: ${totalRecords} records so far`);
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Step 4: Process the Results
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
// Auto-pagination merges all pages into single response
|
|
107
|
-
const allRecords = result.data.virtualPositions.edges.map(edge => edge.node);
|
|
108
|
-
|
|
109
|
-
console.log(`Total records: ${allRecords.length}`);
|
|
110
|
-
console.log(`Pages fetched: ${result.extensions.pagination.totalPages}`);
|
|
111
|
-
console.log(`Time elapsed: ${result.extensions.pagination.timeElapsed}ms`);
|
|
112
|
-
|
|
113
|
-
// Process each record
|
|
114
|
-
for (const record of allRecords) {
|
|
115
|
-
console.log(`Product ${record.productRef}: ${record.quantity} units`);
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Complete Example
|
|
120
|
-
|
|
121
|
-
### Approach 1: Using ExtractionOrchestrator (Recommended)
|
|
122
|
-
|
|
123
|
-
For most use cases, use the high-level ExtractionOrchestrator:
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
import { createClient, ExtractionOrchestrator } from '@fluentcommerce/fc-connect-sdk';
|
|
127
|
-
|
|
128
|
-
async function extractVirtualPositions() {
|
|
129
|
-
const client = await createClient({
|
|
130
|
-
config: {
|
|
131
|
-
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
132
|
-
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
133
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET!
|
|
134
|
-
// retailerId is OPTIONAL for GraphQL queries (only required for Job/Event API)
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const orchestrator = new ExtractionOrchestrator(client, console);
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const result = await orchestrator.extract({
|
|
142
|
-
query: `
|
|
143
|
-
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
144
|
-
virtualPositions(first: $first, after: $after) {
|
|
145
|
-
edges {
|
|
146
|
-
node {
|
|
147
|
-
id ref productRef groupRef quantity status
|
|
148
|
-
createdOn updatedOn
|
|
149
|
-
}
|
|
150
|
-
cursor
|
|
151
|
-
}
|
|
152
|
-
pageInfo { hasNextPage }
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
`,
|
|
156
|
-
resultPath: 'virtualPositions.edges.node',
|
|
157
|
-
pageSize: 100,
|
|
158
|
-
maxRecords: 10000
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
console.log('\n=== Extraction Summary ===');
|
|
162
|
-
console.log(`Total records: ${result.data.length}`);
|
|
163
|
-
console.log(`Pages: ${result.stats.totalPages}`);
|
|
164
|
-
console.log(`Duration: ${result.stats.duration}ms`);
|
|
165
|
-
|
|
166
|
-
return result.data;
|
|
167
|
-
} catch (error) {
|
|
168
|
-
console.error('Extraction failed:', error);
|
|
169
|
-
throw error;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
extractVirtualPositions()
|
|
174
|
-
.then(() => console.log('Extraction complete'))
|
|
175
|
-
.catch(error => console.error('Error:', error));
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Approach 2: Manual Extraction (For Advanced Control)
|
|
179
|
-
|
|
180
|
-
For fine-grained control over pagination and response handling:
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
184
|
-
|
|
185
|
-
async function extractVirtualPositions() {
|
|
186
|
-
// Initialize client
|
|
187
|
-
const client = await createClient({
|
|
188
|
-
config: {
|
|
189
|
-
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
190
|
-
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
191
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET!
|
|
192
|
-
// retailerId is OPTIONAL for GraphQL queries (only required for Job/Event API)
|
|
193
|
-
},
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Define query
|
|
197
|
-
const query = `
|
|
198
|
-
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
199
|
-
virtualPositions(first: $first, after: $after) {
|
|
200
|
-
edges {
|
|
201
|
-
node {
|
|
202
|
-
id
|
|
203
|
-
ref
|
|
204
|
-
productRef
|
|
205
|
-
groupRef
|
|
206
|
-
quantity
|
|
207
|
-
status
|
|
208
|
-
createdOn
|
|
209
|
-
updatedOn
|
|
210
|
-
}
|
|
211
|
-
cursor
|
|
212
|
-
}
|
|
213
|
-
pageInfo {
|
|
214
|
-
hasNextPage
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
`;
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
// Execute with auto-pagination
|
|
222
|
-
const result = await client.graphql({
|
|
223
|
-
query,
|
|
224
|
-
variables: { first: 100 },
|
|
225
|
-
pagination: {
|
|
226
|
-
maxRecords: 10000,
|
|
227
|
-
onProgress: (page, totalRecords) => {
|
|
228
|
-
console.log(`Page ${page}: ${totalRecords} records`);
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Extract records
|
|
234
|
-
const records = result.data.virtualPositions.edges.map(e => e.node);
|
|
235
|
-
|
|
236
|
-
console.log('\n=== Extraction Summary ===');
|
|
237
|
-
console.log(`Total records: ${records.length}`);
|
|
238
|
-
console.log(`Pages: ${result.extensions.pagination.totalPages}`);
|
|
239
|
-
console.log(`Time: ${result.extensions.pagination.timeElapsed}ms`);
|
|
240
|
-
|
|
241
|
-
// Show sample records
|
|
242
|
-
console.log('\n=== Sample Records ===');
|
|
243
|
-
records.slice(0, 5).forEach(record => {
|
|
244
|
-
console.log(`- ${record.ref}: ${record.quantity} units of ${record.productRef}`);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
return records;
|
|
248
|
-
} catch (error) {
|
|
249
|
-
console.error('Extraction failed:', error);
|
|
250
|
-
throw error;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Run extraction
|
|
255
|
-
extractVirtualPositions()
|
|
256
|
-
.then(() => console.log('Extraction complete'))
|
|
257
|
-
.catch(error => console.error('Error:', error));
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## Common Entity Extractions
|
|
261
|
-
|
|
262
|
-
### 1. Inventory Positions
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
const query = `
|
|
266
|
-
query ExtractInventory($first: Int!, $after: String) {
|
|
267
|
-
inventoryPositions(first: $first, after: $after) {
|
|
268
|
-
edges {
|
|
269
|
-
node {
|
|
270
|
-
id
|
|
271
|
-
ref
|
|
272
|
-
productRef
|
|
273
|
-
locationRef
|
|
274
|
-
qty # ✅ Note: 'qty' not 'quantity'
|
|
275
|
-
status
|
|
276
|
-
createdOn
|
|
277
|
-
updatedOn
|
|
278
|
-
}
|
|
279
|
-
cursor
|
|
280
|
-
}
|
|
281
|
-
pageInfo {
|
|
282
|
-
hasNextPage
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
`;
|
|
287
|
-
|
|
288
|
-
const result = await client.graphql({
|
|
289
|
-
query,
|
|
290
|
-
variables: { first: 100 },
|
|
291
|
-
pagination: { maxRecords: 50000 },
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
const inventory = result.data.inventoryPositions.edges.map(e => e.node);
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### 2. Products
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
const query = `
|
|
301
|
-
query ExtractProducts($first: Int!, $after: String) {
|
|
302
|
-
products(first: $first, after: $after) {
|
|
303
|
-
edges {
|
|
304
|
-
node {
|
|
305
|
-
id
|
|
306
|
-
ref
|
|
307
|
-
name
|
|
308
|
-
gtin
|
|
309
|
-
status
|
|
310
|
-
type
|
|
311
|
-
createdOn
|
|
312
|
-
updatedOn
|
|
313
|
-
}
|
|
314
|
-
cursor
|
|
315
|
-
}
|
|
316
|
-
pageInfo {
|
|
317
|
-
hasNextPage
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
`;
|
|
322
|
-
|
|
323
|
-
const result = await client.graphql({
|
|
324
|
-
query,
|
|
325
|
-
variables: { first: 50 }, // Smaller page size for products
|
|
326
|
-
pagination: { maxRecords: 10000 },
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
const products = result.data.products.edges.map(e => e.node);
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### 3. Orders
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
const query = `
|
|
336
|
-
query ExtractOrders($first: Int!, $after: String) {
|
|
337
|
-
orders(first: $first, after: $after) {
|
|
338
|
-
edges {
|
|
339
|
-
node {
|
|
340
|
-
id
|
|
341
|
-
ref
|
|
342
|
-
type
|
|
343
|
-
status
|
|
344
|
-
totalPrice
|
|
345
|
-
totalTaxPrice
|
|
346
|
-
currency
|
|
347
|
-
createdOn
|
|
348
|
-
updatedOn
|
|
349
|
-
}
|
|
350
|
-
cursor
|
|
351
|
-
}
|
|
352
|
-
pageInfo {
|
|
353
|
-
hasNextPage
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
`;
|
|
358
|
-
|
|
359
|
-
const result = await client.graphql({
|
|
360
|
-
query,
|
|
361
|
-
variables: { first: 50 },
|
|
362
|
-
pagination: { maxRecords: 20000 },
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
const orders = result.data.orders.edges.map(e => e.node);
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### 4. Locations
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
const query = `
|
|
372
|
-
query ExtractLocations($first: Int!, $after: String) {
|
|
373
|
-
locations(first: $first, after: $after) {
|
|
374
|
-
edges {
|
|
375
|
-
node {
|
|
376
|
-
id
|
|
377
|
-
ref
|
|
378
|
-
name
|
|
379
|
-
type
|
|
380
|
-
status
|
|
381
|
-
createdOn
|
|
382
|
-
updatedOn
|
|
383
|
-
}
|
|
384
|
-
cursor
|
|
385
|
-
}
|
|
386
|
-
pageInfo {
|
|
387
|
-
hasNextPage
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
`;
|
|
392
|
-
|
|
393
|
-
const result = await client.graphql({
|
|
394
|
-
query,
|
|
395
|
-
variables: { first: 100 },
|
|
396
|
-
pagination: { maxRecords: 5000 },
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
const locations = result.data.locations.edges.map(e => e.node);
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
## Understanding Pagination Responses
|
|
403
|
-
|
|
404
|
-
### Response Structure
|
|
405
|
-
|
|
406
|
-
```typescript
|
|
407
|
-
{
|
|
408
|
-
data: {
|
|
409
|
-
virtualPositions: {
|
|
410
|
-
edges: [
|
|
411
|
-
{
|
|
412
|
-
node: { id: "1", ref: "VP-001", ... },
|
|
413
|
-
cursor: "abc123"
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
node: { id: "2", ref: "VP-002", ... },
|
|
417
|
-
cursor: "def456"
|
|
418
|
-
}
|
|
419
|
-
],
|
|
420
|
-
pageInfo: {
|
|
421
|
-
hasNextPage: true
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
},
|
|
425
|
-
extensions: {
|
|
426
|
-
autoPagination: {
|
|
427
|
-
totalPages: 15,
|
|
428
|
-
totalRecords: 1487,
|
|
429
|
-
truncated: false,
|
|
430
|
-
timeElapsed: 8324
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### Auto-Pagination Extensions
|
|
437
|
-
|
|
438
|
-
The SDK adds `extensions.autoPagination` metadata:
|
|
439
|
-
|
|
440
|
-
| Field | Type | Description |
|
|
441
|
-
| -------------- | ------- | ------------------------------- |
|
|
442
|
-
| `totalPages` | number | Number of pages fetched |
|
|
443
|
-
| `totalRecords` | number | Total records returned |
|
|
444
|
-
| `truncated` | boolean | True if stopped by safety limit |
|
|
445
|
-
| `duration` | number | Total time in milliseconds |
|
|
446
|
-
|
|
447
|
-
### Accessing Data
|
|
448
|
-
|
|
449
|
-
```typescript
|
|
450
|
-
// Get all records
|
|
451
|
-
const allRecords = result.data.virtualPositions.edges.map(e => e.node);
|
|
452
|
-
|
|
453
|
-
// Check if truncated
|
|
454
|
-
if (result.extensions.pagination.truncated) {
|
|
455
|
-
console.warn('Results truncated by safety limit');
|
|
456
|
-
console.log(`Fetched ${result.extensions.pagination.totalRecords} of total`);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// Performance metrics
|
|
460
|
-
console.log(
|
|
461
|
-
`Fetched ${result.extensions.pagination.totalRecords} records in ${result.extensions.pagination.timeElapsed}ms`
|
|
462
|
-
);
|
|
463
|
-
console.log(
|
|
464
|
-
`Rate: ${((result.extensions.pagination.totalRecords / result.extensions.pagination.timeElapsed) * 1000).toFixed(0)} records/sec`
|
|
465
|
-
);
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
## Filtering Results
|
|
469
|
-
|
|
470
|
-
### GraphQL Filters
|
|
471
|
-
|
|
472
|
-
```typescript
|
|
473
|
-
// Filter by status
|
|
474
|
-
const query = `
|
|
475
|
-
query ExtractActiveInventory($first: Int!, $after: String, $filter: JSON) {
|
|
476
|
-
inventoryPositions(
|
|
477
|
-
first: $first
|
|
478
|
-
after: $after
|
|
479
|
-
filter: $filter
|
|
480
|
-
) {
|
|
481
|
-
edges {
|
|
482
|
-
node { id ref qty status }
|
|
483
|
-
cursor
|
|
484
|
-
}
|
|
485
|
-
pageInfo { hasNextPage }
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
`;
|
|
489
|
-
|
|
490
|
-
const result = await client.graphql({
|
|
491
|
-
query,
|
|
492
|
-
variables: {
|
|
493
|
-
first: 100,
|
|
494
|
-
filter: {
|
|
495
|
-
status: { equalTo: 'AVAILABLE' },
|
|
496
|
-
},
|
|
497
|
-
},
|
|
498
|
-
pagination: { maxRecords: 50000 },
|
|
499
|
-
});
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
### Date Range Filters
|
|
503
|
-
|
|
504
|
-
```typescript
|
|
505
|
-
// Filter by date range
|
|
506
|
-
const fromDate = new Date('2024-01-01').toISOString();
|
|
507
|
-
const toDate = new Date('2024-12-31').toISOString();
|
|
508
|
-
|
|
509
|
-
const query = `
|
|
510
|
-
query ExtractRecentOrders($first: Int!, $after: String, $from: DateTime!, $to: DateTime!) {
|
|
511
|
-
orders(
|
|
512
|
-
first: $first
|
|
513
|
-
after: $after
|
|
514
|
-
createdOn: { from: $from, to: $to }
|
|
515
|
-
) {
|
|
516
|
-
edges {
|
|
517
|
-
node { id ref createdOn totalPrice }
|
|
518
|
-
cursor
|
|
519
|
-
}
|
|
520
|
-
pageInfo { hasNextPage }
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
`;
|
|
524
|
-
|
|
525
|
-
const result = await client.graphql({
|
|
526
|
-
query,
|
|
527
|
-
variables: {
|
|
528
|
-
first: 100,
|
|
529
|
-
from: fromDate,
|
|
530
|
-
to: toDate,
|
|
531
|
-
},
|
|
532
|
-
pagination: { maxRecords: 20000 },
|
|
533
|
-
});
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
### Complex Filters
|
|
537
|
-
|
|
538
|
-
```typescript
|
|
539
|
-
// Multiple filter conditions
|
|
540
|
-
const query = `
|
|
541
|
-
query ExtractFilteredProducts($first: Int!, $after: String, $filter: JSON) {
|
|
542
|
-
products(
|
|
543
|
-
first: $first
|
|
544
|
-
after: $after
|
|
545
|
-
filter: $filter
|
|
546
|
-
) {
|
|
547
|
-
edges {
|
|
548
|
-
node { id ref name status type }
|
|
549
|
-
cursor
|
|
550
|
-
}
|
|
551
|
-
pageInfo { hasNextPage }
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
`;
|
|
555
|
-
|
|
556
|
-
const result = await client.graphql({
|
|
557
|
-
query,
|
|
558
|
-
variables: {
|
|
559
|
-
first: 50,
|
|
560
|
-
filter: {
|
|
561
|
-
AND: [{ status: { equalTo: 'ACTIVE' } }, { type: { equalTo: 'STANDARD' } }],
|
|
562
|
-
},
|
|
563
|
-
},
|
|
564
|
-
pagination: { maxRecords: 10000 },
|
|
565
|
-
});
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
## Error Handling
|
|
569
|
-
|
|
570
|
-
### Comprehensive Error Handling with Retry Logic
|
|
571
|
-
|
|
572
|
-
```typescript
|
|
573
|
-
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
574
|
-
|
|
575
|
-
async function extractWithErrorHandling() {
|
|
576
|
-
const client = await createClient({
|
|
577
|
-
config: {
|
|
578
|
-
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
579
|
-
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
580
|
-
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
581
|
-
username: process.env.FLUENT_USERNAME!,
|
|
582
|
-
password: process.env.FLUENT_PASSWORD!
|
|
583
|
-
}
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
const query = `
|
|
587
|
-
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
588
|
-
virtualPositions(first: $first, after: $after) {
|
|
589
|
-
edges {
|
|
590
|
-
node {
|
|
591
|
-
id ref productRef groupRef quantity status
|
|
592
|
-
createdOn updatedOn
|
|
593
|
-
}
|
|
594
|
-
cursor
|
|
595
|
-
}
|
|
596
|
-
pageInfo { hasNextPage }
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
`;
|
|
600
|
-
|
|
601
|
-
try {
|
|
602
|
-
const result = await client.graphql({
|
|
603
|
-
query,
|
|
604
|
-
variables: { first: 100 },
|
|
605
|
-
pagination: { maxRecords: 10000 },
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
// Check for GraphQL errors
|
|
609
|
-
if (result.errors && result.errors.length > 0) {
|
|
610
|
-
console.error('GraphQL errors detected:', {
|
|
611
|
-
errorCount: result.errors.length,
|
|
612
|
-
errors: result.errors.map(e => ({
|
|
613
|
-
message: e.message,
|
|
614
|
-
path: e.path,
|
|
615
|
-
extensions: e.extensions
|
|
616
|
-
}))
|
|
617
|
-
});
|
|
618
|
-
throw new Error(`GraphQL query failed: ${result.errors[0].message}`);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// Validate data structure
|
|
622
|
-
if (!result.data?.virtualPositions?.edges) {
|
|
623
|
-
throw new Error('Unexpected response structure - missing virtualPositions.edges');
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
const records = result.data.virtualPositions.edges.map(e => e.node);
|
|
627
|
-
console.log(`✅ Extracted ${records.length} records successfully`);
|
|
628
|
-
|
|
629
|
-
return records;
|
|
630
|
-
} catch (error) {
|
|
631
|
-
console.error('Extraction failed:', {
|
|
632
|
-
error: error.message,
|
|
633
|
-
errorType: error.constructor.name
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
// Check for specific error types with appropriate handling
|
|
637
|
-
if (error.message.includes('authentication') || error.message.includes('401')) {
|
|
638
|
-
console.error('Authentication failed - check credentials');
|
|
639
|
-
throw new Error('Authentication failure - verify OAuth2 credentials');
|
|
640
|
-
} else if (error.message.includes('timeout') || error.code === 'TIMEOUT_ERROR') {
|
|
641
|
-
console.error('Request timeout - try smaller page size');
|
|
642
|
-
throw new Error('Timeout error - reduce pagination page size');
|
|
643
|
-
} else if (error.message.includes('rate limit') || error.code === 'RATE_LIMIT_ERROR') {
|
|
644
|
-
console.error('Rate limit exceeded - implement exponential backoff');
|
|
645
|
-
throw new Error('Rate limit error - wait before retrying');
|
|
646
|
-
} else if (error.message.includes('network') || error.code === 'ECONNREFUSED') {
|
|
647
|
-
console.error('Network error - check connectivity');
|
|
648
|
-
throw new Error('Network error - verify API endpoint');
|
|
649
|
-
} else {
|
|
650
|
-
throw error;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
// Retry logic for transient errors
|
|
656
|
-
async function extractWithRetry(maxRetries: number = 3) {
|
|
657
|
-
let lastError: Error;
|
|
658
|
-
|
|
659
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
660
|
-
try {
|
|
661
|
-
return await extractWithErrorHandling();
|
|
662
|
-
} catch (error) {
|
|
663
|
-
lastError = error;
|
|
664
|
-
|
|
665
|
-
// Only retry for transient errors
|
|
666
|
-
if (error.message.includes('timeout') ||
|
|
667
|
-
error.message.includes('rate limit') ||
|
|
668
|
-
error.message.includes('network')) {
|
|
669
|
-
|
|
670
|
-
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
|
|
671
|
-
console.log(`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`);
|
|
672
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
673
|
-
} else {
|
|
674
|
-
// Don't retry for authentication or validation errors
|
|
675
|
-
throw error;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
throw lastError!;
|
|
681
|
-
}
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
### Validation Errors with Detailed Logging
|
|
685
|
-
|
|
686
|
-
```typescript
|
|
687
|
-
async function extractWithValidation() {
|
|
688
|
-
try {
|
|
689
|
-
const result = await client.graphql({ query, variables });
|
|
690
|
-
|
|
691
|
-
// Check for GraphQL errors
|
|
692
|
-
if (result.errors && result.errors.length > 0) {
|
|
693
|
-
console.error('GraphQL errors:', {
|
|
694
|
-
query: query.substring(0, 100) + '...',
|
|
695
|
-
variables,
|
|
696
|
-
errors: result.errors.map(e => ({
|
|
697
|
-
message: e.message,
|
|
698
|
-
path: e.path
|
|
699
|
-
}))
|
|
700
|
-
});
|
|
701
|
-
throw new Error('Query returned GraphQL errors');
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// Validate data structure
|
|
705
|
-
if (!result.data?.virtualPositions?.edges) {
|
|
706
|
-
console.error('Invalid response structure:', {
|
|
707
|
-
hasData: !!result.data,
|
|
708
|
-
hasVirtualPositions: !!result.data?.virtualPositions,
|
|
709
|
-
actualStructure: Object.keys(result.data || {})
|
|
710
|
-
});
|
|
711
|
-
throw new Error('Unexpected response structure');
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
const records = result.data.virtualPositions.edges.map(e => e.node);
|
|
715
|
-
|
|
716
|
-
if (records.length === 0) {
|
|
717
|
-
console.warn('No records found - verify query filters');
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
return records;
|
|
721
|
-
} catch (error) {
|
|
722
|
-
console.error('Validation error:', error.message);
|
|
723
|
-
throw error;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
## Practice Exercise
|
|
729
|
-
|
|
730
|
-
**Goal**: Extract all products created in the last 30 days
|
|
731
|
-
|
|
732
|
-
**Requirements:**
|
|
733
|
-
|
|
734
|
-
1. Query the `products` connection
|
|
735
|
-
2. Filter by `createdOn` date range
|
|
736
|
-
3. Include fields: `id`, `ref`, `name`, `status`, `createdOn`
|
|
737
|
-
4. Use auto-pagination with max 5000 records
|
|
738
|
-
5. Log progress every page
|
|
739
|
-
|
|
740
|
-
**Solution:**
|
|
741
|
-
|
|
742
|
-
```typescript
|
|
743
|
-
async function extractRecentProducts() {
|
|
744
|
-
const client = await createClient({ config });
|
|
745
|
-
|
|
746
|
-
const thirtyDaysAgo = new Date();
|
|
747
|
-
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
|
748
|
-
|
|
749
|
-
const query = `
|
|
750
|
-
query ExtractRecentProducts($first: Int!, $after: String, $from: DateTime!) {
|
|
751
|
-
products(
|
|
752
|
-
first: $first
|
|
753
|
-
after: $after
|
|
754
|
-
createdOn: { from: $from }
|
|
755
|
-
) {
|
|
756
|
-
edges {
|
|
757
|
-
node {
|
|
758
|
-
id
|
|
759
|
-
ref
|
|
760
|
-
name
|
|
761
|
-
status
|
|
762
|
-
createdOn
|
|
763
|
-
}
|
|
764
|
-
cursor
|
|
765
|
-
}
|
|
766
|
-
pageInfo {
|
|
767
|
-
hasNextPage
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
`;
|
|
772
|
-
|
|
773
|
-
const result = await client.graphql({
|
|
774
|
-
query,
|
|
775
|
-
variables: {
|
|
776
|
-
first: 50,
|
|
777
|
-
from: thirtyDaysAgo.toISOString(),
|
|
778
|
-
},
|
|
779
|
-
pagination: {
|
|
780
|
-
maxRecords: 5000,
|
|
781
|
-
onProgress: (page, totalRecords) => {
|
|
782
|
-
console.log(`Page ${page}: ${totalRecords} products fetched`);
|
|
783
|
-
},
|
|
784
|
-
},
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
const products = result.data.products.edges.map(e => e.node);
|
|
788
|
-
|
|
789
|
-
console.log(`\nTotal products created in last 30 days: ${products.length}`);
|
|
790
|
-
|
|
791
|
-
return products;
|
|
792
|
-
}
|
|
793
|
-
```
|
|
794
|
-
|
|
795
|
-
## When to Use Each Approach
|
|
796
|
-
|
|
797
|
-
| Feature | ExtractionOrchestrator | Manual Extraction |
|
|
798
|
-
|---------|------------------------|-------------------|
|
|
799
|
-
| **Simplicity** | ✅ High - minimal code | ⚠️ Medium - more code |
|
|
800
|
-
| **Path Extraction** | ✅ Automatic with `resultPath` | ❌ Manual with `.map()` |
|
|
801
|
-
| **Validation** | ✅ Built-in per-item validation | ❌ Manual validation |
|
|
802
|
-
| **Statistics** | ✅ Comprehensive stats object | ⚠️ Via `extensions.autoPagination` |
|
|
803
|
-
| **Error Handling** | ✅ Structured error tracking | ⚠️ Try/catch only |
|
|
804
|
-
| **Fine Control** | ⚠️ Limited customization | ✅ Full control |
|
|
805
|
-
| **Best For** | Most extraction tasks | Custom pagination logic |
|
|
806
|
-
|
|
807
|
-
**Recommendation:** Start with `ExtractionOrchestrator` for 90% of use cases. Switch to manual extraction only when you need custom pagination behavior or response processing.
|
|
808
|
-
|
|
809
|
-
## Key Takeaways
|
|
810
|
-
|
|
811
|
-
- 🎯 **Use ExtractionOrchestrator for simplicity** - handles path extraction and validation
|
|
812
|
-
- 🎯 **Manual extraction for control** - when you need custom pagination logic
|
|
813
|
-
- 🎯 Always include pagination variables (`$first`, `$after`) in queries
|
|
814
|
-
- 🎯 Use auto-pagination to avoid manual cursor management
|
|
815
|
-
- 🎯 Configure safety limits (`maxRecords`, `maxPages`, `timeout`)
|
|
816
|
-
- 🎯 Use `onProgress` callbacks for long-running extractions
|
|
817
|
-
- 🎯 Check `extensions.autoPagination` for metadata (manual approach)
|
|
818
|
-
- 🎯 Handle errors gracefully with try/catch
|
|
819
|
-
- 🎯 Validate field names against schema before use
|
|
820
|
-
|
|
821
|
-
## Next Steps
|
|
822
|
-
|
|
823
|
-
Continue to [Module 3: Parquet Processing](./02-core-guides-extraction-03-parquet-processing.md) to learn how to extract data from Parquet files and combine it with GraphQL enrichment.
|
|
1
|
+
# Module 2: Basic Extraction
|
|
2
|
+
|
|
3
|
+
**Level:** Beginner
|
|
4
|
+
**Estimated Time:** 20 minutes
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
This module teaches you how to perform basic data extraction from Fluent Commerce using validated GraphQL queries and automatic pagination.
|
|
9
|
+
|
|
10
|
+
**Note:** For most extraction use cases, the **ExtractionOrchestrator** (covered in [Module 8](./02-core-guides-extraction-08-extraction-orchestrator.md)) provides a simpler, higher-level API. This module shows the manual approach for cases where you need fine-grained control.
|
|
11
|
+
|
|
12
|
+
## Learning Objectives
|
|
13
|
+
|
|
14
|
+
By the end of this module, you will:
|
|
15
|
+
|
|
16
|
+
- ✅ Write validated GraphQL extraction queries
|
|
17
|
+
- ✅ Use auto-pagination to fetch large datasets
|
|
18
|
+
- ✅ Extract common Fluent entities (inventory, products, orders)
|
|
19
|
+
- ✅ Handle pagination responses correctly
|
|
20
|
+
- ✅ Process extracted data
|
|
21
|
+
- ✅ Understand when to use manual extraction vs ExtractionOrchestrator
|
|
22
|
+
|
|
23
|
+
## Your First Extraction Query
|
|
24
|
+
|
|
25
|
+
### Step 1: Initialize the Client
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
29
|
+
|
|
30
|
+
// Create client (auto-detects Node.js, Deno, or Versori context)
|
|
31
|
+
const client = await createClient({
|
|
32
|
+
config: {
|
|
33
|
+
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
34
|
+
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
35
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
36
|
+
username: process.env.FLUENT_USERNAME!,
|
|
37
|
+
password: process.env.FLUENT_PASSWORD!
|
|
38
|
+
// Note: retailerId is OPTIONAL for GraphQL queries (only required for Job/Event API)
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Step 2: Write a Simple Query
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const query = `
|
|
47
|
+
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
48
|
+
virtualPositions(first: $first, after: $after) {
|
|
49
|
+
edges {
|
|
50
|
+
node {
|
|
51
|
+
id
|
|
52
|
+
ref
|
|
53
|
+
productRef
|
|
54
|
+
groupRef
|
|
55
|
+
quantity
|
|
56
|
+
status
|
|
57
|
+
createdOn
|
|
58
|
+
updatedOn
|
|
59
|
+
}
|
|
60
|
+
cursor
|
|
61
|
+
}
|
|
62
|
+
pageInfo {
|
|
63
|
+
hasNextPage
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Field Validation:**
|
|
71
|
+
|
|
72
|
+
- ✅ `id` - VirtualPosition.id (ID!)
|
|
73
|
+
- ✅ `ref` - VirtualPosition.ref (String!)
|
|
74
|
+
- ✅ `productRef` - VirtualPosition.productRef (String!)
|
|
75
|
+
- ✅ `groupRef` - VirtualPosition.groupRef (String)
|
|
76
|
+
- ✅ `quantity` - VirtualPosition.quantity (Int!)
|
|
77
|
+
- ✅ `status` - VirtualPosition.status (String)
|
|
78
|
+
|
|
79
|
+
> **⚠️ IMPORTANT: VirtualPosition vs InventoryPosition Field Differences**
|
|
80
|
+
>
|
|
81
|
+
> These two types have **different field names** for quantity:
|
|
82
|
+
> - **VirtualPosition**: Uses `quantity` (Int!)
|
|
83
|
+
> - **InventoryPosition**: Uses `qty` (Int!) and `onHand` (Int!)
|
|
84
|
+
>
|
|
85
|
+
> Always check the GraphQL schema when switching between entity types!
|
|
86
|
+
|
|
87
|
+
### Step 3: Execute with Auto-Pagination
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const result = await client.graphql({
|
|
91
|
+
query,
|
|
92
|
+
variables: { first: 100 },
|
|
93
|
+
pagination: {
|
|
94
|
+
maxRecords: 10000, // Stop after 10K records
|
|
95
|
+
maxPages: 100, // OR stop after 100 pages
|
|
96
|
+
onProgress: (page, totalRecords) => {
|
|
97
|
+
console.log(`Fetched page ${page}: ${totalRecords} records so far`);
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Step 4: Process the Results
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// Auto-pagination merges all pages into single response
|
|
107
|
+
const allRecords = result.data.virtualPositions.edges.map(edge => edge.node);
|
|
108
|
+
|
|
109
|
+
console.log(`Total records: ${allRecords.length}`);
|
|
110
|
+
console.log(`Pages fetched: ${result.extensions.pagination.totalPages}`);
|
|
111
|
+
console.log(`Time elapsed: ${result.extensions.pagination.timeElapsed}ms`);
|
|
112
|
+
|
|
113
|
+
// Process each record
|
|
114
|
+
for (const record of allRecords) {
|
|
115
|
+
console.log(`Product ${record.productRef}: ${record.quantity} units`);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Complete Example
|
|
120
|
+
|
|
121
|
+
### Approach 1: Using ExtractionOrchestrator (Recommended)
|
|
122
|
+
|
|
123
|
+
For most use cases, use the high-level ExtractionOrchestrator:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { createClient, ExtractionOrchestrator } from '@fluentcommerce/fc-connect-sdk';
|
|
127
|
+
|
|
128
|
+
async function extractVirtualPositions() {
|
|
129
|
+
const client = await createClient({
|
|
130
|
+
config: {
|
|
131
|
+
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
132
|
+
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
133
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET!
|
|
134
|
+
// retailerId is OPTIONAL for GraphQL queries (only required for Job/Event API)
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const orchestrator = new ExtractionOrchestrator(client, console);
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const result = await orchestrator.extract({
|
|
142
|
+
query: `
|
|
143
|
+
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
144
|
+
virtualPositions(first: $first, after: $after) {
|
|
145
|
+
edges {
|
|
146
|
+
node {
|
|
147
|
+
id ref productRef groupRef quantity status
|
|
148
|
+
createdOn updatedOn
|
|
149
|
+
}
|
|
150
|
+
cursor
|
|
151
|
+
}
|
|
152
|
+
pageInfo { hasNextPage }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
`,
|
|
156
|
+
resultPath: 'virtualPositions.edges.node',
|
|
157
|
+
pageSize: 100,
|
|
158
|
+
maxRecords: 10000
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
console.log('\n=== Extraction Summary ===');
|
|
162
|
+
console.log(`Total records: ${result.data.length}`);
|
|
163
|
+
console.log(`Pages: ${result.stats.totalPages}`);
|
|
164
|
+
console.log(`Duration: ${result.stats.duration}ms`);
|
|
165
|
+
|
|
166
|
+
return result.data;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error('Extraction failed:', error);
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
extractVirtualPositions()
|
|
174
|
+
.then(() => console.log('Extraction complete'))
|
|
175
|
+
.catch(error => console.error('Error:', error));
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Approach 2: Manual Extraction (For Advanced Control)
|
|
179
|
+
|
|
180
|
+
For fine-grained control over pagination and response handling:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
184
|
+
|
|
185
|
+
async function extractVirtualPositions() {
|
|
186
|
+
// Initialize client
|
|
187
|
+
const client = await createClient({
|
|
188
|
+
config: {
|
|
189
|
+
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
190
|
+
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
191
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET!
|
|
192
|
+
// retailerId is OPTIONAL for GraphQL queries (only required for Job/Event API)
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Define query
|
|
197
|
+
const query = `
|
|
198
|
+
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
199
|
+
virtualPositions(first: $first, after: $after) {
|
|
200
|
+
edges {
|
|
201
|
+
node {
|
|
202
|
+
id
|
|
203
|
+
ref
|
|
204
|
+
productRef
|
|
205
|
+
groupRef
|
|
206
|
+
quantity
|
|
207
|
+
status
|
|
208
|
+
createdOn
|
|
209
|
+
updatedOn
|
|
210
|
+
}
|
|
211
|
+
cursor
|
|
212
|
+
}
|
|
213
|
+
pageInfo {
|
|
214
|
+
hasNextPage
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`;
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
// Execute with auto-pagination
|
|
222
|
+
const result = await client.graphql({
|
|
223
|
+
query,
|
|
224
|
+
variables: { first: 100 },
|
|
225
|
+
pagination: {
|
|
226
|
+
maxRecords: 10000,
|
|
227
|
+
onProgress: (page, totalRecords) => {
|
|
228
|
+
console.log(`Page ${page}: ${totalRecords} records`);
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Extract records
|
|
234
|
+
const records = result.data.virtualPositions.edges.map(e => e.node);
|
|
235
|
+
|
|
236
|
+
console.log('\n=== Extraction Summary ===');
|
|
237
|
+
console.log(`Total records: ${records.length}`);
|
|
238
|
+
console.log(`Pages: ${result.extensions.pagination.totalPages}`);
|
|
239
|
+
console.log(`Time: ${result.extensions.pagination.timeElapsed}ms`);
|
|
240
|
+
|
|
241
|
+
// Show sample records
|
|
242
|
+
console.log('\n=== Sample Records ===');
|
|
243
|
+
records.slice(0, 5).forEach(record => {
|
|
244
|
+
console.log(`- ${record.ref}: ${record.quantity} units of ${record.productRef}`);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
return records;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error('Extraction failed:', error);
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Run extraction
|
|
255
|
+
extractVirtualPositions()
|
|
256
|
+
.then(() => console.log('Extraction complete'))
|
|
257
|
+
.catch(error => console.error('Error:', error));
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Common Entity Extractions
|
|
261
|
+
|
|
262
|
+
### 1. Inventory Positions
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const query = `
|
|
266
|
+
query ExtractInventory($first: Int!, $after: String) {
|
|
267
|
+
inventoryPositions(first: $first, after: $after) {
|
|
268
|
+
edges {
|
|
269
|
+
node {
|
|
270
|
+
id
|
|
271
|
+
ref
|
|
272
|
+
productRef
|
|
273
|
+
locationRef
|
|
274
|
+
qty # ✅ Note: 'qty' not 'quantity'
|
|
275
|
+
status
|
|
276
|
+
createdOn
|
|
277
|
+
updatedOn
|
|
278
|
+
}
|
|
279
|
+
cursor
|
|
280
|
+
}
|
|
281
|
+
pageInfo {
|
|
282
|
+
hasNextPage
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
`;
|
|
287
|
+
|
|
288
|
+
const result = await client.graphql({
|
|
289
|
+
query,
|
|
290
|
+
variables: { first: 100 },
|
|
291
|
+
pagination: { maxRecords: 50000 },
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const inventory = result.data.inventoryPositions.edges.map(e => e.node);
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 2. Products
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
const query = `
|
|
301
|
+
query ExtractProducts($first: Int!, $after: String) {
|
|
302
|
+
products(first: $first, after: $after) {
|
|
303
|
+
edges {
|
|
304
|
+
node {
|
|
305
|
+
id
|
|
306
|
+
ref
|
|
307
|
+
name
|
|
308
|
+
gtin
|
|
309
|
+
status
|
|
310
|
+
type
|
|
311
|
+
createdOn
|
|
312
|
+
updatedOn
|
|
313
|
+
}
|
|
314
|
+
cursor
|
|
315
|
+
}
|
|
316
|
+
pageInfo {
|
|
317
|
+
hasNextPage
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
`;
|
|
322
|
+
|
|
323
|
+
const result = await client.graphql({
|
|
324
|
+
query,
|
|
325
|
+
variables: { first: 50 }, // Smaller page size for products
|
|
326
|
+
pagination: { maxRecords: 10000 },
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const products = result.data.products.edges.map(e => e.node);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### 3. Orders
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
const query = `
|
|
336
|
+
query ExtractOrders($first: Int!, $after: String) {
|
|
337
|
+
orders(first: $first, after: $after) {
|
|
338
|
+
edges {
|
|
339
|
+
node {
|
|
340
|
+
id
|
|
341
|
+
ref
|
|
342
|
+
type
|
|
343
|
+
status
|
|
344
|
+
totalPrice
|
|
345
|
+
totalTaxPrice
|
|
346
|
+
currency
|
|
347
|
+
createdOn
|
|
348
|
+
updatedOn
|
|
349
|
+
}
|
|
350
|
+
cursor
|
|
351
|
+
}
|
|
352
|
+
pageInfo {
|
|
353
|
+
hasNextPage
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
`;
|
|
358
|
+
|
|
359
|
+
const result = await client.graphql({
|
|
360
|
+
query,
|
|
361
|
+
variables: { first: 50 },
|
|
362
|
+
pagination: { maxRecords: 20000 },
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const orders = result.data.orders.edges.map(e => e.node);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 4. Locations
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
const query = `
|
|
372
|
+
query ExtractLocations($first: Int!, $after: String) {
|
|
373
|
+
locations(first: $first, after: $after) {
|
|
374
|
+
edges {
|
|
375
|
+
node {
|
|
376
|
+
id
|
|
377
|
+
ref
|
|
378
|
+
name
|
|
379
|
+
type
|
|
380
|
+
status
|
|
381
|
+
createdOn
|
|
382
|
+
updatedOn
|
|
383
|
+
}
|
|
384
|
+
cursor
|
|
385
|
+
}
|
|
386
|
+
pageInfo {
|
|
387
|
+
hasNextPage
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
`;
|
|
392
|
+
|
|
393
|
+
const result = await client.graphql({
|
|
394
|
+
query,
|
|
395
|
+
variables: { first: 100 },
|
|
396
|
+
pagination: { maxRecords: 5000 },
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
const locations = result.data.locations.edges.map(e => e.node);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Understanding Pagination Responses
|
|
403
|
+
|
|
404
|
+
### Response Structure
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
{
|
|
408
|
+
data: {
|
|
409
|
+
virtualPositions: {
|
|
410
|
+
edges: [
|
|
411
|
+
{
|
|
412
|
+
node: { id: "1", ref: "VP-001", ... },
|
|
413
|
+
cursor: "abc123"
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
node: { id: "2", ref: "VP-002", ... },
|
|
417
|
+
cursor: "def456"
|
|
418
|
+
}
|
|
419
|
+
],
|
|
420
|
+
pageInfo: {
|
|
421
|
+
hasNextPage: true
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
extensions: {
|
|
426
|
+
autoPagination: {
|
|
427
|
+
totalPages: 15,
|
|
428
|
+
totalRecords: 1487,
|
|
429
|
+
truncated: false,
|
|
430
|
+
timeElapsed: 8324
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Auto-Pagination Extensions
|
|
437
|
+
|
|
438
|
+
The SDK adds `extensions.autoPagination` metadata:
|
|
439
|
+
|
|
440
|
+
| Field | Type | Description |
|
|
441
|
+
| -------------- | ------- | ------------------------------- |
|
|
442
|
+
| `totalPages` | number | Number of pages fetched |
|
|
443
|
+
| `totalRecords` | number | Total records returned |
|
|
444
|
+
| `truncated` | boolean | True if stopped by safety limit |
|
|
445
|
+
| `duration` | number | Total time in milliseconds |
|
|
446
|
+
|
|
447
|
+
### Accessing Data
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
// Get all records
|
|
451
|
+
const allRecords = result.data.virtualPositions.edges.map(e => e.node);
|
|
452
|
+
|
|
453
|
+
// Check if truncated
|
|
454
|
+
if (result.extensions.pagination.truncated) {
|
|
455
|
+
console.warn('Results truncated by safety limit');
|
|
456
|
+
console.log(`Fetched ${result.extensions.pagination.totalRecords} of total`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Performance metrics
|
|
460
|
+
console.log(
|
|
461
|
+
`Fetched ${result.extensions.pagination.totalRecords} records in ${result.extensions.pagination.timeElapsed}ms`
|
|
462
|
+
);
|
|
463
|
+
console.log(
|
|
464
|
+
`Rate: ${((result.extensions.pagination.totalRecords / result.extensions.pagination.timeElapsed) * 1000).toFixed(0)} records/sec`
|
|
465
|
+
);
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Filtering Results
|
|
469
|
+
|
|
470
|
+
### GraphQL Filters
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// Filter by status
|
|
474
|
+
const query = `
|
|
475
|
+
query ExtractActiveInventory($first: Int!, $after: String, $filter: JSON) {
|
|
476
|
+
inventoryPositions(
|
|
477
|
+
first: $first
|
|
478
|
+
after: $after
|
|
479
|
+
filter: $filter
|
|
480
|
+
) {
|
|
481
|
+
edges {
|
|
482
|
+
node { id ref qty status }
|
|
483
|
+
cursor
|
|
484
|
+
}
|
|
485
|
+
pageInfo { hasNextPage }
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
`;
|
|
489
|
+
|
|
490
|
+
const result = await client.graphql({
|
|
491
|
+
query,
|
|
492
|
+
variables: {
|
|
493
|
+
first: 100,
|
|
494
|
+
filter: {
|
|
495
|
+
status: { equalTo: 'AVAILABLE' },
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
pagination: { maxRecords: 50000 },
|
|
499
|
+
});
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### Date Range Filters
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
// Filter by date range
|
|
506
|
+
const fromDate = new Date('2024-01-01').toISOString();
|
|
507
|
+
const toDate = new Date('2024-12-31').toISOString();
|
|
508
|
+
|
|
509
|
+
const query = `
|
|
510
|
+
query ExtractRecentOrders($first: Int!, $after: String, $from: DateTime!, $to: DateTime!) {
|
|
511
|
+
orders(
|
|
512
|
+
first: $first
|
|
513
|
+
after: $after
|
|
514
|
+
createdOn: { from: $from, to: $to }
|
|
515
|
+
) {
|
|
516
|
+
edges {
|
|
517
|
+
node { id ref createdOn totalPrice }
|
|
518
|
+
cursor
|
|
519
|
+
}
|
|
520
|
+
pageInfo { hasNextPage }
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
`;
|
|
524
|
+
|
|
525
|
+
const result = await client.graphql({
|
|
526
|
+
query,
|
|
527
|
+
variables: {
|
|
528
|
+
first: 100,
|
|
529
|
+
from: fromDate,
|
|
530
|
+
to: toDate,
|
|
531
|
+
},
|
|
532
|
+
pagination: { maxRecords: 20000 },
|
|
533
|
+
});
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Complex Filters
|
|
537
|
+
|
|
538
|
+
```typescript
|
|
539
|
+
// Multiple filter conditions
|
|
540
|
+
const query = `
|
|
541
|
+
query ExtractFilteredProducts($first: Int!, $after: String, $filter: JSON) {
|
|
542
|
+
products(
|
|
543
|
+
first: $first
|
|
544
|
+
after: $after
|
|
545
|
+
filter: $filter
|
|
546
|
+
) {
|
|
547
|
+
edges {
|
|
548
|
+
node { id ref name status type }
|
|
549
|
+
cursor
|
|
550
|
+
}
|
|
551
|
+
pageInfo { hasNextPage }
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
`;
|
|
555
|
+
|
|
556
|
+
const result = await client.graphql({
|
|
557
|
+
query,
|
|
558
|
+
variables: {
|
|
559
|
+
first: 50,
|
|
560
|
+
filter: {
|
|
561
|
+
AND: [{ status: { equalTo: 'ACTIVE' } }, { type: { equalTo: 'STANDARD' } }],
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
pagination: { maxRecords: 10000 },
|
|
565
|
+
});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## Error Handling
|
|
569
|
+
|
|
570
|
+
### Comprehensive Error Handling with Retry Logic
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
574
|
+
|
|
575
|
+
async function extractWithErrorHandling() {
|
|
576
|
+
const client = await createClient({
|
|
577
|
+
config: {
|
|
578
|
+
baseUrl: process.env.FLUENT_BASE_URL!,
|
|
579
|
+
clientId: process.env.FLUENT_CLIENT_ID!,
|
|
580
|
+
clientSecret: process.env.FLUENT_CLIENT_SECRET!,
|
|
581
|
+
username: process.env.FLUENT_USERNAME!,
|
|
582
|
+
password: process.env.FLUENT_PASSWORD!
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
const query = `
|
|
587
|
+
query ExtractVirtualPositions($first: Int!, $after: String) {
|
|
588
|
+
virtualPositions(first: $first, after: $after) {
|
|
589
|
+
edges {
|
|
590
|
+
node {
|
|
591
|
+
id ref productRef groupRef quantity status
|
|
592
|
+
createdOn updatedOn
|
|
593
|
+
}
|
|
594
|
+
cursor
|
|
595
|
+
}
|
|
596
|
+
pageInfo { hasNextPage }
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
`;
|
|
600
|
+
|
|
601
|
+
try {
|
|
602
|
+
const result = await client.graphql({
|
|
603
|
+
query,
|
|
604
|
+
variables: { first: 100 },
|
|
605
|
+
pagination: { maxRecords: 10000 },
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
// Check for GraphQL errors
|
|
609
|
+
if (result.errors && result.errors.length > 0) {
|
|
610
|
+
console.error('GraphQL errors detected:', {
|
|
611
|
+
errorCount: result.errors.length,
|
|
612
|
+
errors: result.errors.map(e => ({
|
|
613
|
+
message: e.message,
|
|
614
|
+
path: e.path,
|
|
615
|
+
extensions: e.extensions
|
|
616
|
+
}))
|
|
617
|
+
});
|
|
618
|
+
throw new Error(`GraphQL query failed: ${result.errors[0].message}`);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Validate data structure
|
|
622
|
+
if (!result.data?.virtualPositions?.edges) {
|
|
623
|
+
throw new Error('Unexpected response structure - missing virtualPositions.edges');
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const records = result.data.virtualPositions.edges.map(e => e.node);
|
|
627
|
+
console.log(`✅ Extracted ${records.length} records successfully`);
|
|
628
|
+
|
|
629
|
+
return records;
|
|
630
|
+
} catch (error) {
|
|
631
|
+
console.error('Extraction failed:', {
|
|
632
|
+
error: error.message,
|
|
633
|
+
errorType: error.constructor.name
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// Check for specific error types with appropriate handling
|
|
637
|
+
if (error.message.includes('authentication') || error.message.includes('401')) {
|
|
638
|
+
console.error('Authentication failed - check credentials');
|
|
639
|
+
throw new Error('Authentication failure - verify OAuth2 credentials');
|
|
640
|
+
} else if (error.message.includes('timeout') || error.code === 'TIMEOUT_ERROR') {
|
|
641
|
+
console.error('Request timeout - try smaller page size');
|
|
642
|
+
throw new Error('Timeout error - reduce pagination page size');
|
|
643
|
+
} else if (error.message.includes('rate limit') || error.code === 'RATE_LIMIT_ERROR') {
|
|
644
|
+
console.error('Rate limit exceeded - implement exponential backoff');
|
|
645
|
+
throw new Error('Rate limit error - wait before retrying');
|
|
646
|
+
} else if (error.message.includes('network') || error.code === 'ECONNREFUSED') {
|
|
647
|
+
console.error('Network error - check connectivity');
|
|
648
|
+
throw new Error('Network error - verify API endpoint');
|
|
649
|
+
} else {
|
|
650
|
+
throw error;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Retry logic for transient errors
|
|
656
|
+
async function extractWithRetry(maxRetries: number = 3) {
|
|
657
|
+
let lastError: Error;
|
|
658
|
+
|
|
659
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
660
|
+
try {
|
|
661
|
+
return await extractWithErrorHandling();
|
|
662
|
+
} catch (error) {
|
|
663
|
+
lastError = error;
|
|
664
|
+
|
|
665
|
+
// Only retry for transient errors
|
|
666
|
+
if (error.message.includes('timeout') ||
|
|
667
|
+
error.message.includes('rate limit') ||
|
|
668
|
+
error.message.includes('network')) {
|
|
669
|
+
|
|
670
|
+
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
|
|
671
|
+
console.log(`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`);
|
|
672
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
673
|
+
} else {
|
|
674
|
+
// Don't retry for authentication or validation errors
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
throw lastError!;
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Validation Errors with Detailed Logging
|
|
685
|
+
|
|
686
|
+
```typescript
|
|
687
|
+
async function extractWithValidation() {
|
|
688
|
+
try {
|
|
689
|
+
const result = await client.graphql({ query, variables });
|
|
690
|
+
|
|
691
|
+
// Check for GraphQL errors
|
|
692
|
+
if (result.errors && result.errors.length > 0) {
|
|
693
|
+
console.error('GraphQL errors:', {
|
|
694
|
+
query: query.substring(0, 100) + '...',
|
|
695
|
+
variables,
|
|
696
|
+
errors: result.errors.map(e => ({
|
|
697
|
+
message: e.message,
|
|
698
|
+
path: e.path
|
|
699
|
+
}))
|
|
700
|
+
});
|
|
701
|
+
throw new Error('Query returned GraphQL errors');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Validate data structure
|
|
705
|
+
if (!result.data?.virtualPositions?.edges) {
|
|
706
|
+
console.error('Invalid response structure:', {
|
|
707
|
+
hasData: !!result.data,
|
|
708
|
+
hasVirtualPositions: !!result.data?.virtualPositions,
|
|
709
|
+
actualStructure: Object.keys(result.data || {})
|
|
710
|
+
});
|
|
711
|
+
throw new Error('Unexpected response structure');
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const records = result.data.virtualPositions.edges.map(e => e.node);
|
|
715
|
+
|
|
716
|
+
if (records.length === 0) {
|
|
717
|
+
console.warn('No records found - verify query filters');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
return records;
|
|
721
|
+
} catch (error) {
|
|
722
|
+
console.error('Validation error:', error.message);
|
|
723
|
+
throw error;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
## Practice Exercise
|
|
729
|
+
|
|
730
|
+
**Goal**: Extract all products created in the last 30 days
|
|
731
|
+
|
|
732
|
+
**Requirements:**
|
|
733
|
+
|
|
734
|
+
1. Query the `products` connection
|
|
735
|
+
2. Filter by `createdOn` date range
|
|
736
|
+
3. Include fields: `id`, `ref`, `name`, `status`, `createdOn`
|
|
737
|
+
4. Use auto-pagination with max 5000 records
|
|
738
|
+
5. Log progress every page
|
|
739
|
+
|
|
740
|
+
**Solution:**
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
async function extractRecentProducts() {
|
|
744
|
+
const client = await createClient({ config });
|
|
745
|
+
|
|
746
|
+
const thirtyDaysAgo = new Date();
|
|
747
|
+
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
|
748
|
+
|
|
749
|
+
const query = `
|
|
750
|
+
query ExtractRecentProducts($first: Int!, $after: String, $from: DateTime!) {
|
|
751
|
+
products(
|
|
752
|
+
first: $first
|
|
753
|
+
after: $after
|
|
754
|
+
createdOn: { from: $from }
|
|
755
|
+
) {
|
|
756
|
+
edges {
|
|
757
|
+
node {
|
|
758
|
+
id
|
|
759
|
+
ref
|
|
760
|
+
name
|
|
761
|
+
status
|
|
762
|
+
createdOn
|
|
763
|
+
}
|
|
764
|
+
cursor
|
|
765
|
+
}
|
|
766
|
+
pageInfo {
|
|
767
|
+
hasNextPage
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
`;
|
|
772
|
+
|
|
773
|
+
const result = await client.graphql({
|
|
774
|
+
query,
|
|
775
|
+
variables: {
|
|
776
|
+
first: 50,
|
|
777
|
+
from: thirtyDaysAgo.toISOString(),
|
|
778
|
+
},
|
|
779
|
+
pagination: {
|
|
780
|
+
maxRecords: 5000,
|
|
781
|
+
onProgress: (page, totalRecords) => {
|
|
782
|
+
console.log(`Page ${page}: ${totalRecords} products fetched`);
|
|
783
|
+
},
|
|
784
|
+
},
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
const products = result.data.products.edges.map(e => e.node);
|
|
788
|
+
|
|
789
|
+
console.log(`\nTotal products created in last 30 days: ${products.length}`);
|
|
790
|
+
|
|
791
|
+
return products;
|
|
792
|
+
}
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
## When to Use Each Approach
|
|
796
|
+
|
|
797
|
+
| Feature | ExtractionOrchestrator | Manual Extraction |
|
|
798
|
+
|---------|------------------------|-------------------|
|
|
799
|
+
| **Simplicity** | ✅ High - minimal code | ⚠️ Medium - more code |
|
|
800
|
+
| **Path Extraction** | ✅ Automatic with `resultPath` | ❌ Manual with `.map()` |
|
|
801
|
+
| **Validation** | ✅ Built-in per-item validation | ❌ Manual validation |
|
|
802
|
+
| **Statistics** | ✅ Comprehensive stats object | ⚠️ Via `extensions.autoPagination` |
|
|
803
|
+
| **Error Handling** | ✅ Structured error tracking | ⚠️ Try/catch only |
|
|
804
|
+
| **Fine Control** | ⚠️ Limited customization | ✅ Full control |
|
|
805
|
+
| **Best For** | Most extraction tasks | Custom pagination logic |
|
|
806
|
+
|
|
807
|
+
**Recommendation:** Start with `ExtractionOrchestrator` for 90% of use cases. Switch to manual extraction only when you need custom pagination behavior or response processing.
|
|
808
|
+
|
|
809
|
+
## Key Takeaways
|
|
810
|
+
|
|
811
|
+
- 🎯 **Use ExtractionOrchestrator for simplicity** - handles path extraction and validation
|
|
812
|
+
- 🎯 **Manual extraction for control** - when you need custom pagination logic
|
|
813
|
+
- 🎯 Always include pagination variables (`$first`, `$after`) in queries
|
|
814
|
+
- 🎯 Use auto-pagination to avoid manual cursor management
|
|
815
|
+
- 🎯 Configure safety limits (`maxRecords`, `maxPages`, `timeout`)
|
|
816
|
+
- 🎯 Use `onProgress` callbacks for long-running extractions
|
|
817
|
+
- 🎯 Check `extensions.autoPagination` for metadata (manual approach)
|
|
818
|
+
- 🎯 Handle errors gracefully with try/catch
|
|
819
|
+
- 🎯 Validate field names against schema before use
|
|
820
|
+
|
|
821
|
+
## Next Steps
|
|
822
|
+
|
|
823
|
+
Continue to [Module 3: Parquet Processing](./02-core-guides-extraction-03-parquet-processing.md) to learn how to extract data from Parquet files and combine it with GraphQL enrichment.
|