@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.56
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/README.md +11 -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
|
@@ -1,653 +1,653 @@
|
|
|
1
|
-
# State Management Architecture
|
|
2
|
-
|
|
3
|
-
This document explains the distributed state management system in the FC Connect SDK, which prevents duplicate file processing and enables coordination across multiple workflow executions.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The SDK provides a **distributed state management system** built on key-value (KV) storage that enables:
|
|
8
|
-
|
|
9
|
-
- File deduplication across workflow runs
|
|
10
|
-
- Job ID caching for reuse
|
|
11
|
-
- Batch count tracking for job strategies
|
|
12
|
-
- Timestamp-based windowing
|
|
13
|
-
- Distributed locking with stale detection
|
|
14
|
-
|
|
15
|
-
```mermaid
|
|
16
|
-
graph TB
|
|
17
|
-
subgraph "State Management"
|
|
18
|
-
STATE_SERVICE[StateService]
|
|
19
|
-
KV_ADAPTER[KV Adapter Interface]
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
subgraph "Storage Implementations"
|
|
23
|
-
VERSORI_KV[VersoriKVAdapter]
|
|
24
|
-
MEMORY_KV[InMemoryKVAdapter]
|
|
25
|
-
CUSTOM_KV[Custom KV Adapter]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
subgraph "Use Cases"
|
|
29
|
-
DEDUP[File Deduplication]
|
|
30
|
-
JOB_CACHE[Job ID Caching]
|
|
31
|
-
BATCH_COUNT[Batch Counting]
|
|
32
|
-
LOCK[Distributed Locking]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
STATE_SERVICE --> KV_ADAPTER
|
|
36
|
-
KV_ADAPTER --> VERSORI_KV
|
|
37
|
-
KV_ADAPTER --> MEMORY_KV
|
|
38
|
-
KV_ADAPTER --> CUSTOM_KV
|
|
39
|
-
|
|
40
|
-
STATE_SERVICE --> DEDUP
|
|
41
|
-
STATE_SERVICE --> JOB_CACHE
|
|
42
|
-
STATE_SERVICE --> BATCH_COUNT
|
|
43
|
-
STATE_SERVICE --> LOCK
|
|
44
|
-
|
|
45
|
-
style STATE_SERVICE fill:#e3f2fd
|
|
46
|
-
style VERSORI_KV fill:#e8f5e9
|
|
47
|
-
style DEDUP fill:#fff3e0
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## State Object Structure
|
|
51
|
-
|
|
52
|
-
The SDK stores state in structured objects:
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
// Sync state (for workflow tracking)
|
|
56
|
-
interface SyncState {
|
|
57
|
-
lastProcessedTimestamp?: string;
|
|
58
|
-
lastProcessedFile?: string;
|
|
59
|
-
lastProcessedCount?: number;
|
|
60
|
-
isInitialized: boolean;
|
|
61
|
-
lastSyncResult?: 'success' | 'failure' | 'partial';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Daily job information (for DAILY strategy)
|
|
65
|
-
interface DailyJob {
|
|
66
|
-
jobId: string;
|
|
67
|
-
createdAt: string;
|
|
68
|
-
expiresAt: string;
|
|
69
|
-
batchCount?: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Processed file metadata
|
|
73
|
-
interface ProcessedFile {
|
|
74
|
-
fileName: string;
|
|
75
|
-
lastModified: string;
|
|
76
|
-
recordCount?: number;
|
|
77
|
-
processedAt?: string;
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## File Deduplication Flow
|
|
82
|
-
|
|
83
|
-
```mermaid
|
|
84
|
-
sequenceDiagram
|
|
85
|
-
participant Workflow
|
|
86
|
-
participant StateService
|
|
87
|
-
participant KVStorage
|
|
88
|
-
participant S3
|
|
89
|
-
|
|
90
|
-
Workflow->>S3: List files
|
|
91
|
-
S3-->>Workflow: [file1.csv, file2.csv, file3.csv]
|
|
92
|
-
|
|
93
|
-
loop For Each File
|
|
94
|
-
Workflow->>StateService: isFileProcessed(kv, 'file1.csv', workflowId)
|
|
95
|
-
StateService->>KVStorage: get(file key)
|
|
96
|
-
KVStorage-->>StateService: File status
|
|
97
|
-
|
|
98
|
-
StateService->>StateService: Check file key
|
|
99
|
-
|
|
100
|
-
alt File Already Processed
|
|
101
|
-
StateService-->>Workflow: true (skip file)
|
|
102
|
-
else File Not Processed
|
|
103
|
-
StateService-->>Workflow: false (process file)
|
|
104
|
-
|
|
105
|
-
Workflow->>Workflow: Process file1.csv
|
|
106
|
-
|
|
107
|
-
Workflow->>StateService: updateSyncState(kv, processedFiles, workflowId)
|
|
108
|
-
StateService->>StateService: Add to processedFiles array
|
|
109
|
-
StateService->>KVStorage: set(state key, updatedState)
|
|
110
|
-
KVStorage-->>StateService: Confirmation
|
|
111
|
-
StateService-->>Workflow: Marked as processed
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**Example Code:**
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
import { StateService, VersoriKVAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
120
|
-
// ✅ CORRECT: Access openKv from Versori context
|
|
121
|
-
// import { openKv } from '@versori/run'; // ❌ WRONG - Not a direct export
|
|
122
|
-
|
|
123
|
-
// In Versori workflow handler:
|
|
124
|
-
const { openKv } = ctx;
|
|
125
|
-
const kv = openKv(':project:');
|
|
126
|
-
const kvAdapter = new VersoriKVAdapter(kv);
|
|
127
|
-
const stateService = new StateService(logger); // logger is optional
|
|
128
|
-
|
|
129
|
-
// IMPORTANT: All StateService methods require 'kv' as first parameter
|
|
130
|
-
|
|
131
|
-
// Check if file processed (note: kv is first parameter)
|
|
132
|
-
const processed = await stateService.isFileProcessed(
|
|
133
|
-
kvAdapter,
|
|
134
|
-
'inventory-2025-01-15.csv',
|
|
135
|
-
'my-ingestion'
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
if (!processed) {
|
|
139
|
-
// Process file
|
|
140
|
-
const result = await processFile();
|
|
141
|
-
|
|
142
|
-
// Update sync state with processed file metadata
|
|
143
|
-
await stateService.updateSyncState(
|
|
144
|
-
kvAdapter,
|
|
145
|
-
[
|
|
146
|
-
{
|
|
147
|
-
fileName: 'inventory-2025-01-15.csv',
|
|
148
|
-
lastModified: new Date().toISOString(),
|
|
149
|
-
recordCount: 1500,
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
'my-ingestion'
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Job Caching for DAILY Strategy
|
|
158
|
-
|
|
159
|
-
The DAILY job strategy reuses the same job for all files processed in a day:
|
|
160
|
-
|
|
161
|
-
```mermaid
|
|
162
|
-
flowchart TD
|
|
163
|
-
START[Start Processing] --> CHECK{Daily Job<br/>Cached?}
|
|
164
|
-
|
|
165
|
-
CHECK -->|Yes| VALIDATE{Job Still<br/>Valid?}
|
|
166
|
-
CHECK -->|No| CREATE_NEW[Create New Job]
|
|
167
|
-
|
|
168
|
-
VALIDATE -->|Valid| USE_CACHED[Use Cached Job ID]
|
|
169
|
-
VALIDATE -->|Expired/Closed| CREATE_NEW
|
|
170
|
-
|
|
171
|
-
CREATE_NEW --> CACHE[Cache Job ID in State]
|
|
172
|
-
CACHE --> USE_NEW[Use New Job]
|
|
173
|
-
|
|
174
|
-
USE_CACHED --> SEND[Send Batches]
|
|
175
|
-
USE_NEW --> SEND
|
|
176
|
-
|
|
177
|
-
SEND --> DONE[Complete]
|
|
178
|
-
|
|
179
|
-
style CHECK fill:#e3f2fd
|
|
180
|
-
style CREATE_NEW fill:#fff3e0
|
|
181
|
-
style USE_CACHED fill:#e8f5e9
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**State Flow:**
|
|
185
|
-
|
|
186
|
-
```mermaid
|
|
187
|
-
sequenceDiagram
|
|
188
|
-
participant Orch as Orchestrator
|
|
189
|
-
participant State as StateService
|
|
190
|
-
participant KV as KVStorage
|
|
191
|
-
participant Fluent as FluentAPI
|
|
192
|
-
|
|
193
|
-
Orch->>State: getDailyJob(KV, 'ingestion')
|
|
194
|
-
State->>KV: get(jobKey)
|
|
195
|
-
KV-->>State: { jobId, expiresAt }
|
|
196
|
-
|
|
197
|
-
alt Job Exists and Valid
|
|
198
|
-
State-->>Orch: jobId
|
|
199
|
-
else Missing or Expired
|
|
200
|
-
Orch->>Fluent: Create new job
|
|
201
|
-
Fluent-->>Orch: job-456
|
|
202
|
-
Orch->>State: setDailyJob(KV, 'ingestion', 'job-456', 24)
|
|
203
|
-
State->>KV: set(jobKey, job)
|
|
204
|
-
end
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**Example:**
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
const stateService = new StateService(logger);
|
|
211
|
-
|
|
212
|
-
// Get cached daily job (kv is first parameter)
|
|
213
|
-
let dailyJob = await stateService.getDailyJob(kvAdapter, 'inventory-ingestion');
|
|
214
|
-
let jobId = dailyJob?.jobId;
|
|
215
|
-
|
|
216
|
-
if (!jobId) {
|
|
217
|
-
// Create new job
|
|
218
|
-
const job = await fluentClient.createJob({
|
|
219
|
-
name: `inventory-sync-${new Date().toISOString().split('T')[0]}`,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// Cache for reuse (kv is first parameter)
|
|
223
|
-
await stateService.setDailyJob(kvAdapter, 'inventory-ingestion', job.id, 24);
|
|
224
|
-
jobId = job.id;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Use job for all batches today
|
|
228
|
-
await fluentClient.sendBatch(jobId, { entityType: 'INVENTORY', action: 'UPSERT', entities: data });
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## Batch Counting for BATCHES_PER_JOB Strategy
|
|
232
|
-
|
|
233
|
-
Track batches per job to create a new job after N batches:
|
|
234
|
-
|
|
235
|
-
```mermaid
|
|
236
|
-
flowchart TD
|
|
237
|
-
START[Start Batch] --> GET_COUNT[Get Current Batch Count]
|
|
238
|
-
GET_COUNT --> CHECK{Count ≥<br/>Max Batches?}
|
|
239
|
-
|
|
240
|
-
CHECK -->|Yes| CREATE[Create New Job]
|
|
241
|
-
CHECK -->|No| USE[Use Current Job]
|
|
242
|
-
|
|
243
|
-
CREATE --> RESET[Reset Batch Count = 0]
|
|
244
|
-
RESET --> INCREMENT
|
|
245
|
-
|
|
246
|
-
USE --> INCREMENT[Increment Batch Count]
|
|
247
|
-
INCREMENT --> UPDATE[Update State]
|
|
248
|
-
UPDATE --> SEND[Send Batch]
|
|
249
|
-
SEND --> DONE[Complete]
|
|
250
|
-
|
|
251
|
-
style CHECK fill:#e3f2fd
|
|
252
|
-
style CREATE fill:#fff3e0
|
|
253
|
-
style INCREMENT fill:#e8f5e9
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**Example:**
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
const MAX_BATCHES_PER_JOB = 10;
|
|
260
|
-
|
|
261
|
-
// Read current state (example tracking via your own key)
|
|
262
|
-
const dailyJob = await stateService.getDailyJob(kvAdapter, 'inventory-ingestion');
|
|
263
|
-
const currentCount = dailyJob?.batchCount ?? 0;
|
|
264
|
-
|
|
265
|
-
if (currentCount >= MAX_BATCHES_PER_JOB) {
|
|
266
|
-
const job = await fluentClient.createJob({ name: 'inventory-sync' });
|
|
267
|
-
await stateService.setDailyJob(kvAdapter, 'inventory-ingestion', job.id, 24);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
await fluentClient.sendBatch(dailyJob?.jobId || '', {
|
|
271
|
-
entityType: 'INVENTORY',
|
|
272
|
-
action: 'UPSERT',
|
|
273
|
-
entities: data,
|
|
274
|
-
});
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Distributed Locking
|
|
278
|
-
|
|
279
|
-
Prevent concurrent workflow executions from processing the same files:
|
|
280
|
-
|
|
281
|
-
```mermaid
|
|
282
|
-
sequenceDiagram
|
|
283
|
-
participant W1 as Workflow 1
|
|
284
|
-
participant W2 as Workflow 2
|
|
285
|
-
participant State as StateService
|
|
286
|
-
participant KV as KVStorage
|
|
287
|
-
|
|
288
|
-
par Concurrent Execution
|
|
289
|
-
W1->>State: acquireLock('file1.csv', kv, 15)
|
|
290
|
-
W2->>State: acquireLock('file1.csv', kv, 15)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
State->>KV: get('lock:file1.csv')
|
|
294
|
-
KV-->>State: null (no lock)
|
|
295
|
-
|
|
296
|
-
State->>KV: set('lock:file1.csv', { owner: 'W1', timestamp })
|
|
297
|
-
KV-->>State: Lock acquired
|
|
298
|
-
|
|
299
|
-
State-->>W1: Lock acquired (process file)
|
|
300
|
-
State-->>W2: Lock already held (skip file)
|
|
301
|
-
|
|
302
|
-
W1->>W1: Process file1.csv
|
|
303
|
-
W1->>State: releaseLock('file1.csv', kv)
|
|
304
|
-
State->>KV: delete('lock:file1.csv')
|
|
305
|
-
KV-->>State: Lock released
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
**Stale Lock Detection:**
|
|
309
|
-
|
|
310
|
-
If a workflow crashes while holding a lock, the lock becomes stale:
|
|
311
|
-
|
|
312
|
-
```mermaid
|
|
313
|
-
flowchart TD
|
|
314
|
-
TRY[Try Acquire Lock] --> EXISTS{Lock<br/>Exists?}
|
|
315
|
-
|
|
316
|
-
EXISTS -->|No| ACQUIRE[Acquire Lock]
|
|
317
|
-
EXISTS -->|Yes| CHECK_TIME{Lock Age > 30 min?}
|
|
318
|
-
|
|
319
|
-
CHECK_TIME -->|Yes| STALE[Lock is Stale]
|
|
320
|
-
CHECK_TIME -->|No| HELD[Lock Held by Other Process]
|
|
321
|
-
|
|
322
|
-
STALE --> OVERRIDE[Override Stale Lock]
|
|
323
|
-
OVERRIDE --> ACQUIRE
|
|
324
|
-
|
|
325
|
-
ACQUIRE --> SUCCESS[Lock Acquired]
|
|
326
|
-
HELD --> FAIL[Lock Failed]
|
|
327
|
-
|
|
328
|
-
style ACQUIRE fill:#e8f5e9
|
|
329
|
-
style STALE fill:#fff3e0
|
|
330
|
-
style FAIL fill:#ffebee
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
**Example:**
|
|
334
|
-
|
|
335
|
-
```typescript
|
|
336
|
-
const stateService = new StateService(logger);
|
|
337
|
-
|
|
338
|
-
// Acquire lock (kv is first parameter)
|
|
339
|
-
const acquired = await stateService.acquireLock('file1.csv', kvAdapter, 15);
|
|
340
|
-
|
|
341
|
-
if (acquired) {
|
|
342
|
-
try {
|
|
343
|
-
// Process file
|
|
344
|
-
await processFile();
|
|
345
|
-
} finally {
|
|
346
|
-
// Always release lock
|
|
347
|
-
await stateService.releaseLock('file1.csv', kvAdapter);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
## State Cleanup and Maintenance
|
|
353
|
-
|
|
354
|
-
```mermaid
|
|
355
|
-
flowchart TD
|
|
356
|
-
START[Maintenance Job] --> GET[Get Current State]
|
|
357
|
-
GET --> FILTER[Filter Processed Files]
|
|
358
|
-
|
|
359
|
-
FILTER --> OLD{Files Older<br/>Than 30 Days?}
|
|
360
|
-
|
|
361
|
-
OLD -->|Yes| REMOVE[Remove from Array]
|
|
362
|
-
OLD -->|No| KEEP[Keep in Array]
|
|
363
|
-
|
|
364
|
-
REMOVE --> UPDATE[Update State]
|
|
365
|
-
KEEP --> UPDATE
|
|
366
|
-
|
|
367
|
-
UPDATE --> CHECK_JOB{Daily Job<br/>Still Valid?}
|
|
368
|
-
|
|
369
|
-
CHECK_JOB -->|Expired| CLEAR_JOB[Clear dailyJobId]
|
|
370
|
-
CHECK_JOB -->|Valid| SKIP
|
|
371
|
-
|
|
372
|
-
CLEAR_JOB --> SAVE[Save State]
|
|
373
|
-
SKIP --> SAVE
|
|
374
|
-
|
|
375
|
-
SAVE --> DONE[Complete]
|
|
376
|
-
|
|
377
|
-
style REMOVE fill:#fff3e0
|
|
378
|
-
style CLEAR_JOB fill:#fff3e0
|
|
379
|
-
style SAVE fill:#e8f5e9
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
**Example Cleanup:**
|
|
383
|
-
|
|
384
|
-
```typescript
|
|
385
|
-
async function cleanupOldEntries() {
|
|
386
|
-
// Get sync state (kv is first parameter)
|
|
387
|
-
const state = await stateService.getSyncState(kvAdapter, 'my-workflow');
|
|
388
|
-
|
|
389
|
-
// Note: File tracking uses individual file keys, not an array
|
|
390
|
-
// This example shows conceptual cleanup - actual implementation
|
|
391
|
-
// would need to list and delete individual file keys
|
|
392
|
-
|
|
393
|
-
logger.info('Current sync state', {
|
|
394
|
-
lastProcessedFile: state.lastProcessedFile,
|
|
395
|
-
lastProcessedTimestamp: state.lastProcessedTimestamp,
|
|
396
|
-
totalRecords: state.lastProcessedCount,
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
## KV Adapter Interface
|
|
402
|
-
|
|
403
|
-
The SDK defines a KV adapter interface for pluggable storage:
|
|
404
|
-
|
|
405
|
-
```mermaid
|
|
406
|
-
classDiagram
|
|
407
|
-
class KVStorageAdapter {
|
|
408
|
-
<<interface>>
|
|
409
|
-
+get(key: string) Promise~any~
|
|
410
|
-
+set(key: string, value: any) Promise~void~
|
|
411
|
-
+delete(key: string) Promise~void~
|
|
412
|
-
+list(prefix?: string) Promise~string[]~
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
class VersoriKVAdapter {
|
|
416
|
-
-kv: KV
|
|
417
|
-
+get(key: string) Promise~any~
|
|
418
|
-
+set(key: string, value: any) Promise~void~
|
|
419
|
-
+delete(key: string) Promise~void~
|
|
420
|
-
+list(prefix?: string) Promise~string[]~
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
class InMemoryKVAdapter {
|
|
424
|
-
-storage: Map
|
|
425
|
-
+get(key: string) Promise~any~
|
|
426
|
-
+set(key: string, value: any) Promise~void~
|
|
427
|
-
+delete(key: string) Promise~void~
|
|
428
|
-
+list(prefix?: string) Promise~string[]~
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
class CustomKVAdapter {
|
|
432
|
-
-client: any
|
|
433
|
-
+get(key: string) Promise~any~
|
|
434
|
-
+set(key: string, value: any) Promise~void~
|
|
435
|
-
+delete(key: string) Promise~void~
|
|
436
|
-
+list(prefix?: string) Promise~string[]~
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
KVStorageAdapter <|.. VersoriKVAdapter
|
|
440
|
-
KVStorageAdapter <|.. InMemoryKVAdapter
|
|
441
|
-
KVStorageAdapter <|.. CustomKVAdapter
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
**Implementing Custom Adapter:**
|
|
445
|
-
|
|
446
|
-
```typescript
|
|
447
|
-
import { KVStorageAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
448
|
-
|
|
449
|
-
class RedisKVAdapter implements KVStorageAdapter {
|
|
450
|
-
constructor(private redis: RedisClient) {}
|
|
451
|
-
|
|
452
|
-
async get(key: string): Promise<any> {
|
|
453
|
-
const value = await this.redis.get(key);
|
|
454
|
-
return value ? JSON.parse(value) : null;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
async set(key: string, value: any): Promise<void> {
|
|
458
|
-
await this.redis.set(key, JSON.stringify(value));
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
async delete(key: string): Promise<void> {
|
|
462
|
-
await this.redis.del(key);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
async list(prefix?: string): Promise<string[]> {
|
|
466
|
-
const pattern = prefix ? `${prefix}*` : '*';
|
|
467
|
-
return await this.redis.keys(pattern);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Use custom adapter
|
|
472
|
-
const kvAdapter = new RedisKVAdapter(redisClient);
|
|
473
|
-
const stateService = new StateService(logger);
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
## State Versioning
|
|
477
|
-
|
|
478
|
-
Handle state schema evolution gracefully:
|
|
479
|
-
|
|
480
|
-
```mermaid
|
|
481
|
-
flowchart TD
|
|
482
|
-
READ[Read State from KV] --> CHECK{Has Version?}
|
|
483
|
-
|
|
484
|
-
CHECK -->|No| V1[Assume Version 1]
|
|
485
|
-
CHECK -->|Yes| VERSION{Which<br/>Version?}
|
|
486
|
-
|
|
487
|
-
VERSION -->|v1| MIGRATE_V2[Migrate v1 → v2]
|
|
488
|
-
VERSION -->|v2| MIGRATE_V3[Migrate v2 → v3]
|
|
489
|
-
VERSION -->|v3| CURRENT[Use Current Schema]
|
|
490
|
-
|
|
491
|
-
MIGRATE_V2 --> MIGRATE_V3
|
|
492
|
-
V1 --> MIGRATE_V2
|
|
493
|
-
|
|
494
|
-
MIGRATE_V3 --> CURRENT
|
|
495
|
-
CURRENT --> USE[Use State]
|
|
496
|
-
|
|
497
|
-
USE --> WRITE[Write with Current Version]
|
|
498
|
-
|
|
499
|
-
style MIGRATE_V2 fill:#fff3e0
|
|
500
|
-
style MIGRATE_V3 fill:#fff3e0
|
|
501
|
-
style CURRENT fill:#e8f5e9
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
**Example Migration:**
|
|
505
|
-
|
|
506
|
-
```typescript
|
|
507
|
-
interface StateV1 {
|
|
508
|
-
processedFiles: string[]; // Just file keys
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
interface StateV2 {
|
|
512
|
-
version: 2;
|
|
513
|
-
processedFiles: ProcessedFileEntry[]; // Full metadata
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
async function migrateState(state: any): Promise<StateV2> {
|
|
517
|
-
if (!state.version) {
|
|
518
|
-
// Migrate v1 to v2
|
|
519
|
-
return {
|
|
520
|
-
version: 2,
|
|
521
|
-
processedFiles: state.processedFiles.map((key: string) => ({
|
|
522
|
-
key,
|
|
523
|
-
timestamp: new Date().toISOString(),
|
|
524
|
-
})),
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return state;
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
## Performance Considerations
|
|
533
|
-
|
|
534
|
-
```mermaid
|
|
535
|
-
graph TB
|
|
536
|
-
PERF[Performance Optimizations]
|
|
537
|
-
|
|
538
|
-
PERF --> BATCH_OPS[Batch KV Operations]
|
|
539
|
-
PERF --> CACHE[In-memory Caching]
|
|
540
|
-
PERF --> COMPRESS[Compress Large States]
|
|
541
|
-
PERF --> PRUNE[Prune Old Entries]
|
|
542
|
-
|
|
543
|
-
BATCH_OPS --> READ[Batch Reads]
|
|
544
|
-
BATCH_OPS --> WRITE[Batch Writes]
|
|
545
|
-
|
|
546
|
-
CACHE --> TTL[Time-based TTL]
|
|
547
|
-
CACHE --> INVALIDATE[Smart Invalidation]
|
|
548
|
-
|
|
549
|
-
COMPRESS --> GZIP[GZIP Compression]
|
|
550
|
-
COMPRESS --> THRESHOLD[Only if > 1MB]
|
|
551
|
-
|
|
552
|
-
PRUNE --> SCHEDULE[Scheduled Cleanup]
|
|
553
|
-
PRUNE --> LIMIT[Max 10k Entries]
|
|
554
|
-
|
|
555
|
-
style PERF fill:#e3f2fd
|
|
556
|
-
style BATCH_OPS fill:#fff3e0
|
|
557
|
-
style CACHE fill:#f3e5f5
|
|
558
|
-
style COMPRESS fill:#e8f5e9
|
|
559
|
-
style PRUNE fill:#e1f5ff
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
## Best Practices
|
|
563
|
-
|
|
564
|
-
### 1. Namespace State Keys
|
|
565
|
-
|
|
566
|
-
```typescript
|
|
567
|
-
// Good - namespaced with logger
|
|
568
|
-
const stateService = new StateService(logger); // logger is optional
|
|
569
|
-
const namespace = 'inventory-ingestion';
|
|
570
|
-
|
|
571
|
-
// Use workflowId parameter to scope state
|
|
572
|
-
await stateService.isFileProcessed(kvAdapter, 'file.csv', namespace);
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### 2. Handle State Corruption
|
|
576
|
-
|
|
577
|
-
```typescript
|
|
578
|
-
// Implement your own backup/fallback strategy using your KV implementation
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
### 3. Monitor State Size
|
|
582
|
-
|
|
583
|
-
```typescript
|
|
584
|
-
// Implement size checks using your KV implementation if listing is supported
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
### 4. Test with Mocks
|
|
588
|
-
|
|
589
|
-
```typescript
|
|
590
|
-
import { StateService } from '@fluentcommerce/fc-connect-sdk';
|
|
591
|
-
|
|
592
|
-
describe('Ingestion with State', () => {
|
|
593
|
-
it('should skip processed files', async () => {
|
|
594
|
-
// Mock KV adapter for testing
|
|
595
|
-
const mockKV = {
|
|
596
|
-
get: jest.fn(),
|
|
597
|
-
set: jest.fn(),
|
|
598
|
-
delete: jest.fn(),
|
|
599
|
-
atomic: jest.fn()
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
const stateService = new StateService(); // no logger for tests
|
|
603
|
-
|
|
604
|
-
// Pre-populate state
|
|
605
|
-
await stateService.updateSyncState(mockKV, [{
|
|
606
|
-
fileName: 'file1.csv',
|
|
607
|
-
lastModified: new Date().toISOString(),
|
|
608
|
-
}]);
|
|
609
|
-
|
|
610
|
-
// Test deduplication (kv is first parameter)
|
|
611
|
-
const processed = await stateService.isFileProcessed(mockKV, 'file1.csv');
|
|
612
|
-
expect(processed).toBe(true);
|
|
613
|
-
});
|
|
614
|
-
});
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
## Monitoring and Debugging
|
|
618
|
-
|
|
619
|
-
### State Inspection
|
|
620
|
-
|
|
621
|
-
```typescript
|
|
622
|
-
async function inspectState() {
|
|
623
|
-
// Get sync state (kv is first parameter)
|
|
624
|
-
const state = await stateService.getSyncState(kvAdapter, 'my-workflow');
|
|
625
|
-
|
|
626
|
-
console.log('State Summary:');
|
|
627
|
-
console.log('- Last processed file:', state.lastProcessedFile);
|
|
628
|
-
console.log('- Last processed timestamp:', state.lastProcessedTimestamp);
|
|
629
|
-
console.log('- Total records:', state.lastProcessedCount);
|
|
630
|
-
console.log('- Initialized:', state.isInitialized);
|
|
631
|
-
console.log('- Last sync result:', state.lastSyncResult);
|
|
632
|
-
}
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
### State Reset (Emergency)
|
|
636
|
-
|
|
637
|
-
```typescript
|
|
638
|
-
async function resetState() {
|
|
639
|
-
logger.warn('Resetting state - all processed files will be forgotten');
|
|
640
|
-
|
|
641
|
-
// Clear state for workflow (kv is first parameter)
|
|
642
|
-
await stateService.clearState(kvAdapter, 'my-workflow');
|
|
643
|
-
|
|
644
|
-
logger.info('State reset complete');
|
|
645
|
-
}
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
## Next Steps
|
|
649
|
-
|
|
650
|
-
- [Overview](./architecture-01-overview.md) - Architecture overview
|
|
651
|
-
- [Client Architecture](./architecture-02-client-architecture.md) - Client layer
|
|
652
|
-
- [Data Flow](./architecture-03-data-flow.md) - Data processing patterns
|
|
653
|
-
- [Getting Started](../../00-START-HERE/getting-started.md) - Start building
|
|
1
|
+
# State Management Architecture
|
|
2
|
+
|
|
3
|
+
This document explains the distributed state management system in the FC Connect SDK, which prevents duplicate file processing and enables coordination across multiple workflow executions.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The SDK provides a **distributed state management system** built on key-value (KV) storage that enables:
|
|
8
|
+
|
|
9
|
+
- File deduplication across workflow runs
|
|
10
|
+
- Job ID caching for reuse
|
|
11
|
+
- Batch count tracking for job strategies
|
|
12
|
+
- Timestamp-based windowing
|
|
13
|
+
- Distributed locking with stale detection
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
graph TB
|
|
17
|
+
subgraph "State Management"
|
|
18
|
+
STATE_SERVICE[StateService]
|
|
19
|
+
KV_ADAPTER[KV Adapter Interface]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
subgraph "Storage Implementations"
|
|
23
|
+
VERSORI_KV[VersoriKVAdapter]
|
|
24
|
+
MEMORY_KV[InMemoryKVAdapter]
|
|
25
|
+
CUSTOM_KV[Custom KV Adapter]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
subgraph "Use Cases"
|
|
29
|
+
DEDUP[File Deduplication]
|
|
30
|
+
JOB_CACHE[Job ID Caching]
|
|
31
|
+
BATCH_COUNT[Batch Counting]
|
|
32
|
+
LOCK[Distributed Locking]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
STATE_SERVICE --> KV_ADAPTER
|
|
36
|
+
KV_ADAPTER --> VERSORI_KV
|
|
37
|
+
KV_ADAPTER --> MEMORY_KV
|
|
38
|
+
KV_ADAPTER --> CUSTOM_KV
|
|
39
|
+
|
|
40
|
+
STATE_SERVICE --> DEDUP
|
|
41
|
+
STATE_SERVICE --> JOB_CACHE
|
|
42
|
+
STATE_SERVICE --> BATCH_COUNT
|
|
43
|
+
STATE_SERVICE --> LOCK
|
|
44
|
+
|
|
45
|
+
style STATE_SERVICE fill:#e3f2fd
|
|
46
|
+
style VERSORI_KV fill:#e8f5e9
|
|
47
|
+
style DEDUP fill:#fff3e0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## State Object Structure
|
|
51
|
+
|
|
52
|
+
The SDK stores state in structured objects:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Sync state (for workflow tracking)
|
|
56
|
+
interface SyncState {
|
|
57
|
+
lastProcessedTimestamp?: string;
|
|
58
|
+
lastProcessedFile?: string;
|
|
59
|
+
lastProcessedCount?: number;
|
|
60
|
+
isInitialized: boolean;
|
|
61
|
+
lastSyncResult?: 'success' | 'failure' | 'partial';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Daily job information (for DAILY strategy)
|
|
65
|
+
interface DailyJob {
|
|
66
|
+
jobId: string;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
expiresAt: string;
|
|
69
|
+
batchCount?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Processed file metadata
|
|
73
|
+
interface ProcessedFile {
|
|
74
|
+
fileName: string;
|
|
75
|
+
lastModified: string;
|
|
76
|
+
recordCount?: number;
|
|
77
|
+
processedAt?: string;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## File Deduplication Flow
|
|
82
|
+
|
|
83
|
+
```mermaid
|
|
84
|
+
sequenceDiagram
|
|
85
|
+
participant Workflow
|
|
86
|
+
participant StateService
|
|
87
|
+
participant KVStorage
|
|
88
|
+
participant S3
|
|
89
|
+
|
|
90
|
+
Workflow->>S3: List files
|
|
91
|
+
S3-->>Workflow: [file1.csv, file2.csv, file3.csv]
|
|
92
|
+
|
|
93
|
+
loop For Each File
|
|
94
|
+
Workflow->>StateService: isFileProcessed(kv, 'file1.csv', workflowId)
|
|
95
|
+
StateService->>KVStorage: get(file key)
|
|
96
|
+
KVStorage-->>StateService: File status
|
|
97
|
+
|
|
98
|
+
StateService->>StateService: Check file key
|
|
99
|
+
|
|
100
|
+
alt File Already Processed
|
|
101
|
+
StateService-->>Workflow: true (skip file)
|
|
102
|
+
else File Not Processed
|
|
103
|
+
StateService-->>Workflow: false (process file)
|
|
104
|
+
|
|
105
|
+
Workflow->>Workflow: Process file1.csv
|
|
106
|
+
|
|
107
|
+
Workflow->>StateService: updateSyncState(kv, processedFiles, workflowId)
|
|
108
|
+
StateService->>StateService: Add to processedFiles array
|
|
109
|
+
StateService->>KVStorage: set(state key, updatedState)
|
|
110
|
+
KVStorage-->>StateService: Confirmation
|
|
111
|
+
StateService-->>Workflow: Marked as processed
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Example Code:**
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { StateService, VersoriKVAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
120
|
+
// ✅ CORRECT: Access openKv from Versori context
|
|
121
|
+
// import { openKv } from '@versori/run'; // ❌ WRONG - Not a direct export
|
|
122
|
+
|
|
123
|
+
// In Versori workflow handler:
|
|
124
|
+
const { openKv } = ctx;
|
|
125
|
+
const kv = openKv(':project:');
|
|
126
|
+
const kvAdapter = new VersoriKVAdapter(kv);
|
|
127
|
+
const stateService = new StateService(logger); // logger is optional
|
|
128
|
+
|
|
129
|
+
// IMPORTANT: All StateService methods require 'kv' as first parameter
|
|
130
|
+
|
|
131
|
+
// Check if file processed (note: kv is first parameter)
|
|
132
|
+
const processed = await stateService.isFileProcessed(
|
|
133
|
+
kvAdapter,
|
|
134
|
+
'inventory-2025-01-15.csv',
|
|
135
|
+
'my-ingestion'
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (!processed) {
|
|
139
|
+
// Process file
|
|
140
|
+
const result = await processFile();
|
|
141
|
+
|
|
142
|
+
// Update sync state with processed file metadata
|
|
143
|
+
await stateService.updateSyncState(
|
|
144
|
+
kvAdapter,
|
|
145
|
+
[
|
|
146
|
+
{
|
|
147
|
+
fileName: 'inventory-2025-01-15.csv',
|
|
148
|
+
lastModified: new Date().toISOString(),
|
|
149
|
+
recordCount: 1500,
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
'my-ingestion'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Job Caching for DAILY Strategy
|
|
158
|
+
|
|
159
|
+
The DAILY job strategy reuses the same job for all files processed in a day:
|
|
160
|
+
|
|
161
|
+
```mermaid
|
|
162
|
+
flowchart TD
|
|
163
|
+
START[Start Processing] --> CHECK{Daily Job<br/>Cached?}
|
|
164
|
+
|
|
165
|
+
CHECK -->|Yes| VALIDATE{Job Still<br/>Valid?}
|
|
166
|
+
CHECK -->|No| CREATE_NEW[Create New Job]
|
|
167
|
+
|
|
168
|
+
VALIDATE -->|Valid| USE_CACHED[Use Cached Job ID]
|
|
169
|
+
VALIDATE -->|Expired/Closed| CREATE_NEW
|
|
170
|
+
|
|
171
|
+
CREATE_NEW --> CACHE[Cache Job ID in State]
|
|
172
|
+
CACHE --> USE_NEW[Use New Job]
|
|
173
|
+
|
|
174
|
+
USE_CACHED --> SEND[Send Batches]
|
|
175
|
+
USE_NEW --> SEND
|
|
176
|
+
|
|
177
|
+
SEND --> DONE[Complete]
|
|
178
|
+
|
|
179
|
+
style CHECK fill:#e3f2fd
|
|
180
|
+
style CREATE_NEW fill:#fff3e0
|
|
181
|
+
style USE_CACHED fill:#e8f5e9
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**State Flow:**
|
|
185
|
+
|
|
186
|
+
```mermaid
|
|
187
|
+
sequenceDiagram
|
|
188
|
+
participant Orch as Orchestrator
|
|
189
|
+
participant State as StateService
|
|
190
|
+
participant KV as KVStorage
|
|
191
|
+
participant Fluent as FluentAPI
|
|
192
|
+
|
|
193
|
+
Orch->>State: getDailyJob(KV, 'ingestion')
|
|
194
|
+
State->>KV: get(jobKey)
|
|
195
|
+
KV-->>State: { jobId, expiresAt }
|
|
196
|
+
|
|
197
|
+
alt Job Exists and Valid
|
|
198
|
+
State-->>Orch: jobId
|
|
199
|
+
else Missing or Expired
|
|
200
|
+
Orch->>Fluent: Create new job
|
|
201
|
+
Fluent-->>Orch: job-456
|
|
202
|
+
Orch->>State: setDailyJob(KV, 'ingestion', 'job-456', 24)
|
|
203
|
+
State->>KV: set(jobKey, job)
|
|
204
|
+
end
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Example:**
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const stateService = new StateService(logger);
|
|
211
|
+
|
|
212
|
+
// Get cached daily job (kv is first parameter)
|
|
213
|
+
let dailyJob = await stateService.getDailyJob(kvAdapter, 'inventory-ingestion');
|
|
214
|
+
let jobId = dailyJob?.jobId;
|
|
215
|
+
|
|
216
|
+
if (!jobId) {
|
|
217
|
+
// Create new job
|
|
218
|
+
const job = await fluentClient.createJob({
|
|
219
|
+
name: `inventory-sync-${new Date().toISOString().split('T')[0]}`,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Cache for reuse (kv is first parameter)
|
|
223
|
+
await stateService.setDailyJob(kvAdapter, 'inventory-ingestion', job.id, 24);
|
|
224
|
+
jobId = job.id;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Use job for all batches today
|
|
228
|
+
await fluentClient.sendBatch(jobId, { entityType: 'INVENTORY', action: 'UPSERT', entities: data });
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Batch Counting for BATCHES_PER_JOB Strategy
|
|
232
|
+
|
|
233
|
+
Track batches per job to create a new job after N batches:
|
|
234
|
+
|
|
235
|
+
```mermaid
|
|
236
|
+
flowchart TD
|
|
237
|
+
START[Start Batch] --> GET_COUNT[Get Current Batch Count]
|
|
238
|
+
GET_COUNT --> CHECK{Count ≥<br/>Max Batches?}
|
|
239
|
+
|
|
240
|
+
CHECK -->|Yes| CREATE[Create New Job]
|
|
241
|
+
CHECK -->|No| USE[Use Current Job]
|
|
242
|
+
|
|
243
|
+
CREATE --> RESET[Reset Batch Count = 0]
|
|
244
|
+
RESET --> INCREMENT
|
|
245
|
+
|
|
246
|
+
USE --> INCREMENT[Increment Batch Count]
|
|
247
|
+
INCREMENT --> UPDATE[Update State]
|
|
248
|
+
UPDATE --> SEND[Send Batch]
|
|
249
|
+
SEND --> DONE[Complete]
|
|
250
|
+
|
|
251
|
+
style CHECK fill:#e3f2fd
|
|
252
|
+
style CREATE fill:#fff3e0
|
|
253
|
+
style INCREMENT fill:#e8f5e9
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Example:**
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
const MAX_BATCHES_PER_JOB = 10;
|
|
260
|
+
|
|
261
|
+
// Read current state (example tracking via your own key)
|
|
262
|
+
const dailyJob = await stateService.getDailyJob(kvAdapter, 'inventory-ingestion');
|
|
263
|
+
const currentCount = dailyJob?.batchCount ?? 0;
|
|
264
|
+
|
|
265
|
+
if (currentCount >= MAX_BATCHES_PER_JOB) {
|
|
266
|
+
const job = await fluentClient.createJob({ name: 'inventory-sync' });
|
|
267
|
+
await stateService.setDailyJob(kvAdapter, 'inventory-ingestion', job.id, 24);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
await fluentClient.sendBatch(dailyJob?.jobId || '', {
|
|
271
|
+
entityType: 'INVENTORY',
|
|
272
|
+
action: 'UPSERT',
|
|
273
|
+
entities: data,
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Distributed Locking
|
|
278
|
+
|
|
279
|
+
Prevent concurrent workflow executions from processing the same files:
|
|
280
|
+
|
|
281
|
+
```mermaid
|
|
282
|
+
sequenceDiagram
|
|
283
|
+
participant W1 as Workflow 1
|
|
284
|
+
participant W2 as Workflow 2
|
|
285
|
+
participant State as StateService
|
|
286
|
+
participant KV as KVStorage
|
|
287
|
+
|
|
288
|
+
par Concurrent Execution
|
|
289
|
+
W1->>State: acquireLock('file1.csv', kv, 15)
|
|
290
|
+
W2->>State: acquireLock('file1.csv', kv, 15)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
State->>KV: get('lock:file1.csv')
|
|
294
|
+
KV-->>State: null (no lock)
|
|
295
|
+
|
|
296
|
+
State->>KV: set('lock:file1.csv', { owner: 'W1', timestamp })
|
|
297
|
+
KV-->>State: Lock acquired
|
|
298
|
+
|
|
299
|
+
State-->>W1: Lock acquired (process file)
|
|
300
|
+
State-->>W2: Lock already held (skip file)
|
|
301
|
+
|
|
302
|
+
W1->>W1: Process file1.csv
|
|
303
|
+
W1->>State: releaseLock('file1.csv', kv)
|
|
304
|
+
State->>KV: delete('lock:file1.csv')
|
|
305
|
+
KV-->>State: Lock released
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Stale Lock Detection:**
|
|
309
|
+
|
|
310
|
+
If a workflow crashes while holding a lock, the lock becomes stale:
|
|
311
|
+
|
|
312
|
+
```mermaid
|
|
313
|
+
flowchart TD
|
|
314
|
+
TRY[Try Acquire Lock] --> EXISTS{Lock<br/>Exists?}
|
|
315
|
+
|
|
316
|
+
EXISTS -->|No| ACQUIRE[Acquire Lock]
|
|
317
|
+
EXISTS -->|Yes| CHECK_TIME{Lock Age > 30 min?}
|
|
318
|
+
|
|
319
|
+
CHECK_TIME -->|Yes| STALE[Lock is Stale]
|
|
320
|
+
CHECK_TIME -->|No| HELD[Lock Held by Other Process]
|
|
321
|
+
|
|
322
|
+
STALE --> OVERRIDE[Override Stale Lock]
|
|
323
|
+
OVERRIDE --> ACQUIRE
|
|
324
|
+
|
|
325
|
+
ACQUIRE --> SUCCESS[Lock Acquired]
|
|
326
|
+
HELD --> FAIL[Lock Failed]
|
|
327
|
+
|
|
328
|
+
style ACQUIRE fill:#e8f5e9
|
|
329
|
+
style STALE fill:#fff3e0
|
|
330
|
+
style FAIL fill:#ffebee
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Example:**
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
const stateService = new StateService(logger);
|
|
337
|
+
|
|
338
|
+
// Acquire lock (kv is first parameter)
|
|
339
|
+
const acquired = await stateService.acquireLock('file1.csv', kvAdapter, 15);
|
|
340
|
+
|
|
341
|
+
if (acquired) {
|
|
342
|
+
try {
|
|
343
|
+
// Process file
|
|
344
|
+
await processFile();
|
|
345
|
+
} finally {
|
|
346
|
+
// Always release lock
|
|
347
|
+
await stateService.releaseLock('file1.csv', kvAdapter);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## State Cleanup and Maintenance
|
|
353
|
+
|
|
354
|
+
```mermaid
|
|
355
|
+
flowchart TD
|
|
356
|
+
START[Maintenance Job] --> GET[Get Current State]
|
|
357
|
+
GET --> FILTER[Filter Processed Files]
|
|
358
|
+
|
|
359
|
+
FILTER --> OLD{Files Older<br/>Than 30 Days?}
|
|
360
|
+
|
|
361
|
+
OLD -->|Yes| REMOVE[Remove from Array]
|
|
362
|
+
OLD -->|No| KEEP[Keep in Array]
|
|
363
|
+
|
|
364
|
+
REMOVE --> UPDATE[Update State]
|
|
365
|
+
KEEP --> UPDATE
|
|
366
|
+
|
|
367
|
+
UPDATE --> CHECK_JOB{Daily Job<br/>Still Valid?}
|
|
368
|
+
|
|
369
|
+
CHECK_JOB -->|Expired| CLEAR_JOB[Clear dailyJobId]
|
|
370
|
+
CHECK_JOB -->|Valid| SKIP
|
|
371
|
+
|
|
372
|
+
CLEAR_JOB --> SAVE[Save State]
|
|
373
|
+
SKIP --> SAVE
|
|
374
|
+
|
|
375
|
+
SAVE --> DONE[Complete]
|
|
376
|
+
|
|
377
|
+
style REMOVE fill:#fff3e0
|
|
378
|
+
style CLEAR_JOB fill:#fff3e0
|
|
379
|
+
style SAVE fill:#e8f5e9
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Example Cleanup:**
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
async function cleanupOldEntries() {
|
|
386
|
+
// Get sync state (kv is first parameter)
|
|
387
|
+
const state = await stateService.getSyncState(kvAdapter, 'my-workflow');
|
|
388
|
+
|
|
389
|
+
// Note: File tracking uses individual file keys, not an array
|
|
390
|
+
// This example shows conceptual cleanup - actual implementation
|
|
391
|
+
// would need to list and delete individual file keys
|
|
392
|
+
|
|
393
|
+
logger.info('Current sync state', {
|
|
394
|
+
lastProcessedFile: state.lastProcessedFile,
|
|
395
|
+
lastProcessedTimestamp: state.lastProcessedTimestamp,
|
|
396
|
+
totalRecords: state.lastProcessedCount,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## KV Adapter Interface
|
|
402
|
+
|
|
403
|
+
The SDK defines a KV adapter interface for pluggable storage:
|
|
404
|
+
|
|
405
|
+
```mermaid
|
|
406
|
+
classDiagram
|
|
407
|
+
class KVStorageAdapter {
|
|
408
|
+
<<interface>>
|
|
409
|
+
+get(key: string) Promise~any~
|
|
410
|
+
+set(key: string, value: any) Promise~void~
|
|
411
|
+
+delete(key: string) Promise~void~
|
|
412
|
+
+list(prefix?: string) Promise~string[]~
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
class VersoriKVAdapter {
|
|
416
|
+
-kv: KV
|
|
417
|
+
+get(key: string) Promise~any~
|
|
418
|
+
+set(key: string, value: any) Promise~void~
|
|
419
|
+
+delete(key: string) Promise~void~
|
|
420
|
+
+list(prefix?: string) Promise~string[]~
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
class InMemoryKVAdapter {
|
|
424
|
+
-storage: Map
|
|
425
|
+
+get(key: string) Promise~any~
|
|
426
|
+
+set(key: string, value: any) Promise~void~
|
|
427
|
+
+delete(key: string) Promise~void~
|
|
428
|
+
+list(prefix?: string) Promise~string[]~
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
class CustomKVAdapter {
|
|
432
|
+
-client: any
|
|
433
|
+
+get(key: string) Promise~any~
|
|
434
|
+
+set(key: string, value: any) Promise~void~
|
|
435
|
+
+delete(key: string) Promise~void~
|
|
436
|
+
+list(prefix?: string) Promise~string[]~
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
KVStorageAdapter <|.. VersoriKVAdapter
|
|
440
|
+
KVStorageAdapter <|.. InMemoryKVAdapter
|
|
441
|
+
KVStorageAdapter <|.. CustomKVAdapter
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Implementing Custom Adapter:**
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
import { KVStorageAdapter } from '@fluentcommerce/fc-connect-sdk';
|
|
448
|
+
|
|
449
|
+
class RedisKVAdapter implements KVStorageAdapter {
|
|
450
|
+
constructor(private redis: RedisClient) {}
|
|
451
|
+
|
|
452
|
+
async get(key: string): Promise<any> {
|
|
453
|
+
const value = await this.redis.get(key);
|
|
454
|
+
return value ? JSON.parse(value) : null;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async set(key: string, value: any): Promise<void> {
|
|
458
|
+
await this.redis.set(key, JSON.stringify(value));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async delete(key: string): Promise<void> {
|
|
462
|
+
await this.redis.del(key);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async list(prefix?: string): Promise<string[]> {
|
|
466
|
+
const pattern = prefix ? `${prefix}*` : '*';
|
|
467
|
+
return await this.redis.keys(pattern);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Use custom adapter
|
|
472
|
+
const kvAdapter = new RedisKVAdapter(redisClient);
|
|
473
|
+
const stateService = new StateService(logger);
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
## State Versioning
|
|
477
|
+
|
|
478
|
+
Handle state schema evolution gracefully:
|
|
479
|
+
|
|
480
|
+
```mermaid
|
|
481
|
+
flowchart TD
|
|
482
|
+
READ[Read State from KV] --> CHECK{Has Version?}
|
|
483
|
+
|
|
484
|
+
CHECK -->|No| V1[Assume Version 1]
|
|
485
|
+
CHECK -->|Yes| VERSION{Which<br/>Version?}
|
|
486
|
+
|
|
487
|
+
VERSION -->|v1| MIGRATE_V2[Migrate v1 → v2]
|
|
488
|
+
VERSION -->|v2| MIGRATE_V3[Migrate v2 → v3]
|
|
489
|
+
VERSION -->|v3| CURRENT[Use Current Schema]
|
|
490
|
+
|
|
491
|
+
MIGRATE_V2 --> MIGRATE_V3
|
|
492
|
+
V1 --> MIGRATE_V2
|
|
493
|
+
|
|
494
|
+
MIGRATE_V3 --> CURRENT
|
|
495
|
+
CURRENT --> USE[Use State]
|
|
496
|
+
|
|
497
|
+
USE --> WRITE[Write with Current Version]
|
|
498
|
+
|
|
499
|
+
style MIGRATE_V2 fill:#fff3e0
|
|
500
|
+
style MIGRATE_V3 fill:#fff3e0
|
|
501
|
+
style CURRENT fill:#e8f5e9
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Example Migration:**
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
interface StateV1 {
|
|
508
|
+
processedFiles: string[]; // Just file keys
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
interface StateV2 {
|
|
512
|
+
version: 2;
|
|
513
|
+
processedFiles: ProcessedFileEntry[]; // Full metadata
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async function migrateState(state: any): Promise<StateV2> {
|
|
517
|
+
if (!state.version) {
|
|
518
|
+
// Migrate v1 to v2
|
|
519
|
+
return {
|
|
520
|
+
version: 2,
|
|
521
|
+
processedFiles: state.processedFiles.map((key: string) => ({
|
|
522
|
+
key,
|
|
523
|
+
timestamp: new Date().toISOString(),
|
|
524
|
+
})),
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return state;
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
## Performance Considerations
|
|
533
|
+
|
|
534
|
+
```mermaid
|
|
535
|
+
graph TB
|
|
536
|
+
PERF[Performance Optimizations]
|
|
537
|
+
|
|
538
|
+
PERF --> BATCH_OPS[Batch KV Operations]
|
|
539
|
+
PERF --> CACHE[In-memory Caching]
|
|
540
|
+
PERF --> COMPRESS[Compress Large States]
|
|
541
|
+
PERF --> PRUNE[Prune Old Entries]
|
|
542
|
+
|
|
543
|
+
BATCH_OPS --> READ[Batch Reads]
|
|
544
|
+
BATCH_OPS --> WRITE[Batch Writes]
|
|
545
|
+
|
|
546
|
+
CACHE --> TTL[Time-based TTL]
|
|
547
|
+
CACHE --> INVALIDATE[Smart Invalidation]
|
|
548
|
+
|
|
549
|
+
COMPRESS --> GZIP[GZIP Compression]
|
|
550
|
+
COMPRESS --> THRESHOLD[Only if > 1MB]
|
|
551
|
+
|
|
552
|
+
PRUNE --> SCHEDULE[Scheduled Cleanup]
|
|
553
|
+
PRUNE --> LIMIT[Max 10k Entries]
|
|
554
|
+
|
|
555
|
+
style PERF fill:#e3f2fd
|
|
556
|
+
style BATCH_OPS fill:#fff3e0
|
|
557
|
+
style CACHE fill:#f3e5f5
|
|
558
|
+
style COMPRESS fill:#e8f5e9
|
|
559
|
+
style PRUNE fill:#e1f5ff
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
## Best Practices
|
|
563
|
+
|
|
564
|
+
### 1. Namespace State Keys
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
// Good - namespaced with logger
|
|
568
|
+
const stateService = new StateService(logger); // logger is optional
|
|
569
|
+
const namespace = 'inventory-ingestion';
|
|
570
|
+
|
|
571
|
+
// Use workflowId parameter to scope state
|
|
572
|
+
await stateService.isFileProcessed(kvAdapter, 'file.csv', namespace);
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### 2. Handle State Corruption
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
// Implement your own backup/fallback strategy using your KV implementation
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### 3. Monitor State Size
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
// Implement size checks using your KV implementation if listing is supported
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### 4. Test with Mocks
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
import { StateService } from '@fluentcommerce/fc-connect-sdk';
|
|
591
|
+
|
|
592
|
+
describe('Ingestion with State', () => {
|
|
593
|
+
it('should skip processed files', async () => {
|
|
594
|
+
// Mock KV adapter for testing
|
|
595
|
+
const mockKV = {
|
|
596
|
+
get: jest.fn(),
|
|
597
|
+
set: jest.fn(),
|
|
598
|
+
delete: jest.fn(),
|
|
599
|
+
atomic: jest.fn()
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
const stateService = new StateService(); // no logger for tests
|
|
603
|
+
|
|
604
|
+
// Pre-populate state
|
|
605
|
+
await stateService.updateSyncState(mockKV, [{
|
|
606
|
+
fileName: 'file1.csv',
|
|
607
|
+
lastModified: new Date().toISOString(),
|
|
608
|
+
}]);
|
|
609
|
+
|
|
610
|
+
// Test deduplication (kv is first parameter)
|
|
611
|
+
const processed = await stateService.isFileProcessed(mockKV, 'file1.csv');
|
|
612
|
+
expect(processed).toBe(true);
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
## Monitoring and Debugging
|
|
618
|
+
|
|
619
|
+
### State Inspection
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
async function inspectState() {
|
|
623
|
+
// Get sync state (kv is first parameter)
|
|
624
|
+
const state = await stateService.getSyncState(kvAdapter, 'my-workflow');
|
|
625
|
+
|
|
626
|
+
console.log('State Summary:');
|
|
627
|
+
console.log('- Last processed file:', state.lastProcessedFile);
|
|
628
|
+
console.log('- Last processed timestamp:', state.lastProcessedTimestamp);
|
|
629
|
+
console.log('- Total records:', state.lastProcessedCount);
|
|
630
|
+
console.log('- Initialized:', state.isInitialized);
|
|
631
|
+
console.log('- Last sync result:', state.lastSyncResult);
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### State Reset (Emergency)
|
|
636
|
+
|
|
637
|
+
```typescript
|
|
638
|
+
async function resetState() {
|
|
639
|
+
logger.warn('Resetting state - all processed files will be forgotten');
|
|
640
|
+
|
|
641
|
+
// Clear state for workflow (kv is first parameter)
|
|
642
|
+
await stateService.clearState(kvAdapter, 'my-workflow');
|
|
643
|
+
|
|
644
|
+
logger.info('State reset complete');
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
## Next Steps
|
|
649
|
+
|
|
650
|
+
- [Overview](./architecture-01-overview.md) - Architecture overview
|
|
651
|
+
- [Client Architecture](./architecture-02-client-architecture.md) - Client layer
|
|
652
|
+
- [Data Flow](./architecture-03-data-flow.md) - Data processing patterns
|
|
653
|
+
- [Getting Started](../../00-START-HERE/getting-started.md) - Start building
|