@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
- package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md
CHANGED
|
@@ -1,739 +1,739 @@
|
|
|
1
|
-
# Module 4: Advanced Patterns
|
|
2
|
-
|
|
3
|
-
**Level:** Advanced
|
|
4
|
-
**Estimated Time:** 30 minutes
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This module covers advanced resolver patterns that leverage all 4 parameters to create powerful, context-aware transformations. You'll learn async patterns, multi-field calculations, and production-ready error handling.
|
|
9
|
-
|
|
10
|
-
## Learning Objectives
|
|
11
|
-
|
|
12
|
-
By the end of this module, you will:
|
|
13
|
-
- ✅ Write context-aware resolvers using sourceData
|
|
14
|
-
- ✅ Implement async resolvers with API calls
|
|
15
|
-
- ✅ Use all 4 parameters in complex transformations
|
|
16
|
-
- ✅ Handle errors gracefully in production resolvers
|
|
17
|
-
- ✅ Optimize performance with memoization and caching
|
|
18
|
-
|
|
19
|
-
## Context-Aware Transformations
|
|
20
|
-
|
|
21
|
-
### Multi-Field Price Calculation
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
'custom.calculateFinalPrice': (basePrice, sourceData, config, helpers) => {
|
|
25
|
-
// 1. VALUE: Base price to transform
|
|
26
|
-
const price = helpers.parseFloatSafe(basePrice, 0);
|
|
27
|
-
|
|
28
|
-
// 2. SOURCEDATA: Access related fields
|
|
29
|
-
const quantity = helpers.get(sourceData, 'quantity') || 1;
|
|
30
|
-
const discountPercent = helpers.get(sourceData, 'discountPercent') || 0;
|
|
31
|
-
const customerTier = helpers.get(sourceData, 'customer.tier');
|
|
32
|
-
|
|
33
|
-
// 3. CONFIG: Business rules
|
|
34
|
-
const tierDiscounts = config.tierDiscounts || {};
|
|
35
|
-
const taxRate = config.taxRate || 0;
|
|
36
|
-
|
|
37
|
-
// 4. HELPERS: Safe calculations
|
|
38
|
-
const subtotal = price * quantity;
|
|
39
|
-
const itemDiscount = subtotal * (discountPercent / 100);
|
|
40
|
-
const tierDiscount = subtotal * (tierDiscounts[customerTier] || 0);
|
|
41
|
-
const afterDiscount = subtotal - itemDiscount - tierDiscount;
|
|
42
|
-
const withTax = afterDiscount * (1 + taxRate);
|
|
43
|
-
|
|
44
|
-
helpers.log.debug(`Price calculation: ${price} × ${quantity} = ${withTax}`);
|
|
45
|
-
|
|
46
|
-
return helpers.parseFloatSafe(withTax, 0);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Usage
|
|
50
|
-
const mapper = new UniversalMapper(mapping, {
|
|
51
|
-
customResolvers: { 'custom.calculateFinalPrice': calculateFinalPrice },
|
|
52
|
-
context: {
|
|
53
|
-
tierDiscounts: {
|
|
54
|
-
'gold': 0.15,
|
|
55
|
-
'silver': 0.10,
|
|
56
|
-
'bronze': 0.05
|
|
57
|
-
},
|
|
58
|
-
taxRate: 0.0975
|
|
59
|
-
},
|
|
60
|
-
logger: myLogger
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Input:
|
|
64
|
-
// {
|
|
65
|
-
// price: 100,
|
|
66
|
-
// quantity: 5,
|
|
67
|
-
// discountPercent: 10,
|
|
68
|
-
// customer: { tier: 'gold' }
|
|
69
|
-
// }
|
|
70
|
-
|
|
71
|
-
// Output: 386.8125
|
|
72
|
-
// Calculation:
|
|
73
|
-
// - Subtotal: 100 × 5 = 500
|
|
74
|
-
// - Item discount: 500 × 0.10 = 50
|
|
75
|
-
// - Tier discount: 500 × 0.15 = 75
|
|
76
|
-
// - After discounts: 500 - 50 - 75 = 375
|
|
77
|
-
// - With tax: 375 × 1.0975 = 411.5625
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Conditional Field Mapping
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
'custom.mapOrderType': (value, sourceData, config, helpers) => {
|
|
84
|
-
// Use sourceData to determine order type
|
|
85
|
-
const itemCount = helpers.get(sourceData, 'items.length') || 0;
|
|
86
|
-
const totalValue = helpers.get(sourceData, 'totalPrice') || 0;
|
|
87
|
-
const priority = helpers.get(sourceData, 'priority');
|
|
88
|
-
|
|
89
|
-
// Apply business rules from config
|
|
90
|
-
const thresholds = config.orderTypeThresholds || {
|
|
91
|
-
bulkItems: 50,
|
|
92
|
-
bulkValue: 10000
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
if (priority === 'URGENT') {
|
|
96
|
-
return 'EXPRESS';
|
|
97
|
-
} else if (itemCount >= thresholds.bulkItems || totalValue >= thresholds.bulkValue) {
|
|
98
|
-
return 'BULK';
|
|
99
|
-
} else if (totalValue < 100) {
|
|
100
|
-
return 'SMALL';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return 'STANDARD';
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Usage
|
|
107
|
-
const mapper = new UniversalMapper(mapping, {
|
|
108
|
-
customResolvers: { 'custom.mapOrderType': mapOrderType },
|
|
109
|
-
context: {
|
|
110
|
-
orderTypeThresholds: {
|
|
111
|
-
bulkItems: 50,
|
|
112
|
-
bulkValue: 10000
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Dynamic Field Selection
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
'custom.selectAddress': (value, sourceData, config, helpers) => {
|
|
122
|
-
// Select shipping vs billing address based on context
|
|
123
|
-
const useShipping = helpers.get(sourceData, 'useShippingAddress');
|
|
124
|
-
const shippingAddr = helpers.get(sourceData, 'shippingAddress');
|
|
125
|
-
const billingAddr = helpers.get(sourceData, 'billingAddress');
|
|
126
|
-
|
|
127
|
-
const selectedAddr = useShipping ? shippingAddr : billingAddr;
|
|
128
|
-
|
|
129
|
-
// Format address using helper
|
|
130
|
-
const street = helpers.get(selectedAddr, 'street', '');
|
|
131
|
-
const city = helpers.get(selectedAddr, 'city', '');
|
|
132
|
-
const state = helpers.get(selectedAddr, 'state', '');
|
|
133
|
-
const zip = helpers.get(selectedAddr, 'zip', '');
|
|
134
|
-
|
|
135
|
-
return `${street}, ${city}, ${state} ${zip}`.trim();
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Async Resolvers with API Calls
|
|
140
|
-
|
|
141
|
-
### Fetch and Enrich Data
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
'custom.enrichWithProduct': async (sku, sourceData, config, helpers) => {
|
|
145
|
-
// Check if FluentClient is available
|
|
146
|
-
if (!helpers.fluentClient) {
|
|
147
|
-
helpers.log.warn('FluentClient not available, skipping enrichment');
|
|
148
|
-
return { sku };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
// Query Fluent API
|
|
153
|
-
const result = await helpers.fluentClient.graphql({
|
|
154
|
-
query: `
|
|
155
|
-
query GetProduct($ref: String!) {
|
|
156
|
-
product(ref: $ref) {
|
|
157
|
-
id
|
|
158
|
-
ref
|
|
159
|
-
name
|
|
160
|
-
gtin
|
|
161
|
-
status
|
|
162
|
-
attributes {
|
|
163
|
-
name
|
|
164
|
-
value
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
`,
|
|
169
|
-
variables: { ref: sku }
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
if (!result.data?.product) {
|
|
173
|
-
helpers.log.warn(`Product not found: ${sku}`);
|
|
174
|
-
return { sku, found: false };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
sku,
|
|
179
|
-
found: true,
|
|
180
|
-
...result.data.product
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
} catch (error) {
|
|
184
|
-
helpers.log.error(`Failed to fetch product ${sku}`, error);
|
|
185
|
-
return { sku, error: error.message };
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Usage
|
|
190
|
-
const mapper = new UniversalMapper(mapping, {
|
|
191
|
-
customResolvers: { 'custom.enrichWithProduct': enrichWithProduct },
|
|
192
|
-
fluentClient: myFluentClient,
|
|
193
|
-
logger: myLogger
|
|
194
|
-
});
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Batch API Calls with Memoization
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
'custom.lookupCustomer': helpers.memoize(
|
|
201
|
-
async (customerId, sourceData, config, helpers) => {
|
|
202
|
-
if (!helpers.fluentClient) {
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
const result = await helpers.fluentClient.graphql({
|
|
208
|
-
query: `
|
|
209
|
-
query GetCustomer($id: ID!) {
|
|
210
|
-
customer(id: $id) {
|
|
211
|
-
id
|
|
212
|
-
firstName
|
|
213
|
-
lastName
|
|
214
|
-
email
|
|
215
|
-
tier
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
`,
|
|
219
|
-
variables: { id: customerId }
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
return result.data?.customer;
|
|
223
|
-
|
|
224
|
-
} catch (error) {
|
|
225
|
-
helpers.log.error(`Customer lookup failed: ${customerId}`, error);
|
|
226
|
-
return null;
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
// Memoization key function
|
|
230
|
-
(customerId) => customerId
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
// This resolver will cache results by customerId
|
|
234
|
-
// Subsequent calls with same ID return cached result
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### Retry Pattern for Resilience
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
'custom.fetchWithRetry': async (id, sourceData, config, helpers) => {
|
|
241
|
-
const maxRetries = config.maxRetries || 3;
|
|
242
|
-
const retryDelay = config.retryDelay || 1000;
|
|
243
|
-
|
|
244
|
-
const fetchData = async () => {
|
|
245
|
-
const result = await helpers.fluentClient.graphql({
|
|
246
|
-
query: `query { data(id: "${id}") { value } }`
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
if (!result.data) {
|
|
250
|
-
throw new Error('No data returned');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return result.data;
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// Use helper's retry utility
|
|
257
|
-
try {
|
|
258
|
-
return await helpers.retry(fetchData, {
|
|
259
|
-
maxAttempts: maxRetries,
|
|
260
|
-
delayMs: retryDelay,
|
|
261
|
-
backoffMultiplier: 2
|
|
262
|
-
});
|
|
263
|
-
} catch (error) {
|
|
264
|
-
helpers.log.error(`Failed after ${maxRetries} retries`, error);
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Usage
|
|
270
|
-
const mapper = new UniversalMapper(mapping, {
|
|
271
|
-
customResolvers: { 'custom.fetchWithRetry': fetchWithRetry },
|
|
272
|
-
context: {
|
|
273
|
-
maxRetries: 3,
|
|
274
|
-
retryDelay: 1000
|
|
275
|
-
},
|
|
276
|
-
fluentClient: myFluentClient,
|
|
277
|
-
logger: myLogger
|
|
278
|
-
});
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
## Complex Data Transformations
|
|
282
|
-
|
|
283
|
-
### Nested Object Construction
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
'custom.buildAddress': (value, sourceData, config, helpers) => {
|
|
287
|
-
// Extract address components from flat structure
|
|
288
|
-
const street = helpers.get(sourceData, 'addr_line1');
|
|
289
|
-
const street2 = helpers.get(sourceData, 'addr_line2');
|
|
290
|
-
const city = helpers.get(sourceData, 'addr_city');
|
|
291
|
-
const state = helpers.get(sourceData, 'addr_state');
|
|
292
|
-
const zip = helpers.get(sourceData, 'addr_zip');
|
|
293
|
-
const country = helpers.get(sourceData, 'addr_country') || config.defaultCountry;
|
|
294
|
-
|
|
295
|
-
// Build nested structure
|
|
296
|
-
return {
|
|
297
|
-
street1: street,
|
|
298
|
-
street2: street2 || null,
|
|
299
|
-
city,
|
|
300
|
-
state,
|
|
301
|
-
postalCode: zip,
|
|
302
|
-
country,
|
|
303
|
-
formatted: helpers.compact([street, street2, city, `${state} ${zip}`, country])
|
|
304
|
-
.join(', ')
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Output:
|
|
309
|
-
// {
|
|
310
|
-
// street1: "123 Main St",
|
|
311
|
-
// street2: "Apt 4B",
|
|
312
|
-
// city: "Springfield",
|
|
313
|
-
// state: "IL",
|
|
314
|
-
// postalCode: "62701",
|
|
315
|
-
// country: "USA",
|
|
316
|
-
// formatted: "123 Main St, Apt 4B, Springfield, IL 62701, USA"
|
|
317
|
-
// }
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### Array Transformation with Filtering
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
'custom.processItems': (items, sourceData, config, helpers) => {
|
|
324
|
-
const arr = helpers.ensureArray(items);
|
|
325
|
-
|
|
326
|
-
// Filter, transform, and aggregate
|
|
327
|
-
const processed = arr
|
|
328
|
-
.filter(item => {
|
|
329
|
-
const qty = helpers.get(item, 'quantity') || 0;
|
|
330
|
-
return qty > 0; // Exclude zero-quantity items
|
|
331
|
-
})
|
|
332
|
-
.map(item => {
|
|
333
|
-
const price = helpers.parseFloatSafe(item.price, 0);
|
|
334
|
-
const qty = helpers.parseIntSafe(item.quantity, 1);
|
|
335
|
-
const taxRate = config.itemTaxRate || 0.08;
|
|
336
|
-
|
|
337
|
-
return {
|
|
338
|
-
sku: item.sku,
|
|
339
|
-
quantity: qty,
|
|
340
|
-
unitPrice: price,
|
|
341
|
-
subtotal: price * qty,
|
|
342
|
-
tax: price * qty * taxRate,
|
|
343
|
-
total: price * qty * (1 + taxRate)
|
|
344
|
-
};
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
// Calculate totals
|
|
348
|
-
const summary = {
|
|
349
|
-
items: processed,
|
|
350
|
-
itemCount: processed.length,
|
|
351
|
-
subtotal: helpers.sum(processed.map(i => i.subtotal)),
|
|
352
|
-
tax: helpers.sum(processed.map(i => i.tax)),
|
|
353
|
-
total: helpers.sum(processed.map(i => i.total))
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
return summary;
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
### Conditional Transformation Pipeline
|
|
361
|
-
|
|
362
|
-
```typescript
|
|
363
|
-
'custom.transformWithPipeline': (value, sourceData, config, helpers) => {
|
|
364
|
-
let result = value;
|
|
365
|
-
|
|
366
|
-
// Apply transformations based on config
|
|
367
|
-
const pipeline = config.transformPipeline || [];
|
|
368
|
-
|
|
369
|
-
for (const step of pipeline) {
|
|
370
|
-
switch (step.type) {
|
|
371
|
-
case 'uppercase':
|
|
372
|
-
result = String(result).toUpperCase();
|
|
373
|
-
break;
|
|
374
|
-
|
|
375
|
-
case 'trim':
|
|
376
|
-
result = String(result).trim();
|
|
377
|
-
break;
|
|
378
|
-
|
|
379
|
-
case 'prefix':
|
|
380
|
-
result = `${step.value || ''}${result}`;
|
|
381
|
-
break;
|
|
382
|
-
|
|
383
|
-
case 'replace':
|
|
384
|
-
result = String(result).replace(
|
|
385
|
-
new RegExp(step.pattern, step.flags || 'g'),
|
|
386
|
-
step.replacement || ''
|
|
387
|
-
);
|
|
388
|
-
break;
|
|
389
|
-
|
|
390
|
-
case 'validate':
|
|
391
|
-
if (!new RegExp(step.pattern).test(result)) {
|
|
392
|
-
helpers.log.error(`Validation failed: ${result}`);
|
|
393
|
-
return null;
|
|
394
|
-
}
|
|
395
|
-
break;
|
|
396
|
-
|
|
397
|
-
default:
|
|
398
|
-
helpers.log.warn(`Unknown pipeline step: ${step.type}`);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
return result;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Usage
|
|
406
|
-
const mapper = new UniversalMapper(mapping, {
|
|
407
|
-
customResolvers: { 'custom.transformWithPipeline': transformWithPipeline },
|
|
408
|
-
context: {
|
|
409
|
-
transformPipeline: [
|
|
410
|
-
{ type: 'trim' },
|
|
411
|
-
{ type: 'uppercase' },
|
|
412
|
-
{ type: 'replace', pattern: '[^A-Z0-9]', replacement: '-' },
|
|
413
|
-
{ type: 'prefix', value: 'SKU-' },
|
|
414
|
-
{ type: 'validate', pattern: '^SKU-[A-Z0-9-]+$' }
|
|
415
|
-
]
|
|
416
|
-
},
|
|
417
|
-
logger: myLogger
|
|
418
|
-
});
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
## Error Handling Patterns
|
|
422
|
-
|
|
423
|
-
### Graceful Degradation
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
'custom.safeTransform': (value, sourceData, config, helpers) => {
|
|
427
|
-
try {
|
|
428
|
-
// Attempt complex transformation
|
|
429
|
-
const result = complexTransformation(value);
|
|
430
|
-
|
|
431
|
-
// Validate result
|
|
432
|
-
if (!result || !result.isValid) {
|
|
433
|
-
throw new Error('Invalid transformation result');
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return result.value;
|
|
437
|
-
|
|
438
|
-
} catch (error) {
|
|
439
|
-
// Log error but don't fail
|
|
440
|
-
helpers.log.error('Transformation failed, using fallback', error);
|
|
441
|
-
|
|
442
|
-
// Return safe fallback value
|
|
443
|
-
return config.fallbackValue || value;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
### Validation with Detailed Errors
|
|
449
|
-
|
|
450
|
-
```typescript
|
|
451
|
-
'custom.validateAndTransform': (value, sourceData, config, helpers) => {
|
|
452
|
-
const errors = [];
|
|
453
|
-
|
|
454
|
-
// Validate required fields
|
|
455
|
-
if (!value) {
|
|
456
|
-
errors.push('Value is required');
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const quantity = helpers.get(sourceData, 'quantity');
|
|
460
|
-
if (!quantity || quantity <= 0) {
|
|
461
|
-
errors.push('Quantity must be positive');
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const price = helpers.get(sourceData, 'price');
|
|
465
|
-
if (!price || price <= 0) {
|
|
466
|
-
errors.push('Price must be positive');
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// If validation fails, log and return null
|
|
470
|
-
if (errors.length > 0) {
|
|
471
|
-
helpers.log.error('Validation failed', {
|
|
472
|
-
value,
|
|
473
|
-
errors,
|
|
474
|
-
sourceData
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
if (config.throwOnValidationError) {
|
|
478
|
-
throw new Error(`Validation failed: ${errors.join(', ')}`);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return null;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Perform transformation
|
|
485
|
-
return helpers.parseFloatSafe(price, 0) * helpers.parseIntSafe(quantity, 1);
|
|
486
|
-
}
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
## Performance Optimization
|
|
490
|
-
|
|
491
|
-
### Memoization for Expensive Operations
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
'custom.expensiveCalc': helpers.memoize(
|
|
495
|
-
(value, sourceData, config, helpers) => {
|
|
496
|
-
// Expensive calculation that should be cached
|
|
497
|
-
let result = 0;
|
|
498
|
-
for (let i = 0; i < 1000000; i++) {
|
|
499
|
-
result += Math.sqrt(i * value);
|
|
500
|
-
}
|
|
501
|
-
return result;
|
|
502
|
-
},
|
|
503
|
-
// Memoization key
|
|
504
|
-
(value) => value
|
|
505
|
-
);
|
|
506
|
-
|
|
507
|
-
// First call with value=5 calculates and caches
|
|
508
|
-
// Subsequent calls with value=5 return cached result instantly
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
### Batch Processing for Arrays
|
|
512
|
-
|
|
513
|
-
```typescript
|
|
514
|
-
'custom.batchProcess': async (items, sourceData, config, helpers) => {
|
|
515
|
-
const arr = helpers.ensureArray(items);
|
|
516
|
-
const batchSize = config.batchSize || 10;
|
|
517
|
-
|
|
518
|
-
// Process in batches to avoid overwhelming API
|
|
519
|
-
const results = await helpers.batchProcess(
|
|
520
|
-
arr,
|
|
521
|
-
async (batch) => {
|
|
522
|
-
// Process each batch
|
|
523
|
-
const promises = batch.map(item =>
|
|
524
|
-
helpers.fluentClient.graphql({
|
|
525
|
-
query: `query { data(id: "${item.id}") { value } }`
|
|
526
|
-
})
|
|
527
|
-
);
|
|
528
|
-
|
|
529
|
-
return await Promise.all(promises);
|
|
530
|
-
},
|
|
531
|
-
batchSize
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
return results.flat();
|
|
535
|
-
}
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
## Complete Real-World Example
|
|
539
|
-
|
|
540
|
-
```typescript
|
|
541
|
-
export const customResolvers = {
|
|
542
|
-
'custom.processOrder': async (orderId, sourceData, config, helpers) => {
|
|
543
|
-
// 1. VALUE: Order ID to process
|
|
544
|
-
if (!orderId) {
|
|
545
|
-
helpers.log.error('Order ID is required');
|
|
546
|
-
return null;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// 2. SOURCEDATA: Get related data
|
|
550
|
-
const items = helpers.get(sourceData, 'items', []);
|
|
551
|
-
const customerTier = helpers.get(sourceData, 'customer.tier', 'standard');
|
|
552
|
-
const shippingZone = helpers.get(sourceData, 'shipping.zone');
|
|
553
|
-
|
|
554
|
-
// 3. CONFIG: Business rules
|
|
555
|
-
const tierDiscounts = config.tierDiscounts || {};
|
|
556
|
-
const shippingRates = config.shippingRates || {};
|
|
557
|
-
const taxRate = config.taxRate || 0.08;
|
|
558
|
-
|
|
559
|
-
// 4. HELPERS: Utilities and API calls
|
|
560
|
-
try {
|
|
561
|
-
// Validate items
|
|
562
|
-
if (items.length === 0) {
|
|
563
|
-
helpers.log.warn(`No items in order ${orderId}`);
|
|
564
|
-
return null;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Calculate item totals
|
|
568
|
-
const itemTotals = items.map(item => {
|
|
569
|
-
const price = helpers.parseFloatSafe(item.price, 0);
|
|
570
|
-
const qty = helpers.parseIntSafe(item.quantity, 1);
|
|
571
|
-
return price * qty;
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
// Calculate subtotal
|
|
575
|
-
const subtotal = helpers.sum(itemTotals);
|
|
576
|
-
|
|
577
|
-
// Apply tier discount
|
|
578
|
-
const discount = subtotal * (tierDiscounts[customerTier] || 0);
|
|
579
|
-
const afterDiscount = subtotal - discount;
|
|
580
|
-
|
|
581
|
-
// Calculate shipping
|
|
582
|
-
const shipping = shippingRates[shippingZone] || shippingRates.default || 0;
|
|
583
|
-
|
|
584
|
-
// Calculate tax
|
|
585
|
-
const tax = afterDiscount * taxRate;
|
|
586
|
-
|
|
587
|
-
// Calculate total
|
|
588
|
-
const total = afterDiscount + shipping + tax;
|
|
589
|
-
|
|
590
|
-
// Enrich with customer data if available
|
|
591
|
-
let customerData = null;
|
|
592
|
-
if (helpers.fluentClient && config.enrichWithCustomer) {
|
|
593
|
-
try {
|
|
594
|
-
const result = await helpers.fluentClient.graphql({
|
|
595
|
-
query: `
|
|
596
|
-
query GetCustomer($tier: String!) {
|
|
597
|
-
customers(tier: $tier, first: 1) {
|
|
598
|
-
edges {
|
|
599
|
-
node {
|
|
600
|
-
id
|
|
601
|
-
firstName
|
|
602
|
-
lastName
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
`,
|
|
608
|
-
variables: { tier: customerTier }
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
customerData = result.data?.customers?.edges[0]?.node;
|
|
612
|
-
} catch (error) {
|
|
613
|
-
helpers.log.error('Customer enrichment failed', error);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Return complete order summary
|
|
618
|
-
return {
|
|
619
|
-
orderId,
|
|
620
|
-
itemCount: items.length,
|
|
621
|
-
subtotal: helpers.parseFloatSafe(subtotal, 0),
|
|
622
|
-
discount: helpers.parseFloatSafe(discount, 0),
|
|
623
|
-
shipping: helpers.parseFloatSafe(shipping, 0),
|
|
624
|
-
tax: helpers.parseFloatSafe(tax, 0),
|
|
625
|
-
total: helpers.parseFloatSafe(total, 0),
|
|
626
|
-
customerTier,
|
|
627
|
-
customerData
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
} catch (error) {
|
|
631
|
-
helpers.log.error(`Order processing failed: ${orderId}`, error);
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
// Usage
|
|
638
|
-
const mapper = new UniversalMapper(mapping, {
|
|
639
|
-
customResolvers,
|
|
640
|
-
context: {
|
|
641
|
-
tierDiscounts: {
|
|
642
|
-
'platinum': 0.20,
|
|
643
|
-
'gold': 0.15,
|
|
644
|
-
'silver': 0.10,
|
|
645
|
-
'standard': 0.0
|
|
646
|
-
},
|
|
647
|
-
shippingRates: {
|
|
648
|
-
'local': 5.00,
|
|
649
|
-
'regional': 10.00,
|
|
650
|
-
'national': 15.00,
|
|
651
|
-
'default': 20.00
|
|
652
|
-
},
|
|
653
|
-
taxRate: 0.0975,
|
|
654
|
-
enrichWithCustomer: true
|
|
655
|
-
},
|
|
656
|
-
fluentClient: myFluentClient,
|
|
657
|
-
logger: myLogger
|
|
658
|
-
});
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
## Key Takeaways
|
|
662
|
-
|
|
663
|
-
- 🎯 **Use all 4 parameters** - Each serves a distinct purpose
|
|
664
|
-
- 🎯 **sourceData for context** - Access related fields for smart transformations
|
|
665
|
-
- 🎯 **config for business rules** - Keep logic configurable and testable
|
|
666
|
-
- 🎯 **helpers for utilities** - Use 48+ functions + FluentClient
|
|
667
|
-
- 🎯 **Handle errors gracefully** - Always provide fallbacks
|
|
668
|
-
- 🎯 **Optimize performance** - Use memoization and batch processing
|
|
669
|
-
|
|
670
|
-
## Practice Exercise
|
|
671
|
-
|
|
672
|
-
Create a resolver that calculates order priority:
|
|
673
|
-
|
|
674
|
-
**Requirements:**
|
|
675
|
-
- Use value as base priority
|
|
676
|
-
- Check if order has express shipping (sourceData)
|
|
677
|
-
- Apply priority multipliers from config
|
|
678
|
-
- Use helpers for safe calculations
|
|
679
|
-
- Return object with priority score and reasoning
|
|
680
|
-
|
|
681
|
-
<details>
|
|
682
|
-
<summary>Show Solution</summary>
|
|
683
|
-
|
|
684
|
-
```typescript
|
|
685
|
-
'custom.calculatePriority': (basePriority, sourceData, config, helpers) => {
|
|
686
|
-
// 1. VALUE: Base priority score
|
|
687
|
-
let score = helpers.parseIntSafe(basePriority, 50);
|
|
688
|
-
|
|
689
|
-
const reasons = [];
|
|
690
|
-
|
|
691
|
-
// 2. SOURCEDATA: Check order details
|
|
692
|
-
const isExpress = helpers.get(sourceData, 'shipping.express', false);
|
|
693
|
-
const customerTier = helpers.get(sourceData, 'customer.tier');
|
|
694
|
-
const orderValue = helpers.get(sourceData, 'totalValue', 0);
|
|
695
|
-
|
|
696
|
-
// 3. CONFIG: Priority multipliers
|
|
697
|
-
const multipliers = config.priorityMultipliers || {
|
|
698
|
-
express: 2.0,
|
|
699
|
-
platinum: 1.5,
|
|
700
|
-
gold: 1.3,
|
|
701
|
-
highValue: 1.2
|
|
702
|
-
};
|
|
703
|
-
|
|
704
|
-
// Calculate priority
|
|
705
|
-
if (isExpress) {
|
|
706
|
-
score *= multipliers.express;
|
|
707
|
-
reasons.push('express shipping');
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
if (customerTier === 'platinum') {
|
|
711
|
-
score *= multipliers.platinum;
|
|
712
|
-
reasons.push('platinum customer');
|
|
713
|
-
} else if (customerTier === 'gold') {
|
|
714
|
-
score *= multipliers.gold;
|
|
715
|
-
reasons.push('gold customer');
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
if (orderValue > 1000) {
|
|
719
|
-
score *= multipliers.highValue;
|
|
720
|
-
reasons.push('high value order');
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
// 4. HELPERS: Safe calculations and logging
|
|
724
|
-
score = helpers.parseIntSafe(score, basePriority);
|
|
725
|
-
|
|
726
|
-
helpers.log.debug(`Priority: ${score} (${reasons.join(', ')})`);
|
|
727
|
-
|
|
728
|
-
return {
|
|
729
|
-
score,
|
|
730
|
-
level: score > 150 ? 'HIGH' : score > 100 ? 'MEDIUM' : 'LOW',
|
|
731
|
-
reasons
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
```
|
|
735
|
-
</details>
|
|
736
|
-
|
|
737
|
-
## Next Steps
|
|
738
|
-
|
|
739
|
-
Continue to [Module 5: SDK Resolvers](./resolver-signature-05-sdk-resolvers.md) to understand how built-in resolvers use the same 4-parameter signature.
|
|
1
|
+
# Module 4: Advanced Patterns
|
|
2
|
+
|
|
3
|
+
**Level:** Advanced
|
|
4
|
+
**Estimated Time:** 30 minutes
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
This module covers advanced resolver patterns that leverage all 4 parameters to create powerful, context-aware transformations. You'll learn async patterns, multi-field calculations, and production-ready error handling.
|
|
9
|
+
|
|
10
|
+
## Learning Objectives
|
|
11
|
+
|
|
12
|
+
By the end of this module, you will:
|
|
13
|
+
- ✅ Write context-aware resolvers using sourceData
|
|
14
|
+
- ✅ Implement async resolvers with API calls
|
|
15
|
+
- ✅ Use all 4 parameters in complex transformations
|
|
16
|
+
- ✅ Handle errors gracefully in production resolvers
|
|
17
|
+
- ✅ Optimize performance with memoization and caching
|
|
18
|
+
|
|
19
|
+
## Context-Aware Transformations
|
|
20
|
+
|
|
21
|
+
### Multi-Field Price Calculation
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
'custom.calculateFinalPrice': (basePrice, sourceData, config, helpers) => {
|
|
25
|
+
// 1. VALUE: Base price to transform
|
|
26
|
+
const price = helpers.parseFloatSafe(basePrice, 0);
|
|
27
|
+
|
|
28
|
+
// 2. SOURCEDATA: Access related fields
|
|
29
|
+
const quantity = helpers.get(sourceData, 'quantity') || 1;
|
|
30
|
+
const discountPercent = helpers.get(sourceData, 'discountPercent') || 0;
|
|
31
|
+
const customerTier = helpers.get(sourceData, 'customer.tier');
|
|
32
|
+
|
|
33
|
+
// 3. CONFIG: Business rules
|
|
34
|
+
const tierDiscounts = config.tierDiscounts || {};
|
|
35
|
+
const taxRate = config.taxRate || 0;
|
|
36
|
+
|
|
37
|
+
// 4. HELPERS: Safe calculations
|
|
38
|
+
const subtotal = price * quantity;
|
|
39
|
+
const itemDiscount = subtotal * (discountPercent / 100);
|
|
40
|
+
const tierDiscount = subtotal * (tierDiscounts[customerTier] || 0);
|
|
41
|
+
const afterDiscount = subtotal - itemDiscount - tierDiscount;
|
|
42
|
+
const withTax = afterDiscount * (1 + taxRate);
|
|
43
|
+
|
|
44
|
+
helpers.log.debug(`Price calculation: ${price} × ${quantity} = ${withTax}`);
|
|
45
|
+
|
|
46
|
+
return helpers.parseFloatSafe(withTax, 0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Usage
|
|
50
|
+
const mapper = new UniversalMapper(mapping, {
|
|
51
|
+
customResolvers: { 'custom.calculateFinalPrice': calculateFinalPrice },
|
|
52
|
+
context: {
|
|
53
|
+
tierDiscounts: {
|
|
54
|
+
'gold': 0.15,
|
|
55
|
+
'silver': 0.10,
|
|
56
|
+
'bronze': 0.05
|
|
57
|
+
},
|
|
58
|
+
taxRate: 0.0975
|
|
59
|
+
},
|
|
60
|
+
logger: myLogger
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Input:
|
|
64
|
+
// {
|
|
65
|
+
// price: 100,
|
|
66
|
+
// quantity: 5,
|
|
67
|
+
// discountPercent: 10,
|
|
68
|
+
// customer: { tier: 'gold' }
|
|
69
|
+
// }
|
|
70
|
+
|
|
71
|
+
// Output: 386.8125
|
|
72
|
+
// Calculation:
|
|
73
|
+
// - Subtotal: 100 × 5 = 500
|
|
74
|
+
// - Item discount: 500 × 0.10 = 50
|
|
75
|
+
// - Tier discount: 500 × 0.15 = 75
|
|
76
|
+
// - After discounts: 500 - 50 - 75 = 375
|
|
77
|
+
// - With tax: 375 × 1.0975 = 411.5625
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Conditional Field Mapping
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
'custom.mapOrderType': (value, sourceData, config, helpers) => {
|
|
84
|
+
// Use sourceData to determine order type
|
|
85
|
+
const itemCount = helpers.get(sourceData, 'items.length') || 0;
|
|
86
|
+
const totalValue = helpers.get(sourceData, 'totalPrice') || 0;
|
|
87
|
+
const priority = helpers.get(sourceData, 'priority');
|
|
88
|
+
|
|
89
|
+
// Apply business rules from config
|
|
90
|
+
const thresholds = config.orderTypeThresholds || {
|
|
91
|
+
bulkItems: 50,
|
|
92
|
+
bulkValue: 10000
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (priority === 'URGENT') {
|
|
96
|
+
return 'EXPRESS';
|
|
97
|
+
} else if (itemCount >= thresholds.bulkItems || totalValue >= thresholds.bulkValue) {
|
|
98
|
+
return 'BULK';
|
|
99
|
+
} else if (totalValue < 100) {
|
|
100
|
+
return 'SMALL';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return 'STANDARD';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Usage
|
|
107
|
+
const mapper = new UniversalMapper(mapping, {
|
|
108
|
+
customResolvers: { 'custom.mapOrderType': mapOrderType },
|
|
109
|
+
context: {
|
|
110
|
+
orderTypeThresholds: {
|
|
111
|
+
bulkItems: 50,
|
|
112
|
+
bulkValue: 10000
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Dynamic Field Selection
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
'custom.selectAddress': (value, sourceData, config, helpers) => {
|
|
122
|
+
// Select shipping vs billing address based on context
|
|
123
|
+
const useShipping = helpers.get(sourceData, 'useShippingAddress');
|
|
124
|
+
const shippingAddr = helpers.get(sourceData, 'shippingAddress');
|
|
125
|
+
const billingAddr = helpers.get(sourceData, 'billingAddress');
|
|
126
|
+
|
|
127
|
+
const selectedAddr = useShipping ? shippingAddr : billingAddr;
|
|
128
|
+
|
|
129
|
+
// Format address using helper
|
|
130
|
+
const street = helpers.get(selectedAddr, 'street', '');
|
|
131
|
+
const city = helpers.get(selectedAddr, 'city', '');
|
|
132
|
+
const state = helpers.get(selectedAddr, 'state', '');
|
|
133
|
+
const zip = helpers.get(selectedAddr, 'zip', '');
|
|
134
|
+
|
|
135
|
+
return `${street}, ${city}, ${state} ${zip}`.trim();
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Async Resolvers with API Calls
|
|
140
|
+
|
|
141
|
+
### Fetch and Enrich Data
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
'custom.enrichWithProduct': async (sku, sourceData, config, helpers) => {
|
|
145
|
+
// Check if FluentClient is available
|
|
146
|
+
if (!helpers.fluentClient) {
|
|
147
|
+
helpers.log.warn('FluentClient not available, skipping enrichment');
|
|
148
|
+
return { sku };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
// Query Fluent API
|
|
153
|
+
const result = await helpers.fluentClient.graphql({
|
|
154
|
+
query: `
|
|
155
|
+
query GetProduct($ref: String!) {
|
|
156
|
+
product(ref: $ref) {
|
|
157
|
+
id
|
|
158
|
+
ref
|
|
159
|
+
name
|
|
160
|
+
gtin
|
|
161
|
+
status
|
|
162
|
+
attributes {
|
|
163
|
+
name
|
|
164
|
+
value
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
`,
|
|
169
|
+
variables: { ref: sku }
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (!result.data?.product) {
|
|
173
|
+
helpers.log.warn(`Product not found: ${sku}`);
|
|
174
|
+
return { sku, found: false };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
sku,
|
|
179
|
+
found: true,
|
|
180
|
+
...result.data.product
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
} catch (error) {
|
|
184
|
+
helpers.log.error(`Failed to fetch product ${sku}`, error);
|
|
185
|
+
return { sku, error: error.message };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Usage
|
|
190
|
+
const mapper = new UniversalMapper(mapping, {
|
|
191
|
+
customResolvers: { 'custom.enrichWithProduct': enrichWithProduct },
|
|
192
|
+
fluentClient: myFluentClient,
|
|
193
|
+
logger: myLogger
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Batch API Calls with Memoization
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
'custom.lookupCustomer': helpers.memoize(
|
|
201
|
+
async (customerId, sourceData, config, helpers) => {
|
|
202
|
+
if (!helpers.fluentClient) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
const result = await helpers.fluentClient.graphql({
|
|
208
|
+
query: `
|
|
209
|
+
query GetCustomer($id: ID!) {
|
|
210
|
+
customer(id: $id) {
|
|
211
|
+
id
|
|
212
|
+
firstName
|
|
213
|
+
lastName
|
|
214
|
+
email
|
|
215
|
+
tier
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`,
|
|
219
|
+
variables: { id: customerId }
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return result.data?.customer;
|
|
223
|
+
|
|
224
|
+
} catch (error) {
|
|
225
|
+
helpers.log.error(`Customer lookup failed: ${customerId}`, error);
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
// Memoization key function
|
|
230
|
+
(customerId) => customerId
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// This resolver will cache results by customerId
|
|
234
|
+
// Subsequent calls with same ID return cached result
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Retry Pattern for Resilience
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
'custom.fetchWithRetry': async (id, sourceData, config, helpers) => {
|
|
241
|
+
const maxRetries = config.maxRetries || 3;
|
|
242
|
+
const retryDelay = config.retryDelay || 1000;
|
|
243
|
+
|
|
244
|
+
const fetchData = async () => {
|
|
245
|
+
const result = await helpers.fluentClient.graphql({
|
|
246
|
+
query: `query { data(id: "${id}") { value } }`
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
if (!result.data) {
|
|
250
|
+
throw new Error('No data returned');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return result.data;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Use helper's retry utility
|
|
257
|
+
try {
|
|
258
|
+
return await helpers.retry(fetchData, {
|
|
259
|
+
maxAttempts: maxRetries,
|
|
260
|
+
delayMs: retryDelay,
|
|
261
|
+
backoffMultiplier: 2
|
|
262
|
+
});
|
|
263
|
+
} catch (error) {
|
|
264
|
+
helpers.log.error(`Failed after ${maxRetries} retries`, error);
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Usage
|
|
270
|
+
const mapper = new UniversalMapper(mapping, {
|
|
271
|
+
customResolvers: { 'custom.fetchWithRetry': fetchWithRetry },
|
|
272
|
+
context: {
|
|
273
|
+
maxRetries: 3,
|
|
274
|
+
retryDelay: 1000
|
|
275
|
+
},
|
|
276
|
+
fluentClient: myFluentClient,
|
|
277
|
+
logger: myLogger
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Complex Data Transformations
|
|
282
|
+
|
|
283
|
+
### Nested Object Construction
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
'custom.buildAddress': (value, sourceData, config, helpers) => {
|
|
287
|
+
// Extract address components from flat structure
|
|
288
|
+
const street = helpers.get(sourceData, 'addr_line1');
|
|
289
|
+
const street2 = helpers.get(sourceData, 'addr_line2');
|
|
290
|
+
const city = helpers.get(sourceData, 'addr_city');
|
|
291
|
+
const state = helpers.get(sourceData, 'addr_state');
|
|
292
|
+
const zip = helpers.get(sourceData, 'addr_zip');
|
|
293
|
+
const country = helpers.get(sourceData, 'addr_country') || config.defaultCountry;
|
|
294
|
+
|
|
295
|
+
// Build nested structure
|
|
296
|
+
return {
|
|
297
|
+
street1: street,
|
|
298
|
+
street2: street2 || null,
|
|
299
|
+
city,
|
|
300
|
+
state,
|
|
301
|
+
postalCode: zip,
|
|
302
|
+
country,
|
|
303
|
+
formatted: helpers.compact([street, street2, city, `${state} ${zip}`, country])
|
|
304
|
+
.join(', ')
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Output:
|
|
309
|
+
// {
|
|
310
|
+
// street1: "123 Main St",
|
|
311
|
+
// street2: "Apt 4B",
|
|
312
|
+
// city: "Springfield",
|
|
313
|
+
// state: "IL",
|
|
314
|
+
// postalCode: "62701",
|
|
315
|
+
// country: "USA",
|
|
316
|
+
// formatted: "123 Main St, Apt 4B, Springfield, IL 62701, USA"
|
|
317
|
+
// }
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Array Transformation with Filtering
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
'custom.processItems': (items, sourceData, config, helpers) => {
|
|
324
|
+
const arr = helpers.ensureArray(items);
|
|
325
|
+
|
|
326
|
+
// Filter, transform, and aggregate
|
|
327
|
+
const processed = arr
|
|
328
|
+
.filter(item => {
|
|
329
|
+
const qty = helpers.get(item, 'quantity') || 0;
|
|
330
|
+
return qty > 0; // Exclude zero-quantity items
|
|
331
|
+
})
|
|
332
|
+
.map(item => {
|
|
333
|
+
const price = helpers.parseFloatSafe(item.price, 0);
|
|
334
|
+
const qty = helpers.parseIntSafe(item.quantity, 1);
|
|
335
|
+
const taxRate = config.itemTaxRate || 0.08;
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
sku: item.sku,
|
|
339
|
+
quantity: qty,
|
|
340
|
+
unitPrice: price,
|
|
341
|
+
subtotal: price * qty,
|
|
342
|
+
tax: price * qty * taxRate,
|
|
343
|
+
total: price * qty * (1 + taxRate)
|
|
344
|
+
};
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Calculate totals
|
|
348
|
+
const summary = {
|
|
349
|
+
items: processed,
|
|
350
|
+
itemCount: processed.length,
|
|
351
|
+
subtotal: helpers.sum(processed.map(i => i.subtotal)),
|
|
352
|
+
tax: helpers.sum(processed.map(i => i.tax)),
|
|
353
|
+
total: helpers.sum(processed.map(i => i.total))
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
return summary;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Conditional Transformation Pipeline
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
'custom.transformWithPipeline': (value, sourceData, config, helpers) => {
|
|
364
|
+
let result = value;
|
|
365
|
+
|
|
366
|
+
// Apply transformations based on config
|
|
367
|
+
const pipeline = config.transformPipeline || [];
|
|
368
|
+
|
|
369
|
+
for (const step of pipeline) {
|
|
370
|
+
switch (step.type) {
|
|
371
|
+
case 'uppercase':
|
|
372
|
+
result = String(result).toUpperCase();
|
|
373
|
+
break;
|
|
374
|
+
|
|
375
|
+
case 'trim':
|
|
376
|
+
result = String(result).trim();
|
|
377
|
+
break;
|
|
378
|
+
|
|
379
|
+
case 'prefix':
|
|
380
|
+
result = `${step.value || ''}${result}`;
|
|
381
|
+
break;
|
|
382
|
+
|
|
383
|
+
case 'replace':
|
|
384
|
+
result = String(result).replace(
|
|
385
|
+
new RegExp(step.pattern, step.flags || 'g'),
|
|
386
|
+
step.replacement || ''
|
|
387
|
+
);
|
|
388
|
+
break;
|
|
389
|
+
|
|
390
|
+
case 'validate':
|
|
391
|
+
if (!new RegExp(step.pattern).test(result)) {
|
|
392
|
+
helpers.log.error(`Validation failed: ${result}`);
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
break;
|
|
396
|
+
|
|
397
|
+
default:
|
|
398
|
+
helpers.log.warn(`Unknown pipeline step: ${step.type}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Usage
|
|
406
|
+
const mapper = new UniversalMapper(mapping, {
|
|
407
|
+
customResolvers: { 'custom.transformWithPipeline': transformWithPipeline },
|
|
408
|
+
context: {
|
|
409
|
+
transformPipeline: [
|
|
410
|
+
{ type: 'trim' },
|
|
411
|
+
{ type: 'uppercase' },
|
|
412
|
+
{ type: 'replace', pattern: '[^A-Z0-9]', replacement: '-' },
|
|
413
|
+
{ type: 'prefix', value: 'SKU-' },
|
|
414
|
+
{ type: 'validate', pattern: '^SKU-[A-Z0-9-]+$' }
|
|
415
|
+
]
|
|
416
|
+
},
|
|
417
|
+
logger: myLogger
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Error Handling Patterns
|
|
422
|
+
|
|
423
|
+
### Graceful Degradation
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
'custom.safeTransform': (value, sourceData, config, helpers) => {
|
|
427
|
+
try {
|
|
428
|
+
// Attempt complex transformation
|
|
429
|
+
const result = complexTransformation(value);
|
|
430
|
+
|
|
431
|
+
// Validate result
|
|
432
|
+
if (!result || !result.isValid) {
|
|
433
|
+
throw new Error('Invalid transformation result');
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return result.value;
|
|
437
|
+
|
|
438
|
+
} catch (error) {
|
|
439
|
+
// Log error but don't fail
|
|
440
|
+
helpers.log.error('Transformation failed, using fallback', error);
|
|
441
|
+
|
|
442
|
+
// Return safe fallback value
|
|
443
|
+
return config.fallbackValue || value;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Validation with Detailed Errors
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
'custom.validateAndTransform': (value, sourceData, config, helpers) => {
|
|
452
|
+
const errors = [];
|
|
453
|
+
|
|
454
|
+
// Validate required fields
|
|
455
|
+
if (!value) {
|
|
456
|
+
errors.push('Value is required');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const quantity = helpers.get(sourceData, 'quantity');
|
|
460
|
+
if (!quantity || quantity <= 0) {
|
|
461
|
+
errors.push('Quantity must be positive');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const price = helpers.get(sourceData, 'price');
|
|
465
|
+
if (!price || price <= 0) {
|
|
466
|
+
errors.push('Price must be positive');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// If validation fails, log and return null
|
|
470
|
+
if (errors.length > 0) {
|
|
471
|
+
helpers.log.error('Validation failed', {
|
|
472
|
+
value,
|
|
473
|
+
errors,
|
|
474
|
+
sourceData
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
if (config.throwOnValidationError) {
|
|
478
|
+
throw new Error(`Validation failed: ${errors.join(', ')}`);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Perform transformation
|
|
485
|
+
return helpers.parseFloatSafe(price, 0) * helpers.parseIntSafe(quantity, 1);
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Performance Optimization
|
|
490
|
+
|
|
491
|
+
### Memoization for Expensive Operations
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
'custom.expensiveCalc': helpers.memoize(
|
|
495
|
+
(value, sourceData, config, helpers) => {
|
|
496
|
+
// Expensive calculation that should be cached
|
|
497
|
+
let result = 0;
|
|
498
|
+
for (let i = 0; i < 1000000; i++) {
|
|
499
|
+
result += Math.sqrt(i * value);
|
|
500
|
+
}
|
|
501
|
+
return result;
|
|
502
|
+
},
|
|
503
|
+
// Memoization key
|
|
504
|
+
(value) => value
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
// First call with value=5 calculates and caches
|
|
508
|
+
// Subsequent calls with value=5 return cached result instantly
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Batch Processing for Arrays
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
'custom.batchProcess': async (items, sourceData, config, helpers) => {
|
|
515
|
+
const arr = helpers.ensureArray(items);
|
|
516
|
+
const batchSize = config.batchSize || 10;
|
|
517
|
+
|
|
518
|
+
// Process in batches to avoid overwhelming API
|
|
519
|
+
const results = await helpers.batchProcess(
|
|
520
|
+
arr,
|
|
521
|
+
async (batch) => {
|
|
522
|
+
// Process each batch
|
|
523
|
+
const promises = batch.map(item =>
|
|
524
|
+
helpers.fluentClient.graphql({
|
|
525
|
+
query: `query { data(id: "${item.id}") { value } }`
|
|
526
|
+
})
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
return await Promise.all(promises);
|
|
530
|
+
},
|
|
531
|
+
batchSize
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
return results.flat();
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
## Complete Real-World Example
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
export const customResolvers = {
|
|
542
|
+
'custom.processOrder': async (orderId, sourceData, config, helpers) => {
|
|
543
|
+
// 1. VALUE: Order ID to process
|
|
544
|
+
if (!orderId) {
|
|
545
|
+
helpers.log.error('Order ID is required');
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// 2. SOURCEDATA: Get related data
|
|
550
|
+
const items = helpers.get(sourceData, 'items', []);
|
|
551
|
+
const customerTier = helpers.get(sourceData, 'customer.tier', 'standard');
|
|
552
|
+
const shippingZone = helpers.get(sourceData, 'shipping.zone');
|
|
553
|
+
|
|
554
|
+
// 3. CONFIG: Business rules
|
|
555
|
+
const tierDiscounts = config.tierDiscounts || {};
|
|
556
|
+
const shippingRates = config.shippingRates || {};
|
|
557
|
+
const taxRate = config.taxRate || 0.08;
|
|
558
|
+
|
|
559
|
+
// 4. HELPERS: Utilities and API calls
|
|
560
|
+
try {
|
|
561
|
+
// Validate items
|
|
562
|
+
if (items.length === 0) {
|
|
563
|
+
helpers.log.warn(`No items in order ${orderId}`);
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Calculate item totals
|
|
568
|
+
const itemTotals = items.map(item => {
|
|
569
|
+
const price = helpers.parseFloatSafe(item.price, 0);
|
|
570
|
+
const qty = helpers.parseIntSafe(item.quantity, 1);
|
|
571
|
+
return price * qty;
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// Calculate subtotal
|
|
575
|
+
const subtotal = helpers.sum(itemTotals);
|
|
576
|
+
|
|
577
|
+
// Apply tier discount
|
|
578
|
+
const discount = subtotal * (tierDiscounts[customerTier] || 0);
|
|
579
|
+
const afterDiscount = subtotal - discount;
|
|
580
|
+
|
|
581
|
+
// Calculate shipping
|
|
582
|
+
const shipping = shippingRates[shippingZone] || shippingRates.default || 0;
|
|
583
|
+
|
|
584
|
+
// Calculate tax
|
|
585
|
+
const tax = afterDiscount * taxRate;
|
|
586
|
+
|
|
587
|
+
// Calculate total
|
|
588
|
+
const total = afterDiscount + shipping + tax;
|
|
589
|
+
|
|
590
|
+
// Enrich with customer data if available
|
|
591
|
+
let customerData = null;
|
|
592
|
+
if (helpers.fluentClient && config.enrichWithCustomer) {
|
|
593
|
+
try {
|
|
594
|
+
const result = await helpers.fluentClient.graphql({
|
|
595
|
+
query: `
|
|
596
|
+
query GetCustomer($tier: String!) {
|
|
597
|
+
customers(tier: $tier, first: 1) {
|
|
598
|
+
edges {
|
|
599
|
+
node {
|
|
600
|
+
id
|
|
601
|
+
firstName
|
|
602
|
+
lastName
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
`,
|
|
608
|
+
variables: { tier: customerTier }
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
customerData = result.data?.customers?.edges[0]?.node;
|
|
612
|
+
} catch (error) {
|
|
613
|
+
helpers.log.error('Customer enrichment failed', error);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Return complete order summary
|
|
618
|
+
return {
|
|
619
|
+
orderId,
|
|
620
|
+
itemCount: items.length,
|
|
621
|
+
subtotal: helpers.parseFloatSafe(subtotal, 0),
|
|
622
|
+
discount: helpers.parseFloatSafe(discount, 0),
|
|
623
|
+
shipping: helpers.parseFloatSafe(shipping, 0),
|
|
624
|
+
tax: helpers.parseFloatSafe(tax, 0),
|
|
625
|
+
total: helpers.parseFloatSafe(total, 0),
|
|
626
|
+
customerTier,
|
|
627
|
+
customerData
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
} catch (error) {
|
|
631
|
+
helpers.log.error(`Order processing failed: ${orderId}`, error);
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
// Usage
|
|
638
|
+
const mapper = new UniversalMapper(mapping, {
|
|
639
|
+
customResolvers,
|
|
640
|
+
context: {
|
|
641
|
+
tierDiscounts: {
|
|
642
|
+
'platinum': 0.20,
|
|
643
|
+
'gold': 0.15,
|
|
644
|
+
'silver': 0.10,
|
|
645
|
+
'standard': 0.0
|
|
646
|
+
},
|
|
647
|
+
shippingRates: {
|
|
648
|
+
'local': 5.00,
|
|
649
|
+
'regional': 10.00,
|
|
650
|
+
'national': 15.00,
|
|
651
|
+
'default': 20.00
|
|
652
|
+
},
|
|
653
|
+
taxRate: 0.0975,
|
|
654
|
+
enrichWithCustomer: true
|
|
655
|
+
},
|
|
656
|
+
fluentClient: myFluentClient,
|
|
657
|
+
logger: myLogger
|
|
658
|
+
});
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
## Key Takeaways
|
|
662
|
+
|
|
663
|
+
- 🎯 **Use all 4 parameters** - Each serves a distinct purpose
|
|
664
|
+
- 🎯 **sourceData for context** - Access related fields for smart transformations
|
|
665
|
+
- 🎯 **config for business rules** - Keep logic configurable and testable
|
|
666
|
+
- 🎯 **helpers for utilities** - Use 48+ functions + FluentClient
|
|
667
|
+
- 🎯 **Handle errors gracefully** - Always provide fallbacks
|
|
668
|
+
- 🎯 **Optimize performance** - Use memoization and batch processing
|
|
669
|
+
|
|
670
|
+
## Practice Exercise
|
|
671
|
+
|
|
672
|
+
Create a resolver that calculates order priority:
|
|
673
|
+
|
|
674
|
+
**Requirements:**
|
|
675
|
+
- Use value as base priority
|
|
676
|
+
- Check if order has express shipping (sourceData)
|
|
677
|
+
- Apply priority multipliers from config
|
|
678
|
+
- Use helpers for safe calculations
|
|
679
|
+
- Return object with priority score and reasoning
|
|
680
|
+
|
|
681
|
+
<details>
|
|
682
|
+
<summary>Show Solution</summary>
|
|
683
|
+
|
|
684
|
+
```typescript
|
|
685
|
+
'custom.calculatePriority': (basePriority, sourceData, config, helpers) => {
|
|
686
|
+
// 1. VALUE: Base priority score
|
|
687
|
+
let score = helpers.parseIntSafe(basePriority, 50);
|
|
688
|
+
|
|
689
|
+
const reasons = [];
|
|
690
|
+
|
|
691
|
+
// 2. SOURCEDATA: Check order details
|
|
692
|
+
const isExpress = helpers.get(sourceData, 'shipping.express', false);
|
|
693
|
+
const customerTier = helpers.get(sourceData, 'customer.tier');
|
|
694
|
+
const orderValue = helpers.get(sourceData, 'totalValue', 0);
|
|
695
|
+
|
|
696
|
+
// 3. CONFIG: Priority multipliers
|
|
697
|
+
const multipliers = config.priorityMultipliers || {
|
|
698
|
+
express: 2.0,
|
|
699
|
+
platinum: 1.5,
|
|
700
|
+
gold: 1.3,
|
|
701
|
+
highValue: 1.2
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
// Calculate priority
|
|
705
|
+
if (isExpress) {
|
|
706
|
+
score *= multipliers.express;
|
|
707
|
+
reasons.push('express shipping');
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
if (customerTier === 'platinum') {
|
|
711
|
+
score *= multipliers.platinum;
|
|
712
|
+
reasons.push('platinum customer');
|
|
713
|
+
} else if (customerTier === 'gold') {
|
|
714
|
+
score *= multipliers.gold;
|
|
715
|
+
reasons.push('gold customer');
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (orderValue > 1000) {
|
|
719
|
+
score *= multipliers.highValue;
|
|
720
|
+
reasons.push('high value order');
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// 4. HELPERS: Safe calculations and logging
|
|
724
|
+
score = helpers.parseIntSafe(score, basePriority);
|
|
725
|
+
|
|
726
|
+
helpers.log.debug(`Priority: ${score} (${reasons.join(', ')})`);
|
|
727
|
+
|
|
728
|
+
return {
|
|
729
|
+
score,
|
|
730
|
+
level: score > 150 ? 'HIGH' : score > 100 ? 'MEDIUM' : 'LOW',
|
|
731
|
+
reasons
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
```
|
|
735
|
+
</details>
|
|
736
|
+
|
|
737
|
+
## Next Steps
|
|
738
|
+
|
|
739
|
+
Continue to [Module 5: SDK Resolvers](./resolver-signature-05-sdk-resolvers.md) to understand how built-in resolvers use the same 4-parameter signature.
|