@fluentcommerce/fc-connect-sdk 0.1.53 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -2
- package/README.md +39 -0
- package/dist/cjs/auth/index.d.ts +3 -0
- package/dist/cjs/auth/index.js +13 -0
- package/dist/cjs/auth/profile-loader.d.ts +18 -0
- package/dist/cjs/auth/profile-loader.js +208 -0
- package/dist/cjs/client-factory.d.ts +4 -0
- package/dist/cjs/client-factory.js +10 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/auth/index.d.ts +3 -0
- package/dist/esm/auth/index.js +2 -0
- package/dist/esm/auth/profile-loader.d.ts +18 -0
- package/dist/esm/auth/profile-loader.js +169 -0
- package/dist/esm/client-factory.d.ts +4 -0
- package/dist/esm/client-factory.js +9 -0
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/auth/index.d.ts +3 -0
- package/dist/types/auth/profile-loader.d.ts +18 -0
- package/dist/types/client-factory.d.ts +4 -0
- package/dist/types/index.d.ts +3 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -482
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
|
@@ -1,1126 +1,1126 @@
|
|
|
1
|
-
# Module 6: Helpers & Resolvers
|
|
2
|
-
|
|
3
|
-
**Leverage 54 Built-in Utilities**
|
|
4
|
-
|
|
5
|
-
**Level:** Advanced
|
|
6
|
-
**Time:** 35 minutes
|
|
7
|
-
**Prerequisites:** [Module 5: Advanced Patterns](./mapping-05-advanced-patterns.md)
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Learning Objectives
|
|
12
|
-
|
|
13
|
-
After completing this module, you will:
|
|
14
|
-
|
|
15
|
-
- ✅ Understand all 16 SDK resolvers
|
|
16
|
-
- ✅ Use 57 helper functions in custom resolvers
|
|
17
|
-
- ✅ Write efficient custom resolvers
|
|
18
|
-
- ✅ Implement async resolvers for API lookups
|
|
19
|
-
- ✅ Apply resolver best practices
|
|
20
|
-
- ✅ Optimize resolver performance
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Table of Contents
|
|
25
|
-
|
|
26
|
-
1. [SDK Resolvers Overview](#sdk-resolvers-overview)
|
|
27
|
-
2. [String Resolvers](#string-resolvers)
|
|
28
|
-
3. [Number Resolvers](#number-resolvers)
|
|
29
|
-
4. [Date Resolvers](#date-resolvers)
|
|
30
|
-
5. [Type Conversion Resolvers](#type-conversion-resolvers)
|
|
31
|
-
6. [Utility Resolvers](#utility-resolvers)
|
|
32
|
-
7. [Helper Functions Reference](#helper-functions-reference)
|
|
33
|
-
8. [Custom Resolvers](#custom-resolvers)
|
|
34
|
-
9. [Async Resolvers](#async-resolvers)
|
|
35
|
-
10. [Best Practices](#best-practices)
|
|
36
|
-
11. [Performance Optimization](#performance-optimization)
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## SDK Resolvers Overview
|
|
41
|
-
|
|
42
|
-
The SDK provides **16 built-in resolvers** for common transformations. All SDK resolvers:
|
|
43
|
-
|
|
44
|
-
- ✅ Follow naming convention: `sdk.<functionName>`
|
|
45
|
-
- ✅ Are null-safe (never throw errors)
|
|
46
|
-
- ✅ Return safe defaults for invalid input
|
|
47
|
-
- ✅ Work with all mappers (UniversalMapper, GraphQLMutationMapper)
|
|
48
|
-
|
|
49
|
-
### Complete SDK Resolver List
|
|
50
|
-
|
|
51
|
-
| Category | Resolvers | Count |
|
|
52
|
-
| ----------- | -------------------------------------- | ----- |
|
|
53
|
-
| **String** | uppercase, lowercase, trim, toString | 4 |
|
|
54
|
-
| **Number** | parseInt, parseFloat, number | 3 |
|
|
55
|
-
| **Date** | formatDate, formatDateShort, parseDate | 3 |
|
|
56
|
-
| **Type** | boolean, parseJson, toJson | 3 |
|
|
57
|
-
| **Utility** | identity, coalesce, default | 3 |
|
|
58
|
-
|
|
59
|
-
**Total**: 16 SDK resolvers
|
|
60
|
-
|
|
61
|
-
### Accessing SDK Resolvers Programmatically (NEW)
|
|
62
|
-
|
|
63
|
-
You can access SDK resolvers directly or test resolver names at runtime.
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import {
|
|
67
|
-
sdkResolvers,
|
|
68
|
-
getSdkResolver,
|
|
69
|
-
isSdkResolver,
|
|
70
|
-
getSdkResolverNames,
|
|
71
|
-
UniversalMapper,
|
|
72
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
73
|
-
|
|
74
|
-
// Get all SDK resolver names
|
|
75
|
-
const allResolvers = getSdkResolverNames();
|
|
76
|
-
console.log(allResolvers);
|
|
77
|
-
// SDK resolvers: ['sdk.uppercase', 'sdk.lowercase', 'sdk.trim', 'sdk.parseInt', ...]
|
|
78
|
-
|
|
79
|
-
// Retrieve a resolver function by name
|
|
80
|
-
const resolverFn = getSdkResolver('sdk.parseInt'); // (value) => number
|
|
81
|
-
console.log(isSdkResolver('sdk.parseInt')); // true
|
|
82
|
-
console.log(isSdkResolver('custom.myResolver')); // false
|
|
83
|
-
|
|
84
|
-
// Use sdkResolvers inside custom resolvers
|
|
85
|
-
const mapper = new UniversalMapper(mappingConfig, {
|
|
86
|
-
customResolvers: {
|
|
87
|
-
'custom.upperTrim': (value: any) => {
|
|
88
|
-
const upper = sdkResolvers\['sdk.uppercase'](value, null, null, {});
|
|
89
|
-
return sdkResolvers\['sdk.trim'](upper, null, null, {});
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**Utility Functions:**
|
|
96
|
-
|
|
97
|
-
- `getSdkResolverNames()` - Returns array of all SDK resolver names (useful for validation, autocomplete)
|
|
98
|
-
- `getSdkResolver(name)` - Returns resolver function by name or undefined
|
|
99
|
-
- `isSdkResolver(name)` - Checks if a resolver name starts with 'sdk.'
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## String Resolvers
|
|
104
|
-
|
|
105
|
-
### sdk.uppercase
|
|
106
|
-
|
|
107
|
-
Convert string to uppercase.
|
|
108
|
-
|
|
109
|
-
**Use case**: Normalize SKU codes, status values, country codes
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{
|
|
113
|
-
"fields": {
|
|
114
|
-
"status": {
|
|
115
|
-
"source": "order_status",
|
|
116
|
-
"resolver": "sdk.uppercase"
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Examples**:
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
"active" → "ACTIVE"
|
|
126
|
-
"pending" → "PENDING"
|
|
127
|
-
123 → 123 (non-strings pass through)
|
|
128
|
-
null → null (null-safe)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Null-safe behavior**: Returns non-strings unchanged
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
### sdk.lowercase
|
|
136
|
-
|
|
137
|
-
Convert string to lowercase.
|
|
138
|
-
|
|
139
|
-
**Use case**: Normalize email addresses, usernames, tags
|
|
140
|
-
|
|
141
|
-
```json
|
|
142
|
-
{
|
|
143
|
-
"fields": {
|
|
144
|
-
"email": {
|
|
145
|
-
"source": "customer_email",
|
|
146
|
-
"resolver": "sdk.lowercase"
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
**Examples**:
|
|
153
|
-
|
|
154
|
-
```typescript
|
|
155
|
-
"John@EXAMPLE.COM" → "john@example.com"
|
|
156
|
-
"SKU-001" → "sku-001"
|
|
157
|
-
123 → 123 (non-strings pass through)
|
|
158
|
-
null → null (null-safe)
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
---
|
|
162
|
-
|
|
163
|
-
### sdk.trim
|
|
164
|
-
|
|
165
|
-
Remove leading and trailing whitespace.
|
|
166
|
-
|
|
167
|
-
**Use case**: Clean CSV fields, remove spaces from user input
|
|
168
|
-
|
|
169
|
-
```json
|
|
170
|
-
{
|
|
171
|
-
"fields": {
|
|
172
|
-
"sku": {
|
|
173
|
-
"source": "product_code",
|
|
174
|
-
"resolver": "sdk.trim"
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Examples**:
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
" SKU123 " → "SKU123"
|
|
184
|
-
"\tSKU456\n" → "SKU456"
|
|
185
|
-
" " → "" (empty after trim)
|
|
186
|
-
123 → 123 (non-strings pass through)
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
### sdk.toString
|
|
192
|
-
|
|
193
|
-
Convert value to string.
|
|
194
|
-
|
|
195
|
-
**Use case**: Ensure value is string type, prevent "null" strings
|
|
196
|
-
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"fields": {
|
|
200
|
-
"productRef": {
|
|
201
|
-
"source": "product_id",
|
|
202
|
-
"resolver": "sdk.toString"
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
**Examples**:
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
123 → "123"
|
|
212
|
-
true → "true"
|
|
213
|
-
null → "" (empty string, NOT "null")
|
|
214
|
-
undefined → "" (empty string, NOT "undefined")
|
|
215
|
-
{ foo: "bar" } → "[object Object]"
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
**Critical**: Returns empty string for null/undefined (prevents literal "null"/"undefined" strings)
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## Number Resolvers
|
|
223
|
-
|
|
224
|
-
### sdk.parseInt
|
|
225
|
-
|
|
226
|
-
Parse value as integer.
|
|
227
|
-
|
|
228
|
-
**Use case**: Convert quantity strings to numbers, parse IDs
|
|
229
|
-
|
|
230
|
-
```json
|
|
231
|
-
{
|
|
232
|
-
"fields": {
|
|
233
|
-
"quantity": {
|
|
234
|
-
"source": "qty",
|
|
235
|
-
"resolver": "sdk.parseInt"
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
**Examples**:
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
"123" → 123
|
|
245
|
-
"123.99" → 123 (truncates decimals)
|
|
246
|
-
"$45" → 0 (invalid → default)
|
|
247
|
-
"abc" → 0 (invalid → default)
|
|
248
|
-
null → 0 (null-safe default)
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
**Important**: Returns `0` for invalid values (NOT `NaN`). This prevents breaking Fluent API calls.
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
### sdk.parseFloat
|
|
256
|
-
|
|
257
|
-
Parse value as floating-point number.
|
|
258
|
-
|
|
259
|
-
**Use case**: Convert price/weight strings to numbers
|
|
260
|
-
|
|
261
|
-
```json
|
|
262
|
-
{
|
|
263
|
-
"fields": {
|
|
264
|
-
"price": {
|
|
265
|
-
"source": "total_price",
|
|
266
|
-
"resolver": "sdk.parseFloat"
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
**Examples**:
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
"123.99" → 123.99
|
|
276
|
-
"$45.50" → 45.5 (strips currency symbols)
|
|
277
|
-
"1,234.56" → 1234.56 (removes commas)
|
|
278
|
-
" 99.99 " → 99.99 (trims whitespace)
|
|
279
|
-
"abc" → 0 (invalid → default)
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
**Advanced**: Handles currency symbols ($, €, £), commas, and whitespace automatically.
|
|
283
|
-
|
|
284
|
-
---
|
|
285
|
-
|
|
286
|
-
### sdk.number
|
|
287
|
-
|
|
288
|
-
Parse value as number (alias for parseFloat).
|
|
289
|
-
|
|
290
|
-
**Use case**: Generic number parsing when integer vs float doesn't matter
|
|
291
|
-
|
|
292
|
-
```json
|
|
293
|
-
{
|
|
294
|
-
"fields": {
|
|
295
|
-
"weight": {
|
|
296
|
-
"source": "product_weight",
|
|
297
|
-
"resolver": "sdk.number"
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
Same behavior as `sdk.parseFloat`.
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## Date Resolvers
|
|
308
|
-
|
|
309
|
-
### sdk.formatDate
|
|
310
|
-
|
|
311
|
-
Format date to ISO8601 (Fluent Commerce API format).
|
|
312
|
-
|
|
313
|
-
**Use case**: Convert dates to Fluent API format
|
|
314
|
-
|
|
315
|
-
```json
|
|
316
|
-
{
|
|
317
|
-
"fields": {
|
|
318
|
-
"expectedOn": {
|
|
319
|
-
"source": "delivery_date",
|
|
320
|
-
"resolver": "sdk.formatDate"
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
**Examples**:
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
"2025-01-15" → "2025-01-15T00:00:00.000Z"
|
|
330
|
-
"01/15/2025" → "2025-01-15T00:00:00.000Z"
|
|
331
|
-
Date object → "2025-01-15T10:30:00.000Z"
|
|
332
|
-
null → null (null-safe)
|
|
333
|
-
"invalid" → "invalid" (passes through)
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
**Critical**: Fluent Commerce API requires ISO8601 format for date fields.
|
|
337
|
-
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
### sdk.formatDateShort
|
|
341
|
-
|
|
342
|
-
Format date to YYYY-MM-DD (short format).
|
|
343
|
-
|
|
344
|
-
**Use case**: Convert dates to short format for reports, CSV exports
|
|
345
|
-
|
|
346
|
-
```json
|
|
347
|
-
{
|
|
348
|
-
"fields": {
|
|
349
|
-
"orderDate": {
|
|
350
|
-
"source": "created_at",
|
|
351
|
-
"resolver": "sdk.formatDateShort"
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**Examples**:
|
|
358
|
-
|
|
359
|
-
```typescript
|
|
360
|
-
"2025-01-15T10:30:00Z" → "2025-01-15"
|
|
361
|
-
Date object → "2025-01-15"
|
|
362
|
-
"invalid" → "invalid" (invalid dates pass through)
|
|
363
|
-
null → null (null-safe)
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
**Note**: Strips time component—useful for date-only fields.
|
|
367
|
-
|
|
368
|
-
---
|
|
369
|
-
|
|
370
|
-
### sdk.parseDate
|
|
371
|
-
|
|
372
|
-
Parse various date formats to Date object.
|
|
373
|
-
|
|
374
|
-
**Use case**: Convert multiple date formats to standardized Date
|
|
375
|
-
|
|
376
|
-
```json
|
|
377
|
-
{
|
|
378
|
-
"fields": {
|
|
379
|
-
"orderDate": {
|
|
380
|
-
"source": "order_date",
|
|
381
|
-
"resolver": "sdk.parseDate"
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
**Examples**:
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
"2025-01-15" → Date("2025-01-15T00:00:00.000Z")
|
|
391
|
-
"01/15/2025" → Date (US format)
|
|
392
|
-
"15/01/2025" → Date (EU format)
|
|
393
|
-
1737763200000 → Date (Unix timestamp)
|
|
394
|
-
null → null (null-safe)
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
**Handles**: ISO8601, US format, EU format, Unix timestamps.
|
|
398
|
-
|
|
399
|
-
---
|
|
400
|
-
|
|
401
|
-
## Type Conversion Resolvers
|
|
402
|
-
|
|
403
|
-
### sdk.boolean
|
|
404
|
-
|
|
405
|
-
Convert value to boolean.
|
|
406
|
-
|
|
407
|
-
**Use case**: Parse boolean flags from CSV, XML
|
|
408
|
-
|
|
409
|
-
```json
|
|
410
|
-
{
|
|
411
|
-
"fields": {
|
|
412
|
-
"isActive": {
|
|
413
|
-
"source": "active_flag",
|
|
414
|
-
"resolver": "sdk.boolean"
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
**Examples**:
|
|
421
|
-
|
|
422
|
-
```typescript
|
|
423
|
-
"true" → true
|
|
424
|
-
"false" → false
|
|
425
|
-
"1" → true
|
|
426
|
-
"0" → false
|
|
427
|
-
"yes" → true
|
|
428
|
-
"no" → false
|
|
429
|
-
"y" → true
|
|
430
|
-
"n" → false
|
|
431
|
-
"TRUE" → true (case-insensitive)
|
|
432
|
-
"True" → true
|
|
433
|
-
null → false (null-safe)
|
|
434
|
-
undefined → false
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
**Case-insensitive**: "TRUE", "True", "true" all return `true`.
|
|
438
|
-
|
|
439
|
-
---
|
|
440
|
-
|
|
441
|
-
### sdk.parseJson
|
|
442
|
-
|
|
443
|
-
Parse JSON string to object.
|
|
444
|
-
|
|
445
|
-
**Use case**: Parse JSON-encoded fields from CSV, XML attributes
|
|
446
|
-
|
|
447
|
-
```json
|
|
448
|
-
{
|
|
449
|
-
"fields": {
|
|
450
|
-
"metadata": {
|
|
451
|
-
"source": "custom_data",
|
|
452
|
-
"resolver": "sdk.parseJson"
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
**Examples**:
|
|
459
|
-
|
|
460
|
-
```typescript
|
|
461
|
-
'{"name":"John","age":30}' → { name: "John", age: 30 }
|
|
462
|
-
'["a","b","c"]' → ["a", "b", "c"]
|
|
463
|
-
"invalid json" → "invalid json" (passes through)
|
|
464
|
-
123 → 123 (non-strings pass through)
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
**Null-safe**: Returns original value if parse fails (never throws).
|
|
468
|
-
|
|
469
|
-
---
|
|
470
|
-
|
|
471
|
-
### sdk.toJson
|
|
472
|
-
|
|
473
|
-
Stringify value as JSON.
|
|
474
|
-
|
|
475
|
-
**Use case**: Convert objects to JSON strings for storage in text fields
|
|
476
|
-
|
|
477
|
-
```json
|
|
478
|
-
{
|
|
479
|
-
"fields": {
|
|
480
|
-
"customAttributes": {
|
|
481
|
-
"source": "attributes_obj",
|
|
482
|
-
"resolver": "sdk.toJson"
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
**Examples**:
|
|
489
|
-
|
|
490
|
-
```typescript
|
|
491
|
-
{ name: "John" } → '{"name":"John"}'
|
|
492
|
-
["a", "b", "c"] → '["a","b","c"]'
|
|
493
|
-
123 → "123"
|
|
494
|
-
"string" → '"string"' (double-quoted)
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
**Use case**: Storing complex objects in Fluent Commerce custom attributes.
|
|
498
|
-
|
|
499
|
-
---
|
|
500
|
-
|
|
501
|
-
## Utility Resolvers
|
|
502
|
-
|
|
503
|
-
### sdk.identity
|
|
504
|
-
|
|
505
|
-
Return value unchanged (no-op resolver).
|
|
506
|
-
|
|
507
|
-
**Use case**: Explicitly pass value through without transformation
|
|
508
|
-
|
|
509
|
-
```json
|
|
510
|
-
{
|
|
511
|
-
"fields": {
|
|
512
|
-
"ref": {
|
|
513
|
-
"source": "order_id",
|
|
514
|
-
"resolver": "sdk.identity"
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
**Why this exists**: Some mapping scenarios require a resolver to be specified, but no transformation is needed.
|
|
521
|
-
|
|
522
|
-
---
|
|
523
|
-
|
|
524
|
-
### sdk.coalesce
|
|
525
|
-
|
|
526
|
-
Return first non-null value.
|
|
527
|
-
|
|
528
|
-
**Use case**: Provide fallback when value is null/undefined
|
|
529
|
-
|
|
530
|
-
```json
|
|
531
|
-
{
|
|
532
|
-
"fields": {
|
|
533
|
-
"email": {
|
|
534
|
-
"source": "primary_email",
|
|
535
|
-
"resolver": "sdk.coalesce",
|
|
536
|
-
"defaultValue": "noreply@example.com"
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
**Note**: Typically handled by mapping engine checking `defaultValue`. This resolver exists for complex scenarios.
|
|
543
|
-
|
|
544
|
-
---
|
|
545
|
-
|
|
546
|
-
### sdk.default
|
|
547
|
-
|
|
548
|
-
Use the `defaultValue` field configuration property instead.
|
|
549
|
-
|
|
550
|
-
This resolver provides default value if source is null/undefined/empty, but `defaultValue` in field config is the preferred approach.
|
|
551
|
-
|
|
552
|
-
```json
|
|
553
|
-
{
|
|
554
|
-
"fields": {
|
|
555
|
-
"status": {
|
|
556
|
-
"source": "order_status",
|
|
557
|
-
"defaultValue": "ACTIVE",
|
|
558
|
-
"resolver": "sdk.default"
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
**Note**: The `defaultValue` field configuration property is preferred. This resolver applies after `config.defaultValue` is processed.
|
|
565
|
-
|
|
566
|
-
**Examples**:
|
|
567
|
-
|
|
568
|
-
```typescript
|
|
569
|
-
"PENDING" → "PENDING" (value exists, pass through)
|
|
570
|
-
null → null (defaultValue applied by mapper before resolver)
|
|
571
|
-
undefined → undefined (defaultValue applied by mapper before resolver)
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
**Note**: Prefer using the `defaultValue` field configuration property instead of this resolver.
|
|
575
|
-
|
|
576
|
-
---
|
|
577
|
-
|
|
578
|
-
## Helper Functions Reference
|
|
579
|
-
|
|
580
|
-
Custom resolvers receive a `helpers` object with 57 utility functions.
|
|
581
|
-
|
|
582
|
-
### Resolver Signature
|
|
583
|
-
|
|
584
|
-
```typescript
|
|
585
|
-
(value: any, sourceData: any, config: any, helpers: ResolverHelpers) => any | Promise<any>;
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
**Parameters**:
|
|
589
|
-
|
|
590
|
-
1. `value` - The extracted field value (may be undefined for generator resolvers)
|
|
591
|
-
2. `sourceData` - The complete source object (for context-aware transformations)
|
|
592
|
-
3. `config` - Resolver-specific configuration object
|
|
593
|
-
4. `helpers` - 57 utility functions
|
|
594
|
-
|
|
595
|
-
### Helper Categories
|
|
596
|
-
|
|
597
|
-
| Category | Count | Examples |
|
|
598
|
-
| ----------------------- | ----- | ------------------------------------------------------- |
|
|
599
|
-
| **Data Access** | 4 | get, set, ensureArray, coalesce |
|
|
600
|
-
| **String Manipulation** | 8 | toCamelCase, toSnakeCase, truncate, normalizeWhitespace |
|
|
601
|
-
| **Number Operations** | 3 | parseIntSafe, parseFloatSafe, formatCurrency |
|
|
602
|
-
| **Date/Time** | 4 | formatDate, parseDate, addDays, subtractDays |
|
|
603
|
-
| **Validation** | 3 | isValidEmail, requireField, isEmpty |
|
|
604
|
-
| **Object Utilities** | 6 | deepClone, deepMerge, pick, omit, merge, template |
|
|
605
|
-
| **Array Operations** | 9 | unique, groupBy, sortBy, chunk, flatten, compact, sum, avg, min |
|
|
606
|
-
| **Performance** | 3 | memoize, batchProcess, retry |
|
|
607
|
-
| **Type Guards** | 5 | isString, isNumber, isArray, isObject, isDate |
|
|
608
|
-
| **Utilities** | 9 | defaultTo, range, clamp, slugify, uuid, hashString, debounce, throttle, safeJsonParse |
|
|
609
|
-
|
|
610
|
-
**Total**: 57 helpers
|
|
611
|
-
|
|
612
|
-
### Core Data Access Helpers
|
|
613
|
-
|
|
614
|
-
```typescript
|
|
615
|
-
helpers.get(obj, 'customer.address.city'); // Safe nested access
|
|
616
|
-
helpers.set(obj, 'customer.address.city', 'NYC'); // Safe nested set
|
|
617
|
-
helpers.ensureArray(value); // Wrap singles in array
|
|
618
|
-
helpers.coalesce(val1, val2, val3); // First non-null
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
### String Helpers
|
|
622
|
-
|
|
623
|
-
```typescript
|
|
624
|
-
helpers.toCamelCase('first_name'); // → "firstName"
|
|
625
|
-
helpers.toSnakeCase('firstName'); // → "first_name"
|
|
626
|
-
helpers.truncate('Long text...', 10); // → "Long te..."
|
|
627
|
-
helpers.normalizeWhitespace(' a b '); // → "a b"
|
|
628
|
-
helpers.fullName('John', 'Doe'); // → "John Doe"
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
### Number Helpers
|
|
632
|
-
|
|
633
|
-
```typescript
|
|
634
|
-
helpers.parseIntSafe('123', 0); // → 123 (or default 0)
|
|
635
|
-
helpers.parseFloatSafe('$99.99', 0); // → 99.99
|
|
636
|
-
helpers.formatCurrency(99.99, 2); // → "99.99"
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
### Date Helpers
|
|
640
|
-
|
|
641
|
-
```typescript
|
|
642
|
-
helpers.formatDate('2025-01-15'); // → ISO8601
|
|
643
|
-
helpers.parseDate('01/15/2025'); // → Date object
|
|
644
|
-
helpers.addDays(new Date(), 7); // → Date + 7 days
|
|
645
|
-
helpers.diffDays(date1, date2); // → number of days
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
### Validation Helpers
|
|
649
|
-
|
|
650
|
-
```typescript
|
|
651
|
-
helpers.isValidEmail('test@example.com'); // → true
|
|
652
|
-
helpers.requireField(value, 'email'); // Throws if null
|
|
653
|
-
helpers.isEmpty(value); // → true if null/undefined/empty
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### Object Helpers
|
|
657
|
-
|
|
658
|
-
```typescript
|
|
659
|
-
helpers.deepClone(obj); // Deep copy
|
|
660
|
-
helpers.deepMerge(obj1, obj2); // Merge objects
|
|
661
|
-
helpers.pick(obj, ['name', 'email']); // Extract fields
|
|
662
|
-
helpers.omit(obj, ['password']); // Remove fields
|
|
663
|
-
helpers.flatten(nestedObj); // Flatten to dot notation
|
|
664
|
-
```
|
|
665
|
-
|
|
666
|
-
### Array Helpers
|
|
667
|
-
|
|
668
|
-
```typescript
|
|
669
|
-
helpers.unique([1, 2, 2, 3]); // → [1, 2, 3]
|
|
670
|
-
helpers.groupBy(items, 'category'); // Group by field
|
|
671
|
-
helpers.sortBy(items, 'name'); // Sort by field
|
|
672
|
-
helpers.chunk([1, 2, 3, 4, 5], 2); // → [[1,2], [3,4], [5]]
|
|
673
|
-
helpers.findBy(items, 'id', '123'); // Find by field value
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
### Performance Helpers
|
|
677
|
-
|
|
678
|
-
```typescript
|
|
679
|
-
await helpers.retry(() => apiCall(), 3, 1000); // Retry with backoff
|
|
680
|
-
await helpers.batchProcess(items, processFn, 100); // Process in batches
|
|
681
|
-
const memoized = helpers.memoize(expensiveFn); // Cache results
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
### Utilities
|
|
685
|
-
|
|
686
|
-
```typescript
|
|
687
|
-
const hash = helpers.hashString('data'); // Simple hash
|
|
688
|
-
const id = helpers.uuid(); // Generate UUID
|
|
689
|
-
const slug = helpers.slugify('Product Name'); // → "product-name"
|
|
690
|
-
helpers.debounce(fn, 300); // Debounce function calls
|
|
691
|
-
helpers.throttle(fn, 1000); // Throttle function calls
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
---
|
|
695
|
-
|
|
696
|
-
## Custom Resolvers
|
|
697
|
-
|
|
698
|
-
### Basic Custom Resolver
|
|
699
|
-
|
|
700
|
-
```typescript
|
|
701
|
-
const customResolvers = {
|
|
702
|
-
'custom.buildRef': (value, sourceData, config, helpers) => {
|
|
703
|
-
const sku = sourceData.sku;
|
|
704
|
-
const location = sourceData.location;
|
|
705
|
-
return `${sku}-${location}`;
|
|
706
|
-
},
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
// Use in mapping
|
|
710
|
-
const mapper = new UniversalMapper(mappingConfig, { customResolvers });
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
### Using Helpers in Custom Resolvers
|
|
714
|
-
|
|
715
|
-
```typescript
|
|
716
|
-
const customResolvers = {
|
|
717
|
-
'custom.formatCustomerName': (value, sourceData, config, helpers) => {
|
|
718
|
-
const firstName = helpers.get(sourceData, 'customer.firstName');
|
|
719
|
-
const lastName = helpers.get(sourceData, 'customer.lastName');
|
|
720
|
-
return helpers.fullName(firstName, lastName);
|
|
721
|
-
},
|
|
722
|
-
|
|
723
|
-
'custom.calculateTotal': (value, sourceData, config, helpers) => {
|
|
724
|
-
const price = helpers.parseFloatSafe(sourceData.price, 0);
|
|
725
|
-
const qty = helpers.parseIntSafe(sourceData.quantity, 0);
|
|
726
|
-
const tax = helpers.parseFloatSafe(sourceData.tax, 0);
|
|
727
|
-
return price * qty + tax;
|
|
728
|
-
},
|
|
729
|
-
|
|
730
|
-
'custom.normalizeEmail': (value, sourceData, config, helpers) => {
|
|
731
|
-
if (!value || typeof value !== 'string') return null;
|
|
732
|
-
|
|
733
|
-
const email = helpers.normalizeWhitespace(value.toLowerCase().trim());
|
|
734
|
-
|
|
735
|
-
if (!helpers.isValidEmail(email)) {
|
|
736
|
-
helpers.logger?.warn('Invalid email', { email });
|
|
737
|
-
return null;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
return email;
|
|
741
|
-
},
|
|
742
|
-
};
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
### Context-Aware Resolvers
|
|
746
|
-
|
|
747
|
-
```typescript
|
|
748
|
-
const customResolvers = {
|
|
749
|
-
'custom.mapOrderType': (value, sourceData, config, helpers) => {
|
|
750
|
-
// Access shared configuration from context
|
|
751
|
-
const environment = helpers.context.environment || 'production';
|
|
752
|
-
|
|
753
|
-
const mapping: Record<string, string> = {
|
|
754
|
-
online: 'HD', // Home Delivery
|
|
755
|
-
store: 'CC', // Click & Collect
|
|
756
|
-
};
|
|
757
|
-
|
|
758
|
-
const orderType = mapping[value] || 'HD';
|
|
759
|
-
|
|
760
|
-
// In non-production, append test suffix
|
|
761
|
-
if (environment !== 'production') {
|
|
762
|
-
return `${orderType}_TEST`;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
return orderType;
|
|
766
|
-
},
|
|
767
|
-
};
|
|
768
|
-
|
|
769
|
-
// Pass context when mapping
|
|
770
|
-
const mapper = new UniversalMapper(mappingConfig, {
|
|
771
|
-
customResolvers,
|
|
772
|
-
fluentClient: client,
|
|
773
|
-
});
|
|
774
|
-
const result = await mapper.map(data);
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
---
|
|
778
|
-
|
|
779
|
-
## Async Resolvers
|
|
780
|
-
|
|
781
|
-
Custom resolvers can be asynchronous for external API calls, database lookups, etc.
|
|
782
|
-
|
|
783
|
-
### Async Lookup Example
|
|
784
|
-
|
|
785
|
-
```typescript
|
|
786
|
-
const customResolvers = {
|
|
787
|
-
'custom.lookupCustomer': async (value, sourceData, config, helpers) => {
|
|
788
|
-
const email = sourceData.customer_email;
|
|
789
|
-
|
|
790
|
-
if (!email) {
|
|
791
|
-
return null;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
// Query Fluent API for existing customer
|
|
795
|
-
const result = await helpers.fluentClient.graphql({
|
|
796
|
-
query: `
|
|
797
|
-
query GetCustomer($email: String) {
|
|
798
|
-
customers(primaryEmail: $email, first: 1) {
|
|
799
|
-
edges {
|
|
800
|
-
node {
|
|
801
|
-
id
|
|
802
|
-
username
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
`,
|
|
808
|
-
variables: { email },
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
const existingCustomer = result?.customers?.edges?.[0]?.node;
|
|
812
|
-
|
|
813
|
-
if (existingCustomer) {
|
|
814
|
-
helpers.logger?.info('Found existing customer', { customerId: existingCustomer.id });
|
|
815
|
-
return existingCustomer.id;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
// Customer not found - create new
|
|
819
|
-
const createResult = await helpers.fluentClient.graphql({
|
|
820
|
-
query: `
|
|
821
|
-
mutation CreateCustomer($input: CreateCustomerInput!) {
|
|
822
|
-
createCustomer(input: $input) {
|
|
823
|
-
id
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
`,
|
|
827
|
-
variables: {
|
|
828
|
-
input: {
|
|
829
|
-
username: email,
|
|
830
|
-
primaryEmail: email,
|
|
831
|
-
firstName: sourceData.first_name || 'Guest',
|
|
832
|
-
lastName: sourceData.last_name || 'Customer',
|
|
833
|
-
retailer: { id: '2' },
|
|
834
|
-
},
|
|
835
|
-
},
|
|
836
|
-
});
|
|
837
|
-
|
|
838
|
-
helpers.logger?.info('Created new customer', { customerId: createResult.id });
|
|
839
|
-
|
|
840
|
-
return createResult.id;
|
|
841
|
-
},
|
|
842
|
-
};
|
|
843
|
-
```
|
|
844
|
-
|
|
845
|
-
**Important**: When using async resolvers, you must `await` the mapping:
|
|
846
|
-
|
|
847
|
-
```typescript
|
|
848
|
-
const result = await mapper.map(data, {
|
|
849
|
-
fluentClient: client,
|
|
850
|
-
helpers: { fluentClient: client },
|
|
851
|
-
});
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
### Async with Retry
|
|
855
|
-
|
|
856
|
-
```typescript
|
|
857
|
-
const customResolvers = {
|
|
858
|
-
'custom.fetchProductPrice': async (value, sourceData, config, helpers) => {
|
|
859
|
-
const sku = sourceData.sku;
|
|
860
|
-
|
|
861
|
-
// Retry API call up to 3 times with 1s delay
|
|
862
|
-
const price = await helpers.retry(
|
|
863
|
-
async () => {
|
|
864
|
-
const response = await fetch(`https://api.example.com/products/${sku}/price`);
|
|
865
|
-
|
|
866
|
-
if (!response.ok) {
|
|
867
|
-
throw new Error(`HTTP ${response.status}`);
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
const data = await response.json();
|
|
871
|
-
return data.price;
|
|
872
|
-
},
|
|
873
|
-
3,
|
|
874
|
-
1000
|
|
875
|
-
);
|
|
876
|
-
|
|
877
|
-
return price;
|
|
878
|
-
},
|
|
879
|
-
};
|
|
880
|
-
```
|
|
881
|
-
|
|
882
|
-
### Batch Processing (Performance Optimization)
|
|
883
|
-
|
|
884
|
-
```typescript
|
|
885
|
-
// ❌ BAD: Sequential API calls (slow for 1000 records)
|
|
886
|
-
'custom.lookupCustomerSlow': async (value, sourceData, config, helpers) => {
|
|
887
|
-
const email = sourceData.email;
|
|
888
|
-
const result = await helpers.fluentClient.graphql({ query, variables: { email } });
|
|
889
|
-
return result?.customers?.edges?.[0]?.node?.id;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
// ✅ GOOD: Batch cache to reduce API calls
|
|
893
|
-
const customerCache = new Map();
|
|
894
|
-
|
|
895
|
-
const customResolvers = {
|
|
896
|
-
'custom.lookupCustomerFast': async (value, sourceData, config, helpers) => {
|
|
897
|
-
const email = sourceData.email;
|
|
898
|
-
|
|
899
|
-
// Check cache first
|
|
900
|
-
if (customerCache.has(email)) {
|
|
901
|
-
return customerCache.get(email);
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
// Query API
|
|
905
|
-
const result = await helpers.fluentClient.graphql({
|
|
906
|
-
query,
|
|
907
|
-
variables: { email }
|
|
908
|
-
});
|
|
909
|
-
|
|
910
|
-
const customerId = result?.customers?.edges?.[0]?.node?.id;
|
|
911
|
-
|
|
912
|
-
// Cache result
|
|
913
|
-
customerCache.set(email, customerId);
|
|
914
|
-
|
|
915
|
-
return customerId;
|
|
916
|
-
}
|
|
917
|
-
};
|
|
918
|
-
```
|
|
919
|
-
|
|
920
|
-
---
|
|
921
|
-
|
|
922
|
-
## Best Practices
|
|
923
|
-
|
|
924
|
-
### 1. Use SDK Resolvers First
|
|
925
|
-
|
|
926
|
-
Before writing custom resolvers, check if SDK resolvers can handle the transformation:
|
|
927
|
-
|
|
928
|
-
```typescript
|
|
929
|
-
// ❌ NOT NEEDED
|
|
930
|
-
'custom.toUppercase': (value) => value?.toUpperCase()
|
|
931
|
-
|
|
932
|
-
// ✅ USE SDK RESOLVER
|
|
933
|
-
{ "resolver": "sdk.uppercase" }
|
|
934
|
-
```
|
|
935
|
-
|
|
936
|
-
### 2. Keep Resolvers Pure
|
|
937
|
-
|
|
938
|
-
Resolvers should be pure functions (same input → same output, no side effects):
|
|
939
|
-
|
|
940
|
-
```typescript
|
|
941
|
-
// ❌ BAD: Side effects (modifies external state)
|
|
942
|
-
let counter = 0;
|
|
943
|
-
'custom.increment': (value) => {
|
|
944
|
-
counter++; // Side effect!
|
|
945
|
-
return value;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
// ✅ GOOD: Pure function
|
|
949
|
-
'custom.incrementValue': (value) => {
|
|
950
|
-
return (value || 0) + 1;
|
|
951
|
-
}
|
|
952
|
-
```
|
|
953
|
-
|
|
954
|
-
### 3. Handle Null/Undefined
|
|
955
|
-
|
|
956
|
-
Always handle null/undefined gracefully:
|
|
957
|
-
|
|
958
|
-
```typescript
|
|
959
|
-
// ❌ BAD: Throws on null
|
|
960
|
-
'custom.getLength': (value) => value.length // Throws if value is null
|
|
961
|
-
|
|
962
|
-
// ✅ GOOD: Null-safe
|
|
963
|
-
'custom.getLength': (value) => value?.length || 0
|
|
964
|
-
```
|
|
965
|
-
|
|
966
|
-
### 4. Use Helpers for Common Operations
|
|
967
|
-
|
|
968
|
-
Don't reinvent the wheel—use helpers:
|
|
969
|
-
|
|
970
|
-
```typescript
|
|
971
|
-
// ❌ BAD: Manual parsing
|
|
972
|
-
'custom.parsePrice': (value) => {
|
|
973
|
-
const num = parseFloat(value.replace(/[^0-9.]/g, ''));
|
|
974
|
-
return isNaN(num) ? 0 : num;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// ✅ GOOD: Use helper
|
|
978
|
-
'custom.parsePrice': (value, sourceData, config, helpers) => {
|
|
979
|
-
return helpers.parseFloatSafe(value, 0);
|
|
980
|
-
}
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
### 5. Document Custom Resolvers
|
|
984
|
-
|
|
985
|
-
Add comments to explain complex logic:
|
|
986
|
-
|
|
987
|
-
```typescript
|
|
988
|
-
const customResolvers = {
|
|
989
|
-
/**
|
|
990
|
-
* Calculate item total: (price * qty) + tax + shipping
|
|
991
|
-
* Returns 0 if any values are invalid
|
|
992
|
-
*/
|
|
993
|
-
'custom.calculateItemTotal': (value, sourceData, config, helpers) => {
|
|
994
|
-
const price = helpers.parseFloatSafe(sourceData.price, 0);
|
|
995
|
-
const qty = helpers.parseIntSafe(sourceData.quantity, 0);
|
|
996
|
-
const tax = helpers.parseFloatSafe(sourceData.tax, 0);
|
|
997
|
-
const shipping = helpers.parseFloatSafe(sourceData.shipping, 0);
|
|
998
|
-
|
|
999
|
-
return price * qty + tax + shipping;
|
|
1000
|
-
},
|
|
1001
|
-
};
|
|
1002
|
-
```
|
|
1003
|
-
|
|
1004
|
-
### 6. Use Logging for Debugging
|
|
1005
|
-
|
|
1006
|
-
Use `helpers.logger` for debugging complex resolvers:
|
|
1007
|
-
|
|
1008
|
-
```typescript
|
|
1009
|
-
'custom.mapOrderType': (value, sourceData, config, helpers) => {
|
|
1010
|
-
helpers.logger?.debug('Mapping order type', {
|
|
1011
|
-
inputValue: value,
|
|
1012
|
-
sourceOrderType: sourceData.order_type
|
|
1013
|
-
});
|
|
1014
|
-
|
|
1015
|
-
const mapped = orderTypeMapping[value] || 'HD';
|
|
1016
|
-
|
|
1017
|
-
helpers.logger?.debug('Mapped order type', {
|
|
1018
|
-
input: value,
|
|
1019
|
-
output: mapped
|
|
1020
|
-
});
|
|
1021
|
-
|
|
1022
|
-
return mapped;
|
|
1023
|
-
}
|
|
1024
|
-
```
|
|
1025
|
-
|
|
1026
|
-
---
|
|
1027
|
-
|
|
1028
|
-
## Performance Optimization
|
|
1029
|
-
|
|
1030
|
-
### 1. Memoize Expensive Operations
|
|
1031
|
-
|
|
1032
|
-
```typescript
|
|
1033
|
-
const expensiveCalculation = helpers.memoize((value) => {
|
|
1034
|
-
// Complex calculation here
|
|
1035
|
-
return result;
|
|
1036
|
-
});
|
|
1037
|
-
|
|
1038
|
-
'custom.calculate': (value) => expensiveCalculation(value)
|
|
1039
|
-
```
|
|
1040
|
-
|
|
1041
|
-
### 2. Cache API Lookups
|
|
1042
|
-
|
|
1043
|
-
```typescript
|
|
1044
|
-
const cache = new Map();
|
|
1045
|
-
|
|
1046
|
-
'custom.lookup': async (value, sourceData, config, helpers) => {
|
|
1047
|
-
if (cache.has(value)) {
|
|
1048
|
-
return cache.get(value);
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
const result = await apiCall(value);
|
|
1052
|
-
cache.set(value, result);
|
|
1053
|
-
return result;
|
|
1054
|
-
}
|
|
1055
|
-
```
|
|
1056
|
-
|
|
1057
|
-
### 3. Batch Process Arrays
|
|
1058
|
-
|
|
1059
|
-
```typescript
|
|
1060
|
-
'custom.processItems': async (value, sourceData, config, helpers) => {
|
|
1061
|
-
const items = helpers.ensureArray(value);
|
|
1062
|
-
|
|
1063
|
-
// Process 100 items at a time
|
|
1064
|
-
const results = await helpers.batchProcess(
|
|
1065
|
-
items,
|
|
1066
|
-
async (item) => await processItem(item),
|
|
1067
|
-
100
|
|
1068
|
-
);
|
|
1069
|
-
|
|
1070
|
-
return results;
|
|
1071
|
-
}
|
|
1072
|
-
```
|
|
1073
|
-
|
|
1074
|
-
### 4. Avoid Nested Loops
|
|
1075
|
-
|
|
1076
|
-
```typescript
|
|
1077
|
-
// ❌ BAD: O(n²) complexity
|
|
1078
|
-
'custom.findMatch': (value, sourceData) => {
|
|
1079
|
-
for (const item of sourceData.items) {
|
|
1080
|
-
for (const match of sourceData.matches) {
|
|
1081
|
-
if (item.id === match.id) return match;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
// ✅ GOOD: O(n) complexity
|
|
1087
|
-
'custom.findMatch': (value, sourceData, config, helpers) => {
|
|
1088
|
-
const matchMap = new Map(sourceData.matches.map(m => [m.id, m]));
|
|
1089
|
-
return matchMap.get(value);
|
|
1090
|
-
}
|
|
1091
|
-
```
|
|
1092
|
-
|
|
1093
|
-
---
|
|
1094
|
-
|
|
1095
|
-
## Next Steps
|
|
1096
|
-
|
|
1097
|
-
You've mastered all SDK resolvers and helper functions! Next:
|
|
1098
|
-
|
|
1099
|
-
**Continue to:** [Module 7: API Reference →](../../auto-pagination/modules/auto-pagination-07-api-reference.md)
|
|
1100
|
-
|
|
1101
|
-
Or explore:
|
|
1102
|
-
|
|
1103
|
-
- [GraphQL Mutation Mapping Quick Reference](../graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md) - Comprehensive cheat sheet
|
|
1104
|
-
- [Examples](../examples/) - Complete working examples
|
|
1105
|
-
- [Module 5: Advanced Patterns](./mapping-05-advanced-patterns.md) - Review complex patterns
|
|
1106
|
-
|
|
1107
|
-
---
|
|
1108
|
-
|
|
1109
|
-
## Additional Resources
|
|
1110
|
-
|
|
1111
|
-
- [SDK Resolvers Source Code](../../../../src/services/resolvers/sdk-resolvers.ts)
|
|
1112
|
-
- [Resolver Engine Source](../../../../src/services/resolvers/resolver-engine.ts)
|
|
1113
|
-
- [Helper Functions Reference](../../../../src/services/resolvers/resolver-helpers.ts)
|
|
1114
|
-
|
|
1115
|
-
---
|
|
1116
|
-
|
|
1117
|
-
[← Back to Index](../mapping-readme.md) | [Previous: Advanced Patterns](./mapping-05-advanced-patterns.md) | [Next: API Reference →](../../auto-pagination/modules/auto-pagination-07-api-reference.md)
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1
|
+
# Module 6: Helpers & Resolvers
|
|
2
|
+
|
|
3
|
+
**Leverage 54 Built-in Utilities**
|
|
4
|
+
|
|
5
|
+
**Level:** Advanced
|
|
6
|
+
**Time:** 35 minutes
|
|
7
|
+
**Prerequisites:** [Module 5: Advanced Patterns](./mapping-05-advanced-patterns.md)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Learning Objectives
|
|
12
|
+
|
|
13
|
+
After completing this module, you will:
|
|
14
|
+
|
|
15
|
+
- ✅ Understand all 16 SDK resolvers
|
|
16
|
+
- ✅ Use 57 helper functions in custom resolvers
|
|
17
|
+
- ✅ Write efficient custom resolvers
|
|
18
|
+
- ✅ Implement async resolvers for API lookups
|
|
19
|
+
- ✅ Apply resolver best practices
|
|
20
|
+
- ✅ Optimize resolver performance
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
1. [SDK Resolvers Overview](#sdk-resolvers-overview)
|
|
27
|
+
2. [String Resolvers](#string-resolvers)
|
|
28
|
+
3. [Number Resolvers](#number-resolvers)
|
|
29
|
+
4. [Date Resolvers](#date-resolvers)
|
|
30
|
+
5. [Type Conversion Resolvers](#type-conversion-resolvers)
|
|
31
|
+
6. [Utility Resolvers](#utility-resolvers)
|
|
32
|
+
7. [Helper Functions Reference](#helper-functions-reference)
|
|
33
|
+
8. [Custom Resolvers](#custom-resolvers)
|
|
34
|
+
9. [Async Resolvers](#async-resolvers)
|
|
35
|
+
10. [Best Practices](#best-practices)
|
|
36
|
+
11. [Performance Optimization](#performance-optimization)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## SDK Resolvers Overview
|
|
41
|
+
|
|
42
|
+
The SDK provides **16 built-in resolvers** for common transformations. All SDK resolvers:
|
|
43
|
+
|
|
44
|
+
- ✅ Follow naming convention: `sdk.<functionName>`
|
|
45
|
+
- ✅ Are null-safe (never throw errors)
|
|
46
|
+
- ✅ Return safe defaults for invalid input
|
|
47
|
+
- ✅ Work with all mappers (UniversalMapper, GraphQLMutationMapper)
|
|
48
|
+
|
|
49
|
+
### Complete SDK Resolver List
|
|
50
|
+
|
|
51
|
+
| Category | Resolvers | Count |
|
|
52
|
+
| ----------- | -------------------------------------- | ----- |
|
|
53
|
+
| **String** | uppercase, lowercase, trim, toString | 4 |
|
|
54
|
+
| **Number** | parseInt, parseFloat, number | 3 |
|
|
55
|
+
| **Date** | formatDate, formatDateShort, parseDate | 3 |
|
|
56
|
+
| **Type** | boolean, parseJson, toJson | 3 |
|
|
57
|
+
| **Utility** | identity, coalesce, default | 3 |
|
|
58
|
+
|
|
59
|
+
**Total**: 16 SDK resolvers
|
|
60
|
+
|
|
61
|
+
### Accessing SDK Resolvers Programmatically (NEW)
|
|
62
|
+
|
|
63
|
+
You can access SDK resolvers directly or test resolver names at runtime.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import {
|
|
67
|
+
sdkResolvers,
|
|
68
|
+
getSdkResolver,
|
|
69
|
+
isSdkResolver,
|
|
70
|
+
getSdkResolverNames,
|
|
71
|
+
UniversalMapper,
|
|
72
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
73
|
+
|
|
74
|
+
// Get all SDK resolver names
|
|
75
|
+
const allResolvers = getSdkResolverNames();
|
|
76
|
+
console.log(allResolvers);
|
|
77
|
+
// SDK resolvers: ['sdk.uppercase', 'sdk.lowercase', 'sdk.trim', 'sdk.parseInt', ...]
|
|
78
|
+
|
|
79
|
+
// Retrieve a resolver function by name
|
|
80
|
+
const resolverFn = getSdkResolver('sdk.parseInt'); // (value) => number
|
|
81
|
+
console.log(isSdkResolver('sdk.parseInt')); // true
|
|
82
|
+
console.log(isSdkResolver('custom.myResolver')); // false
|
|
83
|
+
|
|
84
|
+
// Use sdkResolvers inside custom resolvers
|
|
85
|
+
const mapper = new UniversalMapper(mappingConfig, {
|
|
86
|
+
customResolvers: {
|
|
87
|
+
'custom.upperTrim': (value: any) => {
|
|
88
|
+
const upper = sdkResolvers\['sdk.uppercase'](value, null, null, {});
|
|
89
|
+
return sdkResolvers\['sdk.trim'](upper, null, null, {});
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Utility Functions:**
|
|
96
|
+
|
|
97
|
+
- `getSdkResolverNames()` - Returns array of all SDK resolver names (useful for validation, autocomplete)
|
|
98
|
+
- `getSdkResolver(name)` - Returns resolver function by name or undefined
|
|
99
|
+
- `isSdkResolver(name)` - Checks if a resolver name starts with 'sdk.'
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## String Resolvers
|
|
104
|
+
|
|
105
|
+
### sdk.uppercase
|
|
106
|
+
|
|
107
|
+
Convert string to uppercase.
|
|
108
|
+
|
|
109
|
+
**Use case**: Normalize SKU codes, status values, country codes
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"fields": {
|
|
114
|
+
"status": {
|
|
115
|
+
"source": "order_status",
|
|
116
|
+
"resolver": "sdk.uppercase"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Examples**:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
"active" → "ACTIVE"
|
|
126
|
+
"pending" → "PENDING"
|
|
127
|
+
123 → 123 (non-strings pass through)
|
|
128
|
+
null → null (null-safe)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Null-safe behavior**: Returns non-strings unchanged
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### sdk.lowercase
|
|
136
|
+
|
|
137
|
+
Convert string to lowercase.
|
|
138
|
+
|
|
139
|
+
**Use case**: Normalize email addresses, usernames, tags
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"fields": {
|
|
144
|
+
"email": {
|
|
145
|
+
"source": "customer_email",
|
|
146
|
+
"resolver": "sdk.lowercase"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Examples**:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
"John@EXAMPLE.COM" → "john@example.com"
|
|
156
|
+
"SKU-001" → "sku-001"
|
|
157
|
+
123 → 123 (non-strings pass through)
|
|
158
|
+
null → null (null-safe)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### sdk.trim
|
|
164
|
+
|
|
165
|
+
Remove leading and trailing whitespace.
|
|
166
|
+
|
|
167
|
+
**Use case**: Clean CSV fields, remove spaces from user input
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"fields": {
|
|
172
|
+
"sku": {
|
|
173
|
+
"source": "product_code",
|
|
174
|
+
"resolver": "sdk.trim"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Examples**:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
" SKU123 " → "SKU123"
|
|
184
|
+
"\tSKU456\n" → "SKU456"
|
|
185
|
+
" " → "" (empty after trim)
|
|
186
|
+
123 → 123 (non-strings pass through)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### sdk.toString
|
|
192
|
+
|
|
193
|
+
Convert value to string.
|
|
194
|
+
|
|
195
|
+
**Use case**: Ensure value is string type, prevent "null" strings
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"fields": {
|
|
200
|
+
"productRef": {
|
|
201
|
+
"source": "product_id",
|
|
202
|
+
"resolver": "sdk.toString"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Examples**:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
123 → "123"
|
|
212
|
+
true → "true"
|
|
213
|
+
null → "" (empty string, NOT "null")
|
|
214
|
+
undefined → "" (empty string, NOT "undefined")
|
|
215
|
+
{ foo: "bar" } → "[object Object]"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Critical**: Returns empty string for null/undefined (prevents literal "null"/"undefined" strings)
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Number Resolvers
|
|
223
|
+
|
|
224
|
+
### sdk.parseInt
|
|
225
|
+
|
|
226
|
+
Parse value as integer.
|
|
227
|
+
|
|
228
|
+
**Use case**: Convert quantity strings to numbers, parse IDs
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"fields": {
|
|
233
|
+
"quantity": {
|
|
234
|
+
"source": "qty",
|
|
235
|
+
"resolver": "sdk.parseInt"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Examples**:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
"123" → 123
|
|
245
|
+
"123.99" → 123 (truncates decimals)
|
|
246
|
+
"$45" → 0 (invalid → default)
|
|
247
|
+
"abc" → 0 (invalid → default)
|
|
248
|
+
null → 0 (null-safe default)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Important**: Returns `0` for invalid values (NOT `NaN`). This prevents breaking Fluent API calls.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### sdk.parseFloat
|
|
256
|
+
|
|
257
|
+
Parse value as floating-point number.
|
|
258
|
+
|
|
259
|
+
**Use case**: Convert price/weight strings to numbers
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"fields": {
|
|
264
|
+
"price": {
|
|
265
|
+
"source": "total_price",
|
|
266
|
+
"resolver": "sdk.parseFloat"
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Examples**:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
"123.99" → 123.99
|
|
276
|
+
"$45.50" → 45.5 (strips currency symbols)
|
|
277
|
+
"1,234.56" → 1234.56 (removes commas)
|
|
278
|
+
" 99.99 " → 99.99 (trims whitespace)
|
|
279
|
+
"abc" → 0 (invalid → default)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Advanced**: Handles currency symbols ($, €, £), commas, and whitespace automatically.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### sdk.number
|
|
287
|
+
|
|
288
|
+
Parse value as number (alias for parseFloat).
|
|
289
|
+
|
|
290
|
+
**Use case**: Generic number parsing when integer vs float doesn't matter
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"fields": {
|
|
295
|
+
"weight": {
|
|
296
|
+
"source": "product_weight",
|
|
297
|
+
"resolver": "sdk.number"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Same behavior as `sdk.parseFloat`.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Date Resolvers
|
|
308
|
+
|
|
309
|
+
### sdk.formatDate
|
|
310
|
+
|
|
311
|
+
Format date to ISO8601 (Fluent Commerce API format).
|
|
312
|
+
|
|
313
|
+
**Use case**: Convert dates to Fluent API format
|
|
314
|
+
|
|
315
|
+
```json
|
|
316
|
+
{
|
|
317
|
+
"fields": {
|
|
318
|
+
"expectedOn": {
|
|
319
|
+
"source": "delivery_date",
|
|
320
|
+
"resolver": "sdk.formatDate"
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Examples**:
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
"2025-01-15" → "2025-01-15T00:00:00.000Z"
|
|
330
|
+
"01/15/2025" → "2025-01-15T00:00:00.000Z"
|
|
331
|
+
Date object → "2025-01-15T10:30:00.000Z"
|
|
332
|
+
null → null (null-safe)
|
|
333
|
+
"invalid" → "invalid" (passes through)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Critical**: Fluent Commerce API requires ISO8601 format for date fields.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### sdk.formatDateShort
|
|
341
|
+
|
|
342
|
+
Format date to YYYY-MM-DD (short format).
|
|
343
|
+
|
|
344
|
+
**Use case**: Convert dates to short format for reports, CSV exports
|
|
345
|
+
|
|
346
|
+
```json
|
|
347
|
+
{
|
|
348
|
+
"fields": {
|
|
349
|
+
"orderDate": {
|
|
350
|
+
"source": "created_at",
|
|
351
|
+
"resolver": "sdk.formatDateShort"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Examples**:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
"2025-01-15T10:30:00Z" → "2025-01-15"
|
|
361
|
+
Date object → "2025-01-15"
|
|
362
|
+
"invalid" → "invalid" (invalid dates pass through)
|
|
363
|
+
null → null (null-safe)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Note**: Strips time component—useful for date-only fields.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### sdk.parseDate
|
|
371
|
+
|
|
372
|
+
Parse various date formats to Date object.
|
|
373
|
+
|
|
374
|
+
**Use case**: Convert multiple date formats to standardized Date
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"fields": {
|
|
379
|
+
"orderDate": {
|
|
380
|
+
"source": "order_date",
|
|
381
|
+
"resolver": "sdk.parseDate"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Examples**:
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
"2025-01-15" → Date("2025-01-15T00:00:00.000Z")
|
|
391
|
+
"01/15/2025" → Date (US format)
|
|
392
|
+
"15/01/2025" → Date (EU format)
|
|
393
|
+
1737763200000 → Date (Unix timestamp)
|
|
394
|
+
null → null (null-safe)
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Handles**: ISO8601, US format, EU format, Unix timestamps.
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Type Conversion Resolvers
|
|
402
|
+
|
|
403
|
+
### sdk.boolean
|
|
404
|
+
|
|
405
|
+
Convert value to boolean.
|
|
406
|
+
|
|
407
|
+
**Use case**: Parse boolean flags from CSV, XML
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
{
|
|
411
|
+
"fields": {
|
|
412
|
+
"isActive": {
|
|
413
|
+
"source": "active_flag",
|
|
414
|
+
"resolver": "sdk.boolean"
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Examples**:
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
"true" → true
|
|
424
|
+
"false" → false
|
|
425
|
+
"1" → true
|
|
426
|
+
"0" → false
|
|
427
|
+
"yes" → true
|
|
428
|
+
"no" → false
|
|
429
|
+
"y" → true
|
|
430
|
+
"n" → false
|
|
431
|
+
"TRUE" → true (case-insensitive)
|
|
432
|
+
"True" → true
|
|
433
|
+
null → false (null-safe)
|
|
434
|
+
undefined → false
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Case-insensitive**: "TRUE", "True", "true" all return `true`.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
### sdk.parseJson
|
|
442
|
+
|
|
443
|
+
Parse JSON string to object.
|
|
444
|
+
|
|
445
|
+
**Use case**: Parse JSON-encoded fields from CSV, XML attributes
|
|
446
|
+
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"fields": {
|
|
450
|
+
"metadata": {
|
|
451
|
+
"source": "custom_data",
|
|
452
|
+
"resolver": "sdk.parseJson"
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Examples**:
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
'{"name":"John","age":30}' → { name: "John", age: 30 }
|
|
462
|
+
'["a","b","c"]' → ["a", "b", "c"]
|
|
463
|
+
"invalid json" → "invalid json" (passes through)
|
|
464
|
+
123 → 123 (non-strings pass through)
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Null-safe**: Returns original value if parse fails (never throws).
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
### sdk.toJson
|
|
472
|
+
|
|
473
|
+
Stringify value as JSON.
|
|
474
|
+
|
|
475
|
+
**Use case**: Convert objects to JSON strings for storage in text fields
|
|
476
|
+
|
|
477
|
+
```json
|
|
478
|
+
{
|
|
479
|
+
"fields": {
|
|
480
|
+
"customAttributes": {
|
|
481
|
+
"source": "attributes_obj",
|
|
482
|
+
"resolver": "sdk.toJson"
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Examples**:
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
{ name: "John" } → '{"name":"John"}'
|
|
492
|
+
["a", "b", "c"] → '["a","b","c"]'
|
|
493
|
+
123 → "123"
|
|
494
|
+
"string" → '"string"' (double-quoted)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**Use case**: Storing complex objects in Fluent Commerce custom attributes.
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Utility Resolvers
|
|
502
|
+
|
|
503
|
+
### sdk.identity
|
|
504
|
+
|
|
505
|
+
Return value unchanged (no-op resolver).
|
|
506
|
+
|
|
507
|
+
**Use case**: Explicitly pass value through without transformation
|
|
508
|
+
|
|
509
|
+
```json
|
|
510
|
+
{
|
|
511
|
+
"fields": {
|
|
512
|
+
"ref": {
|
|
513
|
+
"source": "order_id",
|
|
514
|
+
"resolver": "sdk.identity"
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Why this exists**: Some mapping scenarios require a resolver to be specified, but no transformation is needed.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
### sdk.coalesce
|
|
525
|
+
|
|
526
|
+
Return first non-null value.
|
|
527
|
+
|
|
528
|
+
**Use case**: Provide fallback when value is null/undefined
|
|
529
|
+
|
|
530
|
+
```json
|
|
531
|
+
{
|
|
532
|
+
"fields": {
|
|
533
|
+
"email": {
|
|
534
|
+
"source": "primary_email",
|
|
535
|
+
"resolver": "sdk.coalesce",
|
|
536
|
+
"defaultValue": "noreply@example.com"
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**Note**: Typically handled by mapping engine checking `defaultValue`. This resolver exists for complex scenarios.
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
### sdk.default
|
|
547
|
+
|
|
548
|
+
Use the `defaultValue` field configuration property instead.
|
|
549
|
+
|
|
550
|
+
This resolver provides default value if source is null/undefined/empty, but `defaultValue` in field config is the preferred approach.
|
|
551
|
+
|
|
552
|
+
```json
|
|
553
|
+
{
|
|
554
|
+
"fields": {
|
|
555
|
+
"status": {
|
|
556
|
+
"source": "order_status",
|
|
557
|
+
"defaultValue": "ACTIVE",
|
|
558
|
+
"resolver": "sdk.default"
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Note**: The `defaultValue` field configuration property is preferred. This resolver applies after `config.defaultValue` is processed.
|
|
565
|
+
|
|
566
|
+
**Examples**:
|
|
567
|
+
|
|
568
|
+
```typescript
|
|
569
|
+
"PENDING" → "PENDING" (value exists, pass through)
|
|
570
|
+
null → null (defaultValue applied by mapper before resolver)
|
|
571
|
+
undefined → undefined (defaultValue applied by mapper before resolver)
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**Note**: Prefer using the `defaultValue` field configuration property instead of this resolver.
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Helper Functions Reference
|
|
579
|
+
|
|
580
|
+
Custom resolvers receive a `helpers` object with 57 utility functions.
|
|
581
|
+
|
|
582
|
+
### Resolver Signature
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
(value: any, sourceData: any, config: any, helpers: ResolverHelpers) => any | Promise<any>;
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Parameters**:
|
|
589
|
+
|
|
590
|
+
1. `value` - The extracted field value (may be undefined for generator resolvers)
|
|
591
|
+
2. `sourceData` - The complete source object (for context-aware transformations)
|
|
592
|
+
3. `config` - Resolver-specific configuration object
|
|
593
|
+
4. `helpers` - 57 utility functions
|
|
594
|
+
|
|
595
|
+
### Helper Categories
|
|
596
|
+
|
|
597
|
+
| Category | Count | Examples |
|
|
598
|
+
| ----------------------- | ----- | ------------------------------------------------------- |
|
|
599
|
+
| **Data Access** | 4 | get, set, ensureArray, coalesce |
|
|
600
|
+
| **String Manipulation** | 8 | toCamelCase, toSnakeCase, truncate, normalizeWhitespace |
|
|
601
|
+
| **Number Operations** | 3 | parseIntSafe, parseFloatSafe, formatCurrency |
|
|
602
|
+
| **Date/Time** | 4 | formatDate, parseDate, addDays, subtractDays |
|
|
603
|
+
| **Validation** | 3 | isValidEmail, requireField, isEmpty |
|
|
604
|
+
| **Object Utilities** | 6 | deepClone, deepMerge, pick, omit, merge, template |
|
|
605
|
+
| **Array Operations** | 9 | unique, groupBy, sortBy, chunk, flatten, compact, sum, avg, min |
|
|
606
|
+
| **Performance** | 3 | memoize, batchProcess, retry |
|
|
607
|
+
| **Type Guards** | 5 | isString, isNumber, isArray, isObject, isDate |
|
|
608
|
+
| **Utilities** | 9 | defaultTo, range, clamp, slugify, uuid, hashString, debounce, throttle, safeJsonParse |
|
|
609
|
+
|
|
610
|
+
**Total**: 57 helpers
|
|
611
|
+
|
|
612
|
+
### Core Data Access Helpers
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
helpers.get(obj, 'customer.address.city'); // Safe nested access
|
|
616
|
+
helpers.set(obj, 'customer.address.city', 'NYC'); // Safe nested set
|
|
617
|
+
helpers.ensureArray(value); // Wrap singles in array
|
|
618
|
+
helpers.coalesce(val1, val2, val3); // First non-null
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### String Helpers
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
helpers.toCamelCase('first_name'); // → "firstName"
|
|
625
|
+
helpers.toSnakeCase('firstName'); // → "first_name"
|
|
626
|
+
helpers.truncate('Long text...', 10); // → "Long te..."
|
|
627
|
+
helpers.normalizeWhitespace(' a b '); // → "a b"
|
|
628
|
+
helpers.fullName('John', 'Doe'); // → "John Doe"
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Number Helpers
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
helpers.parseIntSafe('123', 0); // → 123 (or default 0)
|
|
635
|
+
helpers.parseFloatSafe('$99.99', 0); // → 99.99
|
|
636
|
+
helpers.formatCurrency(99.99, 2); // → "99.99"
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Date Helpers
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
helpers.formatDate('2025-01-15'); // → ISO8601
|
|
643
|
+
helpers.parseDate('01/15/2025'); // → Date object
|
|
644
|
+
helpers.addDays(new Date(), 7); // → Date + 7 days
|
|
645
|
+
helpers.diffDays(date1, date2); // → number of days
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### Validation Helpers
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
helpers.isValidEmail('test@example.com'); // → true
|
|
652
|
+
helpers.requireField(value, 'email'); // Throws if null
|
|
653
|
+
helpers.isEmpty(value); // → true if null/undefined/empty
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### Object Helpers
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
helpers.deepClone(obj); // Deep copy
|
|
660
|
+
helpers.deepMerge(obj1, obj2); // Merge objects
|
|
661
|
+
helpers.pick(obj, ['name', 'email']); // Extract fields
|
|
662
|
+
helpers.omit(obj, ['password']); // Remove fields
|
|
663
|
+
helpers.flatten(nestedObj); // Flatten to dot notation
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
### Array Helpers
|
|
667
|
+
|
|
668
|
+
```typescript
|
|
669
|
+
helpers.unique([1, 2, 2, 3]); // → [1, 2, 3]
|
|
670
|
+
helpers.groupBy(items, 'category'); // Group by field
|
|
671
|
+
helpers.sortBy(items, 'name'); // Sort by field
|
|
672
|
+
helpers.chunk([1, 2, 3, 4, 5], 2); // → [[1,2], [3,4], [5]]
|
|
673
|
+
helpers.findBy(items, 'id', '123'); // Find by field value
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Performance Helpers
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
await helpers.retry(() => apiCall(), 3, 1000); // Retry with backoff
|
|
680
|
+
await helpers.batchProcess(items, processFn, 100); // Process in batches
|
|
681
|
+
const memoized = helpers.memoize(expensiveFn); // Cache results
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Utilities
|
|
685
|
+
|
|
686
|
+
```typescript
|
|
687
|
+
const hash = helpers.hashString('data'); // Simple hash
|
|
688
|
+
const id = helpers.uuid(); // Generate UUID
|
|
689
|
+
const slug = helpers.slugify('Product Name'); // → "product-name"
|
|
690
|
+
helpers.debounce(fn, 300); // Debounce function calls
|
|
691
|
+
helpers.throttle(fn, 1000); // Throttle function calls
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
## Custom Resolvers
|
|
697
|
+
|
|
698
|
+
### Basic Custom Resolver
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
const customResolvers = {
|
|
702
|
+
'custom.buildRef': (value, sourceData, config, helpers) => {
|
|
703
|
+
const sku = sourceData.sku;
|
|
704
|
+
const location = sourceData.location;
|
|
705
|
+
return `${sku}-${location}`;
|
|
706
|
+
},
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
// Use in mapping
|
|
710
|
+
const mapper = new UniversalMapper(mappingConfig, { customResolvers });
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
### Using Helpers in Custom Resolvers
|
|
714
|
+
|
|
715
|
+
```typescript
|
|
716
|
+
const customResolvers = {
|
|
717
|
+
'custom.formatCustomerName': (value, sourceData, config, helpers) => {
|
|
718
|
+
const firstName = helpers.get(sourceData, 'customer.firstName');
|
|
719
|
+
const lastName = helpers.get(sourceData, 'customer.lastName');
|
|
720
|
+
return helpers.fullName(firstName, lastName);
|
|
721
|
+
},
|
|
722
|
+
|
|
723
|
+
'custom.calculateTotal': (value, sourceData, config, helpers) => {
|
|
724
|
+
const price = helpers.parseFloatSafe(sourceData.price, 0);
|
|
725
|
+
const qty = helpers.parseIntSafe(sourceData.quantity, 0);
|
|
726
|
+
const tax = helpers.parseFloatSafe(sourceData.tax, 0);
|
|
727
|
+
return price * qty + tax;
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
'custom.normalizeEmail': (value, sourceData, config, helpers) => {
|
|
731
|
+
if (!value || typeof value !== 'string') return null;
|
|
732
|
+
|
|
733
|
+
const email = helpers.normalizeWhitespace(value.toLowerCase().trim());
|
|
734
|
+
|
|
735
|
+
if (!helpers.isValidEmail(email)) {
|
|
736
|
+
helpers.logger?.warn('Invalid email', { email });
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return email;
|
|
741
|
+
},
|
|
742
|
+
};
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### Context-Aware Resolvers
|
|
746
|
+
|
|
747
|
+
```typescript
|
|
748
|
+
const customResolvers = {
|
|
749
|
+
'custom.mapOrderType': (value, sourceData, config, helpers) => {
|
|
750
|
+
// Access shared configuration from context
|
|
751
|
+
const environment = helpers.context.environment || 'production';
|
|
752
|
+
|
|
753
|
+
const mapping: Record<string, string> = {
|
|
754
|
+
online: 'HD', // Home Delivery
|
|
755
|
+
store: 'CC', // Click & Collect
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
const orderType = mapping[value] || 'HD';
|
|
759
|
+
|
|
760
|
+
// In non-production, append test suffix
|
|
761
|
+
if (environment !== 'production') {
|
|
762
|
+
return `${orderType}_TEST`;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return orderType;
|
|
766
|
+
},
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
// Pass context when mapping
|
|
770
|
+
const mapper = new UniversalMapper(mappingConfig, {
|
|
771
|
+
customResolvers,
|
|
772
|
+
fluentClient: client,
|
|
773
|
+
});
|
|
774
|
+
const result = await mapper.map(data);
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
## Async Resolvers
|
|
780
|
+
|
|
781
|
+
Custom resolvers can be asynchronous for external API calls, database lookups, etc.
|
|
782
|
+
|
|
783
|
+
### Async Lookup Example
|
|
784
|
+
|
|
785
|
+
```typescript
|
|
786
|
+
const customResolvers = {
|
|
787
|
+
'custom.lookupCustomer': async (value, sourceData, config, helpers) => {
|
|
788
|
+
const email = sourceData.customer_email;
|
|
789
|
+
|
|
790
|
+
if (!email) {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Query Fluent API for existing customer
|
|
795
|
+
const result = await helpers.fluentClient.graphql({
|
|
796
|
+
query: `
|
|
797
|
+
query GetCustomer($email: String) {
|
|
798
|
+
customers(primaryEmail: $email, first: 1) {
|
|
799
|
+
edges {
|
|
800
|
+
node {
|
|
801
|
+
id
|
|
802
|
+
username
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
`,
|
|
808
|
+
variables: { email },
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
const existingCustomer = result?.customers?.edges?.[0]?.node;
|
|
812
|
+
|
|
813
|
+
if (existingCustomer) {
|
|
814
|
+
helpers.logger?.info('Found existing customer', { customerId: existingCustomer.id });
|
|
815
|
+
return existingCustomer.id;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Customer not found - create new
|
|
819
|
+
const createResult = await helpers.fluentClient.graphql({
|
|
820
|
+
query: `
|
|
821
|
+
mutation CreateCustomer($input: CreateCustomerInput!) {
|
|
822
|
+
createCustomer(input: $input) {
|
|
823
|
+
id
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
`,
|
|
827
|
+
variables: {
|
|
828
|
+
input: {
|
|
829
|
+
username: email,
|
|
830
|
+
primaryEmail: email,
|
|
831
|
+
firstName: sourceData.first_name || 'Guest',
|
|
832
|
+
lastName: sourceData.last_name || 'Customer',
|
|
833
|
+
retailer: { id: '2' },
|
|
834
|
+
},
|
|
835
|
+
},
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
helpers.logger?.info('Created new customer', { customerId: createResult.id });
|
|
839
|
+
|
|
840
|
+
return createResult.id;
|
|
841
|
+
},
|
|
842
|
+
};
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
**Important**: When using async resolvers, you must `await` the mapping:
|
|
846
|
+
|
|
847
|
+
```typescript
|
|
848
|
+
const result = await mapper.map(data, {
|
|
849
|
+
fluentClient: client,
|
|
850
|
+
helpers: { fluentClient: client },
|
|
851
|
+
});
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### Async with Retry
|
|
855
|
+
|
|
856
|
+
```typescript
|
|
857
|
+
const customResolvers = {
|
|
858
|
+
'custom.fetchProductPrice': async (value, sourceData, config, helpers) => {
|
|
859
|
+
const sku = sourceData.sku;
|
|
860
|
+
|
|
861
|
+
// Retry API call up to 3 times with 1s delay
|
|
862
|
+
const price = await helpers.retry(
|
|
863
|
+
async () => {
|
|
864
|
+
const response = await fetch(`https://api.example.com/products/${sku}/price`);
|
|
865
|
+
|
|
866
|
+
if (!response.ok) {
|
|
867
|
+
throw new Error(`HTTP ${response.status}`);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
const data = await response.json();
|
|
871
|
+
return data.price;
|
|
872
|
+
},
|
|
873
|
+
3,
|
|
874
|
+
1000
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
return price;
|
|
878
|
+
},
|
|
879
|
+
};
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
### Batch Processing (Performance Optimization)
|
|
883
|
+
|
|
884
|
+
```typescript
|
|
885
|
+
// ❌ BAD: Sequential API calls (slow for 1000 records)
|
|
886
|
+
'custom.lookupCustomerSlow': async (value, sourceData, config, helpers) => {
|
|
887
|
+
const email = sourceData.email;
|
|
888
|
+
const result = await helpers.fluentClient.graphql({ query, variables: { email } });
|
|
889
|
+
return result?.customers?.edges?.[0]?.node?.id;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// ✅ GOOD: Batch cache to reduce API calls
|
|
893
|
+
const customerCache = new Map();
|
|
894
|
+
|
|
895
|
+
const customResolvers = {
|
|
896
|
+
'custom.lookupCustomerFast': async (value, sourceData, config, helpers) => {
|
|
897
|
+
const email = sourceData.email;
|
|
898
|
+
|
|
899
|
+
// Check cache first
|
|
900
|
+
if (customerCache.has(email)) {
|
|
901
|
+
return customerCache.get(email);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// Query API
|
|
905
|
+
const result = await helpers.fluentClient.graphql({
|
|
906
|
+
query,
|
|
907
|
+
variables: { email }
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
const customerId = result?.customers?.edges?.[0]?.node?.id;
|
|
911
|
+
|
|
912
|
+
// Cache result
|
|
913
|
+
customerCache.set(email, customerId);
|
|
914
|
+
|
|
915
|
+
return customerId;
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
---
|
|
921
|
+
|
|
922
|
+
## Best Practices
|
|
923
|
+
|
|
924
|
+
### 1. Use SDK Resolvers First
|
|
925
|
+
|
|
926
|
+
Before writing custom resolvers, check if SDK resolvers can handle the transformation:
|
|
927
|
+
|
|
928
|
+
```typescript
|
|
929
|
+
// ❌ NOT NEEDED
|
|
930
|
+
'custom.toUppercase': (value) => value?.toUpperCase()
|
|
931
|
+
|
|
932
|
+
// ✅ USE SDK RESOLVER
|
|
933
|
+
{ "resolver": "sdk.uppercase" }
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### 2. Keep Resolvers Pure
|
|
937
|
+
|
|
938
|
+
Resolvers should be pure functions (same input → same output, no side effects):
|
|
939
|
+
|
|
940
|
+
```typescript
|
|
941
|
+
// ❌ BAD: Side effects (modifies external state)
|
|
942
|
+
let counter = 0;
|
|
943
|
+
'custom.increment': (value) => {
|
|
944
|
+
counter++; // Side effect!
|
|
945
|
+
return value;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// ✅ GOOD: Pure function
|
|
949
|
+
'custom.incrementValue': (value) => {
|
|
950
|
+
return (value || 0) + 1;
|
|
951
|
+
}
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
### 3. Handle Null/Undefined
|
|
955
|
+
|
|
956
|
+
Always handle null/undefined gracefully:
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
// ❌ BAD: Throws on null
|
|
960
|
+
'custom.getLength': (value) => value.length // Throws if value is null
|
|
961
|
+
|
|
962
|
+
// ✅ GOOD: Null-safe
|
|
963
|
+
'custom.getLength': (value) => value?.length || 0
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
### 4. Use Helpers for Common Operations
|
|
967
|
+
|
|
968
|
+
Don't reinvent the wheel—use helpers:
|
|
969
|
+
|
|
970
|
+
```typescript
|
|
971
|
+
// ❌ BAD: Manual parsing
|
|
972
|
+
'custom.parsePrice': (value) => {
|
|
973
|
+
const num = parseFloat(value.replace(/[^0-9.]/g, ''));
|
|
974
|
+
return isNaN(num) ? 0 : num;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// ✅ GOOD: Use helper
|
|
978
|
+
'custom.parsePrice': (value, sourceData, config, helpers) => {
|
|
979
|
+
return helpers.parseFloatSafe(value, 0);
|
|
980
|
+
}
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
### 5. Document Custom Resolvers
|
|
984
|
+
|
|
985
|
+
Add comments to explain complex logic:
|
|
986
|
+
|
|
987
|
+
```typescript
|
|
988
|
+
const customResolvers = {
|
|
989
|
+
/**
|
|
990
|
+
* Calculate item total: (price * qty) + tax + shipping
|
|
991
|
+
* Returns 0 if any values are invalid
|
|
992
|
+
*/
|
|
993
|
+
'custom.calculateItemTotal': (value, sourceData, config, helpers) => {
|
|
994
|
+
const price = helpers.parseFloatSafe(sourceData.price, 0);
|
|
995
|
+
const qty = helpers.parseIntSafe(sourceData.quantity, 0);
|
|
996
|
+
const tax = helpers.parseFloatSafe(sourceData.tax, 0);
|
|
997
|
+
const shipping = helpers.parseFloatSafe(sourceData.shipping, 0);
|
|
998
|
+
|
|
999
|
+
return price * qty + tax + shipping;
|
|
1000
|
+
},
|
|
1001
|
+
};
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
### 6. Use Logging for Debugging
|
|
1005
|
+
|
|
1006
|
+
Use `helpers.logger` for debugging complex resolvers:
|
|
1007
|
+
|
|
1008
|
+
```typescript
|
|
1009
|
+
'custom.mapOrderType': (value, sourceData, config, helpers) => {
|
|
1010
|
+
helpers.logger?.debug('Mapping order type', {
|
|
1011
|
+
inputValue: value,
|
|
1012
|
+
sourceOrderType: sourceData.order_type
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
const mapped = orderTypeMapping[value] || 'HD';
|
|
1016
|
+
|
|
1017
|
+
helpers.logger?.debug('Mapped order type', {
|
|
1018
|
+
input: value,
|
|
1019
|
+
output: mapped
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
return mapped;
|
|
1023
|
+
}
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
---
|
|
1027
|
+
|
|
1028
|
+
## Performance Optimization
|
|
1029
|
+
|
|
1030
|
+
### 1. Memoize Expensive Operations
|
|
1031
|
+
|
|
1032
|
+
```typescript
|
|
1033
|
+
const expensiveCalculation = helpers.memoize((value) => {
|
|
1034
|
+
// Complex calculation here
|
|
1035
|
+
return result;
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
'custom.calculate': (value) => expensiveCalculation(value)
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
### 2. Cache API Lookups
|
|
1042
|
+
|
|
1043
|
+
```typescript
|
|
1044
|
+
const cache = new Map();
|
|
1045
|
+
|
|
1046
|
+
'custom.lookup': async (value, sourceData, config, helpers) => {
|
|
1047
|
+
if (cache.has(value)) {
|
|
1048
|
+
return cache.get(value);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const result = await apiCall(value);
|
|
1052
|
+
cache.set(value, result);
|
|
1053
|
+
return result;
|
|
1054
|
+
}
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
### 3. Batch Process Arrays
|
|
1058
|
+
|
|
1059
|
+
```typescript
|
|
1060
|
+
'custom.processItems': async (value, sourceData, config, helpers) => {
|
|
1061
|
+
const items = helpers.ensureArray(value);
|
|
1062
|
+
|
|
1063
|
+
// Process 100 items at a time
|
|
1064
|
+
const results = await helpers.batchProcess(
|
|
1065
|
+
items,
|
|
1066
|
+
async (item) => await processItem(item),
|
|
1067
|
+
100
|
|
1068
|
+
);
|
|
1069
|
+
|
|
1070
|
+
return results;
|
|
1071
|
+
}
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
### 4. Avoid Nested Loops
|
|
1075
|
+
|
|
1076
|
+
```typescript
|
|
1077
|
+
// ❌ BAD: O(n²) complexity
|
|
1078
|
+
'custom.findMatch': (value, sourceData) => {
|
|
1079
|
+
for (const item of sourceData.items) {
|
|
1080
|
+
for (const match of sourceData.matches) {
|
|
1081
|
+
if (item.id === match.id) return match;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// ✅ GOOD: O(n) complexity
|
|
1087
|
+
'custom.findMatch': (value, sourceData, config, helpers) => {
|
|
1088
|
+
const matchMap = new Map(sourceData.matches.map(m => [m.id, m]));
|
|
1089
|
+
return matchMap.get(value);
|
|
1090
|
+
}
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
---
|
|
1094
|
+
|
|
1095
|
+
## Next Steps
|
|
1096
|
+
|
|
1097
|
+
You've mastered all SDK resolvers and helper functions! Next:
|
|
1098
|
+
|
|
1099
|
+
**Continue to:** [Module 7: API Reference →](../../auto-pagination/modules/auto-pagination-07-api-reference.md)
|
|
1100
|
+
|
|
1101
|
+
Or explore:
|
|
1102
|
+
|
|
1103
|
+
- [GraphQL Mutation Mapping Quick Reference](../graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md) - Comprehensive cheat sheet
|
|
1104
|
+
- [Examples](../examples/) - Complete working examples
|
|
1105
|
+
- [Module 5: Advanced Patterns](./mapping-05-advanced-patterns.md) - Review complex patterns
|
|
1106
|
+
|
|
1107
|
+
---
|
|
1108
|
+
|
|
1109
|
+
## Additional Resources
|
|
1110
|
+
|
|
1111
|
+
- [SDK Resolvers Source Code](../../../../src/services/resolvers/sdk-resolvers.ts)
|
|
1112
|
+
- [Resolver Engine Source](../../../../src/services/resolvers/resolver-engine.ts)
|
|
1113
|
+
- [Helper Functions Reference](../../../../src/services/resolvers/resolver-helpers.ts)
|
|
1114
|
+
|
|
1115
|
+
---
|
|
1116
|
+
|
|
1117
|
+
[← Back to Index](../mapping-readme.md) | [Previous: Advanced Patterns](./mapping-05-advanced-patterns.md) | [Next: API Reference →](../../auto-pagination/modules/auto-pagination-07-api-reference.md)
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|