@fluentcommerce/fc-connect-sdk 0.1.53 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -2
- package/README.md +39 -0
- package/dist/cjs/auth/index.d.ts +3 -0
- package/dist/cjs/auth/index.js +13 -0
- package/dist/cjs/auth/profile-loader.d.ts +18 -0
- package/dist/cjs/auth/profile-loader.js +208 -0
- package/dist/cjs/client-factory.d.ts +4 -0
- package/dist/cjs/client-factory.js +10 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/auth/index.d.ts +3 -0
- package/dist/esm/auth/index.js +2 -0
- package/dist/esm/auth/profile-loader.d.ts +18 -0
- package/dist/esm/auth/profile-loader.js +169 -0
- package/dist/esm/client-factory.d.ts +4 -0
- package/dist/esm/client-factory.js +9 -0
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/auth/index.d.ts +3 -0
- package/dist/types/auth/profile-loader.d.ts +18 -0
- package/dist/types/client-factory.d.ts +4 -0
- package/dist/types/index.d.ts +3 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -482
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
|
@@ -1,1083 +1,1083 @@
|
|
|
1
|
-
# Module 06: Data Sources
|
|
2
|
-
|
|
3
|
-
**Level:** Intermediate
|
|
4
|
-
**Category:** Data Integration
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
Data sources provide unified interfaces for reading and writing data from different storage systems (S3, SFTP, etc.). They handle connection management, file operations, format conversions, and error handling, allowing you to work with multiple data sources through a consistent API.
|
|
9
|
-
|
|
10
|
-
## Architecture
|
|
11
|
-
|
|
12
|
-
All data sources extend `AbstractDataSource`, which provides:
|
|
13
|
-
|
|
14
|
-
**Required Methods (must implement):**
|
|
15
|
-
- `listFiles()` - List files with filtering
|
|
16
|
-
- `downloadFile()` - Download file content
|
|
17
|
-
- `uploadFile()` - Upload file content (⚠️ **mandatory**)
|
|
18
|
-
- `deleteFile()` - Delete a file
|
|
19
|
-
- `copyFileInternal()` - Internal copy implementation
|
|
20
|
-
- `validateConnection()` - Test connectivity
|
|
21
|
-
|
|
22
|
-
**Template Methods (inherited):**
|
|
23
|
-
- `moveFile()` - Move file using copyFileInternal() + deleteFile()
|
|
24
|
-
- `archiveFile()` - Archive file to timestamped location using moveFile()
|
|
25
|
-
|
|
26
|
-
Both S3DataSource and SftpDataSource implement all required methods and inherit the template methods. For advanced use cases (e.g., cross-bucket S3 operations), use `copyFile()` directly.
|
|
27
|
-
|
|
28
|
-
## Table of Contents
|
|
29
|
-
|
|
30
|
-
- [S3 Data Source](#s3-data-source)
|
|
31
|
-
- [Constructor](#constructor)
|
|
32
|
-
- [File Listing](#file-listing)
|
|
33
|
-
- [File Download](#file-download)
|
|
34
|
-
- [File Upload](#file-upload)
|
|
35
|
-
- [File Deletion](#file-deletion)
|
|
36
|
-
- [File Copy](#file-copy)
|
|
37
|
-
- [File Move](#file-move)
|
|
38
|
-
- [Connection Validation](#connection-validation)
|
|
39
|
-
- [Writing Parquet Files](#writing-parquet-files)
|
|
40
|
-
- [SFTP Data Source](#sftp-data-source)
|
|
41
|
-
- [Constructor](#sftp-constructor)
|
|
42
|
-
- [Configuration Types](#configuration-types)
|
|
43
|
-
- [File Listing](#sftp-file-listing)
|
|
44
|
-
- [File Download](#sftp-file-download)
|
|
45
|
-
- [File Existence Checks](#file-existence-checks)
|
|
46
|
-
- [File Upload](#sftp-file-upload)
|
|
47
|
-
- [Directory Operations](#directory-operations)
|
|
48
|
-
- [File Deletion](#sftp-file-deletion)
|
|
49
|
-
- [File Move](#file-move-atomic)
|
|
50
|
-
- [File Copy](#sftp-file-copy)
|
|
51
|
-
- [Multi-Format Support](#multi-format-support)
|
|
52
|
-
- [Error Handling](#error-handling)
|
|
53
|
-
- [Connection Management](#connection-management)
|
|
54
|
-
- [Complete Methods Reference](#complete-methods-reference)
|
|
55
|
-
- [See Also](#see-also)
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## S3 Data Source
|
|
60
|
-
|
|
61
|
-
Read and write files from Amazon S3 with presigned URLs.
|
|
62
|
-
|
|
63
|
-
### Constructor
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import { S3DataSource } from '@fluentcommerce/fc-connect-sdk';
|
|
67
|
-
|
|
68
|
-
const s3Config: S3DataSourceConfig = {
|
|
69
|
-
type: 'S3_CSV',
|
|
70
|
-
connectionId: 's3-api-ref',
|
|
71
|
-
name: 'S3 API Reference',
|
|
72
|
-
s3Config: {
|
|
73
|
-
bucket: 'my-bucket',
|
|
74
|
-
region: 'us-east-1',
|
|
75
|
-
accessKeyId: 'your-access-key',
|
|
76
|
-
secretAccessKey: 'your-secret-key',
|
|
77
|
-
sessionToken: 'optional-session-token', // Optional for temporary credentials
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const s3 = new S3DataSource(s3Config, logger);
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Configuration Notes:**
|
|
85
|
-
|
|
86
|
-
`S3DataSourceConfig` extends `DataSourceConfig`, which includes:
|
|
87
|
-
|
|
88
|
-
- `type: string` - Data source type ('S3_CSV')
|
|
89
|
-
- `connectionId?: string` - Optional connection identifier
|
|
90
|
-
- `name?: string` - Optional descriptive name
|
|
91
|
-
- `connection?: any` - Optional Versori platform connection object (for Versori integration)
|
|
92
|
-
|
|
93
|
-
For **standalone use** (without Versori), only provide `type` and `s3Config`.
|
|
94
|
-
For **Versori platform integration**, also provide `connection`, `connectionId`, and `name`.
|
|
95
|
-
|
|
96
|
-
### File Listing
|
|
97
|
-
|
|
98
|
-
**listFiles(params?)** - List objects in S3 bucket with filtering options
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
// List all files in bucket
|
|
102
|
-
const files = await s3.listFiles();
|
|
103
|
-
|
|
104
|
-
// List files with prefix (folder)
|
|
105
|
-
const files = await s3.listFiles({
|
|
106
|
-
prefix: 'inventory/',
|
|
107
|
-
maxKeys: 100,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// List files with delimiter (folder separator)
|
|
111
|
-
const files = await s3.listFiles({
|
|
112
|
-
prefix: 'inventory/',
|
|
113
|
-
delimiter: '/',
|
|
114
|
-
maxKeys: 1000,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// Returns: FileMetadata[]
|
|
118
|
-
// [
|
|
119
|
-
// {
|
|
120
|
-
// path: 'inventory/data.csv',
|
|
121
|
-
// name: 'data.csv',
|
|
122
|
-
// size: 2048,
|
|
123
|
-
// lastModified: '2025-01-15T10:30:00Z',
|
|
124
|
-
// contentType: 'text/csv',
|
|
125
|
-
// etag: '"abc123"',
|
|
126
|
-
// bucket: 'my-bucket',
|
|
127
|
-
// region: 'us-east-1',
|
|
128
|
-
// source: 'S3'
|
|
129
|
-
// }
|
|
130
|
-
// ]
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
**Parameters:**
|
|
134
|
-
|
|
135
|
-
- `prefix?: string` - Filter by object key prefix (e.g., 'folder/')
|
|
136
|
-
- `delimiter?: string` - Delimiter for folder structure (typically '/')
|
|
137
|
-
- `maxKeys?: number` - Maximum number of keys to return (default: 1000)
|
|
138
|
-
- `continuationToken?: string` - Token for paginated results
|
|
139
|
-
|
|
140
|
-
**Note:** S3 does NOT support wildcard pattern matching. Use prefix + manual filtering:
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
// Get all CSV files in folder
|
|
144
|
-
const files = await s3.listFiles({ prefix: 'inventory/' });
|
|
145
|
-
|
|
146
|
-
// IMPORTANT: Use .endsWith('.csv') NOT .endsWith('*.csv')
|
|
147
|
-
// The asterisk is a glob pattern character, not part of the file extension
|
|
148
|
-
const csvFiles = files.filter(f => f.name.endsWith('.csv')); // ✓ Correct
|
|
149
|
-
|
|
150
|
-
// Common mistake to avoid:
|
|
151
|
-
// const csvFiles = files.filter(f => f.name.endsWith('*.csv')); // ✗ WRONG - Never matches!
|
|
152
|
-
|
|
153
|
-
// Get files matching pattern
|
|
154
|
-
const productFiles = files.filter(f => f.name.startsWith('products_'));
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### File Download
|
|
158
|
-
|
|
159
|
-
**downloadFile(key, options?)** - Download file content from S3
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
// Download as text (default UTF-8)
|
|
163
|
-
const csvContent = await s3.downloadFile('inventory/data.csv');
|
|
164
|
-
// Returns: string
|
|
165
|
-
|
|
166
|
-
// Download as binary (for images, Parquet, etc.)
|
|
167
|
-
const parquetBuffer = await s3.downloadFile('exports/data.parquet', {
|
|
168
|
-
encoding: 'binary',
|
|
169
|
-
});
|
|
170
|
-
// Returns: Buffer
|
|
171
|
-
|
|
172
|
-
// Download with custom response headers
|
|
173
|
-
const content = await s3.downloadFile('data/file.csv', {
|
|
174
|
-
responseHeaders: {
|
|
175
|
-
'Cache-Control': 'no-cache',
|
|
176
|
-
},
|
|
177
|
-
});
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Parameters:**
|
|
181
|
-
|
|
182
|
-
- `key: string` - S3 object key (path)
|
|
183
|
-
- `options.encoding?: 'utf8' | 'binary'` - Encoding format (default: 'utf8')
|
|
184
|
-
- `options.responseHeaders?: Record<string, string>` - Custom response headers
|
|
185
|
-
|
|
186
|
-
**Returns:**
|
|
187
|
-
|
|
188
|
-
- `Promise<string | Buffer>` - File content as string or Buffer
|
|
189
|
-
|
|
190
|
-
### File Upload
|
|
191
|
-
|
|
192
|
-
**uploadFile(key, content, options?)** - Upload file content to S3
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
// Upload text content
|
|
196
|
-
await s3.uploadFile('output/results.csv', csvContent, {
|
|
197
|
-
contentType: 'text/csv',
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// Upload binary content (Buffer)
|
|
201
|
-
const parquetBuffer = await s3.writeParquetContent(records);
|
|
202
|
-
await s3.uploadFile('exports/data.parquet', parquetBuffer, {
|
|
203
|
-
contentType: 'application/octet-stream',
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// Upload with metadata
|
|
207
|
-
await s3.uploadFile('data/inventory.json', jsonContent, {
|
|
208
|
-
contentType: 'application/json',
|
|
209
|
-
metadata: {
|
|
210
|
-
'upload-date': new Date().toISOString(),
|
|
211
|
-
source: 'fluent-commerce',
|
|
212
|
-
'record-count': '1000',
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
**Parameters:**
|
|
218
|
-
|
|
219
|
-
- `key: string` - Destination S3 object key
|
|
220
|
-
- `content: string | Buffer` - File content to upload
|
|
221
|
-
- `options.contentType?: string` - MIME type (default: 'application/octet-stream')
|
|
222
|
-
- `options.metadata?: Record<string, string>` - Custom metadata headers
|
|
223
|
-
|
|
224
|
-
### File Deletion
|
|
225
|
-
|
|
226
|
-
**deleteFile(key)** - Delete object from S3
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
// Delete single file
|
|
230
|
-
await s3.deleteFile('old-data/obsolete.csv');
|
|
231
|
-
|
|
232
|
-
// Delete with error handling
|
|
233
|
-
try {
|
|
234
|
-
await s3.deleteFile('temp/file.csv');
|
|
235
|
-
console.log('File deleted successfully');
|
|
236
|
-
} catch (error) {
|
|
237
|
-
if (error.code === 'NoSuchKey') {
|
|
238
|
-
console.log('File does not exist');
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
**Parameters:**
|
|
244
|
-
|
|
245
|
-
- `key: string` - S3 object key to delete
|
|
246
|
-
|
|
247
|
-
**Note:** Delete succeeds even if file doesn't exist (idempotent)
|
|
248
|
-
|
|
249
|
-
### File Copy
|
|
250
|
-
|
|
251
|
-
**copyFile(sourceKey, destKey, options?)** - Copy object within or across buckets
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
// Copy within same bucket
|
|
255
|
-
await s3.copyFile('data/file.csv', 'archive/file.csv');
|
|
256
|
-
|
|
257
|
-
// Copy from different bucket
|
|
258
|
-
await s3.copyFile('original.csv', 'backup/copy.csv', {
|
|
259
|
-
sourceBucket: 'source-bucket',
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// Copy with metadata update
|
|
263
|
-
await s3.copyFile('data/file.csv', 'processed/file.csv', {
|
|
264
|
-
metadata: {
|
|
265
|
-
'processed-date': new Date().toISOString(),
|
|
266
|
-
status: 'completed',
|
|
267
|
-
},
|
|
268
|
-
});
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
**Parameters:**
|
|
272
|
-
|
|
273
|
-
- `sourceKey: string` - Source object key
|
|
274
|
-
- `destKey: string` - Destination object key
|
|
275
|
-
- `options.sourceBucket?: string` - Source bucket (defaults to current bucket)
|
|
276
|
-
- `options.metadata?: Record<string, string>` - Metadata for destination object
|
|
277
|
-
|
|
278
|
-
### File Move
|
|
279
|
-
|
|
280
|
-
**moveFile(sourcePath, destPath, deleteSource?)** - Move object within same bucket (template method from AbstractDataSource)
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
// Move within same bucket
|
|
284
|
-
await s3.moveFile('temp/processing.csv', 'archive/completed.csv');
|
|
285
|
-
|
|
286
|
-
// Copy without deleting source
|
|
287
|
-
await s3.moveFile('data/file.csv', 'backup/file.csv', false);
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**Parameters:**
|
|
291
|
-
|
|
292
|
-
- `sourcePath: string` - Source object key
|
|
293
|
-
- `destPath: string` - Destination object key
|
|
294
|
-
- `deleteSource?: boolean` - Delete source after copy (default: true)
|
|
295
|
-
|
|
296
|
-
**Returns:** `Promise<void>`
|
|
297
|
-
|
|
298
|
-
**Important Notes:**
|
|
299
|
-
- S3 moveFile() is NOT atomic - it performs copy then delete. If delete fails, you'll have duplicate files.
|
|
300
|
-
- **Same-bucket only:** This method only works within the same bucket.
|
|
301
|
-
- **Cross-bucket moves:** For moving files between different S3 buckets, use `copyFile()` and `deleteFile()` directly.
|
|
302
|
-
|
|
303
|
-
**Cross-Bucket Move Example:**
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
// For cross-bucket operations, use copyFile() + deleteFile() directly
|
|
307
|
-
await s3.copyFile('source.csv', 'archive/source.csv', {
|
|
308
|
-
sourceBucket: 'source-bucket',
|
|
309
|
-
});
|
|
310
|
-
await s3.deleteFile('source.csv'); // Deletes from current bucket
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### File Archive
|
|
314
|
-
|
|
315
|
-
**archiveFile(sourcePath, archivePrefix?)** - Archive file with timestamp (template method from AbstractDataSource)
|
|
316
|
-
|
|
317
|
-
```typescript
|
|
318
|
-
// Archive to default 'archive/' prefix
|
|
319
|
-
const archivePath = await s3.archiveFile('data/inventory.csv');
|
|
320
|
-
// Returns: 'archive/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
321
|
-
|
|
322
|
-
// Archive to custom prefix
|
|
323
|
-
const archivePath = await s3.archiveFile('data/inventory.csv', 'backup/2025/');
|
|
324
|
-
// Returns: 'backup/2025/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
**Parameters:**
|
|
328
|
-
|
|
329
|
-
- `sourcePath: string` - Source object key
|
|
330
|
-
- `archivePrefix?: string` - Archive directory prefix (default: 'archive/')
|
|
331
|
-
|
|
332
|
-
**Returns:** `Promise<string>` - The archive path where file was moved
|
|
333
|
-
|
|
334
|
-
**How It Works:**
|
|
335
|
-
1. Generates timestamped filename: `{archivePrefix}{timestamp}_{originalFilename}`
|
|
336
|
-
2. Moves file to archive location using moveFile()
|
|
337
|
-
3. Returns the full archive path
|
|
338
|
-
|
|
339
|
-
### Connection Validation
|
|
340
|
-
|
|
341
|
-
**validateConnection()** - Test S3 bucket access
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
const isValid = await s3.validateConnection();
|
|
345
|
-
if (!isValid) {
|
|
346
|
-
console.error('Cannot access S3 bucket');
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### Writing Parquet Files
|
|
351
|
-
|
|
352
|
-
Both S3 and SFTP data sources support writing data records as Parquet format with automatic schema inference.
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
import { S3DataSource } from '@fluentcommerce/fc-connect-sdk';
|
|
356
|
-
|
|
357
|
-
const s3 = new S3DataSource(
|
|
358
|
-
{
|
|
359
|
-
type: 'S3_PARQUET',
|
|
360
|
-
connectionId: 's3-parquet-write',
|
|
361
|
-
name: 'S3 Parquet Write',
|
|
362
|
-
s3Config: config.s3Config,
|
|
363
|
-
},
|
|
364
|
-
logger
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
// Prepare data records
|
|
368
|
-
const records = [
|
|
369
|
-
{
|
|
370
|
-
id: 1,
|
|
371
|
-
name: 'Product A',
|
|
372
|
-
qty: 100,
|
|
373
|
-
price: 19.99,
|
|
374
|
-
active: true,
|
|
375
|
-
updatedAt: new Date(),
|
|
376
|
-
},
|
|
377
|
-
{
|
|
378
|
-
id: 2,
|
|
379
|
-
name: 'Product B',
|
|
380
|
-
qty: 50,
|
|
381
|
-
price: 29.99,
|
|
382
|
-
active: true,
|
|
383
|
-
updatedAt: new Date(),
|
|
384
|
-
},
|
|
385
|
-
];
|
|
386
|
-
|
|
387
|
-
// Write Parquet content with GZIP compression
|
|
388
|
-
const parquetBuffer = await s3.writeParquetContent(records, {
|
|
389
|
-
compression: 'GZIP',
|
|
390
|
-
rowGroupSize: 50000,
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
// Upload to S3
|
|
394
|
-
await s3.uploadFile('output/inventory.parquet', parquetBuffer, {
|
|
395
|
-
contentType: 'application/octet-stream',
|
|
396
|
-
});
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
**ParquetWriteOptions:**
|
|
400
|
-
|
|
401
|
-
```typescript
|
|
402
|
-
interface ParquetWriteOptions {
|
|
403
|
-
compression?: 'UNCOMPRESSED' | 'GZIP' | 'SNAPPY' | 'LZO' | 'BROTLI';
|
|
404
|
-
schema?: Record<string, any>; // Custom schema, auto-infers if not provided
|
|
405
|
-
rowGroupSize?: number; // Default: 50000
|
|
406
|
-
}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**Automatic Schema Inference:**
|
|
410
|
-
|
|
411
|
-
The SDK automatically infers Parquet schema from your data types:
|
|
412
|
-
|
|
413
|
-
| JavaScript Type | Parquet Type |
|
|
414
|
-
| ------------------ | ------------------------- |
|
|
415
|
-
| `string` | UTF8 |
|
|
416
|
-
| `number` (integer) | INT64 |
|
|
417
|
-
| `number` (float) | DOUBLE |
|
|
418
|
-
| `boolean` | BOOLEAN |
|
|
419
|
-
| `Date` | TIMESTAMP_MILLIS |
|
|
420
|
-
| `null/undefined` | UTF8 (optional) |
|
|
421
|
-
| `object` | UTF8 (serialized as JSON) |
|
|
422
|
-
|
|
423
|
-
**Custom Schema Example:**
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
// Define custom schema for precise control
|
|
427
|
-
const customSchema = {
|
|
428
|
-
productRef: { type: 'UTF8' },
|
|
429
|
-
qty: { type: 'INT32' },
|
|
430
|
-
price: { type: 'DECIMAL', precision: 10, scale: 2 },
|
|
431
|
-
locationRef: { type: 'UTF8' },
|
|
432
|
-
updatedAt: { type: 'TIMESTAMP_MILLIS' },
|
|
433
|
-
active: { type: 'BOOLEAN', optional: true },
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
const buffer = await s3.writeParquetContent(records, {
|
|
437
|
-
schema: customSchema,
|
|
438
|
-
compression: 'SNAPPY',
|
|
439
|
-
});
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
**Compression Options:**
|
|
443
|
-
|
|
444
|
-
- **UNCOMPRESSED**: No compression, fastest write, largest file
|
|
445
|
-
- **GZIP**: Good compression ratio, slower, widely compatible
|
|
446
|
-
- **SNAPPY**: Fast compression, good for large files
|
|
447
|
-
- **LZO**: Fast compression (requires native library)
|
|
448
|
-
- **BROTLI**: Best compression ratio, slower
|
|
449
|
-
|
|
450
|
-
**Complete Workflow Example:**
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
import {
|
|
454
|
-
S3DataSource,
|
|
455
|
-
generateFileName,
|
|
456
|
-
generateFilePath,
|
|
457
|
-
generateDateSubdirectories,
|
|
458
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
459
|
-
|
|
460
|
-
// Fetch data from Fluent Commerce
|
|
461
|
-
const inventory = await client.graphql({
|
|
462
|
-
query: `query { inventoryPositions(first: 1000) { ... } }`,
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
// Transform to records
|
|
466
|
-
const records = inventory.data.inventoryPositions.edges.map(e => ({
|
|
467
|
-
productRef: e.node.productRef,
|
|
468
|
-
locationRef: e.node.locationRef,
|
|
469
|
-
qty: e.node.qty,
|
|
470
|
-
updatedAt: new Date(),
|
|
471
|
-
}));
|
|
472
|
-
|
|
473
|
-
// Write as Parquet
|
|
474
|
-
const buffer = await s3.writeParquetContent(records, {
|
|
475
|
-
compression: 'GZIP',
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// Generate file name with timestamp
|
|
479
|
-
const fileName = generateFileName('inventory', {
|
|
480
|
-
timestamp: 'yyyymmdd-hhmmss',
|
|
481
|
-
extension: 'parquet',
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
// Generate date-based path
|
|
485
|
-
const subdirs = generateDateSubdirectories();
|
|
486
|
-
const fullPath = generateFilePath('exports', fileName, subdirs);
|
|
487
|
-
// Result: 'exports/2025/10/06/inventory-20251006-123045.parquet'
|
|
488
|
-
|
|
489
|
-
// Upload to S3
|
|
490
|
-
await s3.uploadFile(fullPath, buffer);
|
|
491
|
-
|
|
492
|
-
console.log(`Exported ${records.length} records to ${fullPath}`);
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
## SFTP Data Source
|
|
496
|
-
|
|
497
|
-
Direct SFTP file operations using `ssh2-sftp-client`. Works standalone without Versori dependencies.
|
|
498
|
-
|
|
499
|
-
### SFTP Constructor
|
|
500
|
-
|
|
501
|
-
```typescript
|
|
502
|
-
import { SftpDataSource } from '@fluentcommerce/fc-connect-sdk';
|
|
503
|
-
|
|
504
|
-
const sftpConfig: SftpDataSourceConfig = {
|
|
505
|
-
type: 'SFTP_CSV', // or 'SFTP_JSON', 'SFTP_JSONL', 'SFTP_PARQUET'
|
|
506
|
-
connectionId: 'sftp-prod',
|
|
507
|
-
name: 'Production SFTP',
|
|
508
|
-
settings: {
|
|
509
|
-
// Direct connection credentials (no platform required)
|
|
510
|
-
host: 'sftp.example.com',
|
|
511
|
-
port: 22,
|
|
512
|
-
username: 'user',
|
|
513
|
-
password: 'password', // or use privateKey
|
|
514
|
-
privateKey: 'PEM string or Buffer', // Optional SSH key
|
|
515
|
-
passphrase: 'key passphrase', // Optional for encrypted keys
|
|
516
|
-
remotePath: '/data',
|
|
517
|
-
filePattern: '*.csv',
|
|
518
|
-
|
|
519
|
-
// Connection settings
|
|
520
|
-
connectionTimeout: 30000,
|
|
521
|
-
keepaliveInterval: 5000,
|
|
522
|
-
maxConnections: 5,
|
|
523
|
-
|
|
524
|
-
// Write operation settings
|
|
525
|
-
writeCreateDirectories: true,
|
|
526
|
-
writeOverwrite: false,
|
|
527
|
-
writePermissions: '0644',
|
|
528
|
-
},
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
const sftp = new SftpDataSource(sftpConfig, logger);
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
**Configuration Notes:**
|
|
535
|
-
|
|
536
|
-
`SftpDataSourceConfig` extends `DataSourceConfig`, which includes:
|
|
537
|
-
|
|
538
|
-
- `type: string` - Data source type ('SFTP_CSV', 'SFTP_JSON', 'SFTP_JSONL', or 'SFTP_PARQUET')
|
|
539
|
-
- `connectionId?: string` - Optional connection identifier
|
|
540
|
-
- `name?: string` - Optional descriptive name
|
|
541
|
-
- `connection?: SftpConnection` - **Optional** - Only required for Versori platform integration
|
|
542
|
-
|
|
543
|
-
**Authentication Options:**
|
|
544
|
-
|
|
545
|
-
- For **standalone use** (no Versori), provide `username` and either `password` or `privateKey` in settings
|
|
546
|
-
- For **Versori platform integration**, provide `connection` object (credentials managed by platform)
|
|
547
|
-
|
|
548
|
-
### Configuration Types
|
|
549
|
-
|
|
550
|
-
The SFTP data source uses ssh2-sftp-client internally:
|
|
551
|
-
|
|
552
|
-
```typescript
|
|
553
|
-
interface SftpDataSourceConfig extends DataSourceConfig {
|
|
554
|
-
type: 'SFTP_CSV' | 'SFTP_JSON' | 'SFTP_JSONL' | 'SFTP_PARQUET';
|
|
555
|
-
connection?: SftpConnection; // Optional - only for Versori
|
|
556
|
-
settings: {
|
|
557
|
-
// Direct SFTP connection (no connection object needed)
|
|
558
|
-
host: string;
|
|
559
|
-
port?: number;
|
|
560
|
-
username?: string;
|
|
561
|
-
password?: string;
|
|
562
|
-
privateKey?: string | Buffer;
|
|
563
|
-
passphrase?: string;
|
|
564
|
-
remotePath: string;
|
|
565
|
-
filePattern: string;
|
|
566
|
-
|
|
567
|
-
// CSV settings
|
|
568
|
-
csvDelimiter?: string;
|
|
569
|
-
csvHeaders?: string[];
|
|
570
|
-
csvSkipEmptyLines?: boolean;
|
|
571
|
-
csvTrimValues?: boolean;
|
|
572
|
-
csvQuote?: string;
|
|
573
|
-
csvEscape?: string;
|
|
574
|
-
|
|
575
|
-
// JSON settings
|
|
576
|
-
jsonFormat?: 'json' | 'jsonl';
|
|
577
|
-
jsonValidate?: boolean;
|
|
578
|
-
jsonMaxDepth?: number;
|
|
579
|
-
jsonIndent?: number;
|
|
580
|
-
jsonSortKeys?: boolean;
|
|
581
|
-
|
|
582
|
-
// Parquet settings
|
|
583
|
-
parquetCompression?: 'none' | 'snappy' | 'gzip' | 'lz4';
|
|
584
|
-
parquetSchema?: Record<string, string>;
|
|
585
|
-
parquetRowGroupSize?: number;
|
|
586
|
-
|
|
587
|
-
// Write operation settings
|
|
588
|
-
writeCreateDirectories?: boolean;
|
|
589
|
-
writeOverwrite?: boolean;
|
|
590
|
-
writePermissions?: string;
|
|
591
|
-
|
|
592
|
-
// Connection settings
|
|
593
|
-
encoding?: string;
|
|
594
|
-
connectionTimeout?: number;
|
|
595
|
-
keepAliveInterval?: number;
|
|
596
|
-
maxConnections?: number;
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
### SFTP File Listing
|
|
602
|
-
|
|
603
|
-
**listFiles(params?)** - List files on SFTP server with pattern matching and timestamp filtering
|
|
604
|
-
|
|
605
|
-
```typescript
|
|
606
|
-
// List all files with default pattern
|
|
607
|
-
const files = await sftp.listFiles();
|
|
608
|
-
|
|
609
|
-
// List files with custom pattern (wildcard supported)
|
|
610
|
-
const files = await sftp.listFiles({
|
|
611
|
-
filePattern: '*.csv',
|
|
612
|
-
remotePath: '/data/inventory',
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
// List files with wildcard patterns
|
|
616
|
-
const files = await sftp.listFiles({
|
|
617
|
-
filePattern: 'products_*.csv', // Match: products_2025.csv, products_test.csv
|
|
618
|
-
remotePath: '/data',
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
// Incremental sync - files modified after timestamp
|
|
622
|
-
const files = await sftp.listFiles({
|
|
623
|
-
lastProcessedTimestamp: '2025-01-01T00:00:00Z',
|
|
624
|
-
filePattern: '*.csv',
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
// Filter by file name substring
|
|
628
|
-
const files = await sftp.listFiles({
|
|
629
|
-
fileName: 'inventory', // Matches files containing 'inventory'
|
|
630
|
-
remotePath: '/data',
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
// Returns: FileMetadata[]
|
|
634
|
-
// [
|
|
635
|
-
// {
|
|
636
|
-
// path: '/data/inventory/products.csv',
|
|
637
|
-
// name: 'products.csv',
|
|
638
|
-
// size: 1024,
|
|
639
|
-
// lastModified: '2025-01-15T10:30:00Z',
|
|
640
|
-
// contentType: 'text/csv',
|
|
641
|
-
// source: 'SFTP'
|
|
642
|
-
// }
|
|
643
|
-
// ]
|
|
644
|
-
```
|
|
645
|
-
|
|
646
|
-
**Parameters:**
|
|
647
|
-
|
|
648
|
-
- `remotePath?: string` - Remote directory path (defaults to config remotePath)
|
|
649
|
-
- `filePattern?: string` - Wildcard pattern for filtering (e.g., '\_.csv', 'products\_\_.json')
|
|
650
|
-
- `lastProcessedTimestamp?: string` - ISO timestamp for incremental sync
|
|
651
|
-
- `fileName?: string` - Filter by file name substring
|
|
652
|
-
|
|
653
|
-
**Pattern Matching:**
|
|
654
|
-
|
|
655
|
-
- `*.csv` - All CSV files
|
|
656
|
-
- `products_*.csv` - CSV files starting with 'products\_'
|
|
657
|
-
- `*_2025_*.json` - JSON files containing '_2025_'
|
|
658
|
-
- Case-insensitive matching
|
|
659
|
-
|
|
660
|
-
**Note:** Unlike S3, SFTP DOES support wildcard pattern matching natively.
|
|
661
|
-
|
|
662
|
-
### SFTP File Download
|
|
663
|
-
|
|
664
|
-
**downloadFile(path, options?)** - Download file content from SFTP server
|
|
665
|
-
|
|
666
|
-
```typescript
|
|
667
|
-
// Download as text (default UTF-8)
|
|
668
|
-
const csvContent = await sftp.downloadFile('/data/inventory.csv');
|
|
669
|
-
// Returns: string
|
|
670
|
-
|
|
671
|
-
// Download as buffer (for binary files)
|
|
672
|
-
const buffer = await sftp.downloadFile('/data/file.parquet', {
|
|
673
|
-
asBuffer: true,
|
|
674
|
-
});
|
|
675
|
-
// Returns: Buffer
|
|
676
|
-
|
|
677
|
-
// Download with custom encoding
|
|
678
|
-
const content = await sftp.downloadFile('/data/file.txt', {
|
|
679
|
-
encoding: 'latin1',
|
|
680
|
-
});
|
|
681
|
-
// Returns: string
|
|
682
|
-
|
|
683
|
-
// Download with size limit
|
|
684
|
-
const content = await sftp.downloadFile('/data/large-file.csv', {
|
|
685
|
-
maxSize: 10 * 1024 * 1024, // 10 MB limit
|
|
686
|
-
});
|
|
687
|
-
```
|
|
688
|
-
|
|
689
|
-
**Parameters:**
|
|
690
|
-
|
|
691
|
-
- `path: string` - Remote file path
|
|
692
|
-
- `options.encoding?: string` - Text encoding (default: 'utf8')
|
|
693
|
-
- `options.asBuffer?: boolean` - Return Buffer instead of string
|
|
694
|
-
- `options.maxSize?: number` - Maximum file size in bytes
|
|
695
|
-
|
|
696
|
-
**Returns:**
|
|
697
|
-
|
|
698
|
-
- `Promise<string | Buffer>` - File content
|
|
699
|
-
|
|
700
|
-
### File Existence Checks
|
|
701
|
-
|
|
702
|
-
```typescript
|
|
703
|
-
// Check if file exists
|
|
704
|
-
const fileExists = await sftp.fileExists('/data/inventory.csv');
|
|
705
|
-
|
|
706
|
-
// Check if directory exists
|
|
707
|
-
const dirExists = await sftp.directoryExists('/data/exports');
|
|
708
|
-
```
|
|
709
|
-
|
|
710
|
-
### SFTP File Upload
|
|
711
|
-
|
|
712
|
-
**uploadContent(content, remotePath, options?)** - Upload content directly to SFTP server
|
|
713
|
-
|
|
714
|
-
```typescript
|
|
715
|
-
// Upload text content
|
|
716
|
-
const csvContent = 'sku,qty\nPROD-001,100\nPROD-002,50';
|
|
717
|
-
await sftp.uploadFile('/data/inventory.csv', {
|
|
718
|
-
overwrite: true,
|
|
719
|
-
createDirectories: true,
|
|
720
|
-
}, csvContent);
|
|
721
|
-
|
|
722
|
-
// Upload binary content (Buffer)
|
|
723
|
-
const parquetBuffer = await sftp.writeParquetContent(records);
|
|
724
|
-
await sftp.uploadFile('/exports/data.parquet', {
|
|
725
|
-
overwrite: true,
|
|
726
|
-
encoding: 'binary',
|
|
727
|
-
}, parquetBuffer);
|
|
728
|
-
|
|
729
|
-
// Upload JSON with auto-directory creation
|
|
730
|
-
const jsonData = [
|
|
731
|
-
{ productRef: 'PROD-001', qty: 100 },
|
|
732
|
-
{ productRef: 'PROD-002', qty: 50 },
|
|
733
|
-
];
|
|
734
|
-
await sftp.uploadFile(null, 2, JSON.stringify(jsonData), '/exports/2025/01/15/data.json', {
|
|
735
|
-
createDirectories: true, // Creates /exports/2025/01/15/ if needed
|
|
736
|
-
permissions: '0644',
|
|
737
|
-
});
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
**Parameters:**
|
|
741
|
-
|
|
742
|
-
- `content: string | Buffer` - Content to upload
|
|
743
|
-
- `remotePath: string` - Destination file path
|
|
744
|
-
- `options.overwrite?: boolean` - Overwrite if file exists (default: false)
|
|
745
|
-
- `options.createDirectories?: boolean` - Create parent directories (default: false)
|
|
746
|
-
- `options.permissions?: string` - File permissions (default: '0644')
|
|
747
|
-
- `options.encoding?: string` - Text encoding (default: 'utf8')
|
|
748
|
-
|
|
749
|
-
**uploadFile(localPath, remotePath, options?)** - Upload local file to SFTP server
|
|
750
|
-
|
|
751
|
-
```typescript
|
|
752
|
-
// Upload local file
|
|
753
|
-
await sftp.uploadFile('/local/data/inventory.csv', '/remote/data/inventory.csv', {
|
|
754
|
-
overwrite: true,
|
|
755
|
-
createDirectories: true,
|
|
756
|
-
permissions: '0644',
|
|
757
|
-
});
|
|
758
|
-
```
|
|
759
|
-
|
|
760
|
-
**Parameters:**
|
|
761
|
-
|
|
762
|
-
- `localPath: string` - Local file path
|
|
763
|
-
- `remotePath: string` - Remote destination path
|
|
764
|
-
- `options` - Same as uploadContent
|
|
765
|
-
|
|
766
|
-
### Directory Operations
|
|
767
|
-
|
|
768
|
-
**createDirectory(remotePath, recursive, permissions?)** - Create directory on SFTP server
|
|
769
|
-
|
|
770
|
-
```typescript
|
|
771
|
-
// Create single directory
|
|
772
|
-
await sftp.createDirectory('/data/exports', false);
|
|
773
|
-
|
|
774
|
-
// Create directory tree
|
|
775
|
-
await sftp.createDirectory('/data/exports/2025/01/15', true, '0755');
|
|
776
|
-
|
|
777
|
-
// Check before creating
|
|
778
|
-
if (!(await sftp.directoryExists('/data/archive'))) {
|
|
779
|
-
await sftp.createDirectory('/data/archive', true);
|
|
780
|
-
}
|
|
781
|
-
```
|
|
782
|
-
|
|
783
|
-
**Parameters:**
|
|
784
|
-
|
|
785
|
-
- `remotePath: string` - Directory path to create
|
|
786
|
-
- `recursive: boolean` - Create parent directories (default: false)
|
|
787
|
-
- `permissions?: string` - Directory permissions (default: '0755')
|
|
788
|
-
|
|
789
|
-
### SFTP File Deletion
|
|
790
|
-
|
|
791
|
-
**deleteFile(remotePath)** - Delete file from SFTP server
|
|
792
|
-
|
|
793
|
-
```typescript
|
|
794
|
-
// Delete single file
|
|
795
|
-
await sftp.deleteFile('/temp/processing.csv');
|
|
796
|
-
|
|
797
|
-
// Delete with existence check
|
|
798
|
-
if (await sftp.fileExists('/temp/old-file.csv')) {
|
|
799
|
-
await sftp.deleteFile('/temp/old-file.csv');
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
// Bulk delete
|
|
803
|
-
const tempFiles = await sftp.listFiles({ remotePath: '/temp', filePattern: '*.tmp' });
|
|
804
|
-
for (const file of tempFiles) {
|
|
805
|
-
await sftp.deleteFile(file.path);
|
|
806
|
-
}
|
|
807
|
-
```
|
|
808
|
-
|
|
809
|
-
**Parameters:**
|
|
810
|
-
|
|
811
|
-
- `remotePath: string` - File path to delete
|
|
812
|
-
|
|
813
|
-
**Throws:** Error if file does not exist
|
|
814
|
-
|
|
815
|
-
### File Move (Atomic)
|
|
816
|
-
|
|
817
|
-
**moveFile(oldPath, newPath, overwrite?)** - Move/rename file on SFTP server
|
|
818
|
-
|
|
819
|
-
```typescript
|
|
820
|
-
// Move file between directories
|
|
821
|
-
await sftp.moveFile('/data/processing.csv', '/data/archive/processed.csv', false);
|
|
822
|
-
|
|
823
|
-
// Rename file in same directory
|
|
824
|
-
await sftp.moveFile(
|
|
825
|
-
'/data/temp_file.csv',
|
|
826
|
-
'/data/inventory_2025.csv',
|
|
827
|
-
true // overwrite if exists
|
|
828
|
-
);
|
|
829
|
-
|
|
830
|
-
// Archive processed files
|
|
831
|
-
const files = await sftp.listFiles({ remotePath: '/data/inbox' });
|
|
832
|
-
for (const file of files) {
|
|
833
|
-
const archivePath = `/data/archive/${file.name}`;
|
|
834
|
-
await sftp.moveFile(file.path, archivePath, false);
|
|
835
|
-
}
|
|
836
|
-
```
|
|
837
|
-
|
|
838
|
-
**Parameters:**
|
|
839
|
-
|
|
840
|
-
- `oldPath: string` - Current file path
|
|
841
|
-
- `newPath: string` - New file path
|
|
842
|
-
- `overwrite?: boolean` - Overwrite destination (default: false)
|
|
843
|
-
|
|
844
|
-
**Important:** SFTP moveFile() is ATOMIC - single server-side operation (unlike S3)
|
|
845
|
-
|
|
846
|
-
### SFTP File Copy
|
|
847
|
-
|
|
848
|
-
**copyFile(sourcePath, destPath, overwrite?)** - Copy file on SFTP server
|
|
849
|
-
|
|
850
|
-
```typescript
|
|
851
|
-
// Create backup
|
|
852
|
-
await sftp.copyFile('/data/inventory.csv', '/backup/inventory_backup.csv', true);
|
|
853
|
-
|
|
854
|
-
// Copy to multiple locations
|
|
855
|
-
const sourceFile = '/data/master.csv';
|
|
856
|
-
const destinations = ['/backup/master.csv', '/archive/2025/master.csv', '/staging/master.csv'];
|
|
857
|
-
|
|
858
|
-
for (const dest of destinations) {
|
|
859
|
-
await sftp.copyFile(sourceFile, dest, true);
|
|
860
|
-
}
|
|
861
|
-
```
|
|
862
|
-
|
|
863
|
-
**Parameters:**
|
|
864
|
-
|
|
865
|
-
- `sourcePath: string` - Source file path
|
|
866
|
-
- `destPath: string` - Destination file path
|
|
867
|
-
- `overwrite?: boolean` - Overwrite destination (default: false)
|
|
868
|
-
|
|
869
|
-
**Note:** Implemented as download + upload (SFTP protocol has no native copy command)
|
|
870
|
-
|
|
871
|
-
### SFTP File Archive
|
|
872
|
-
|
|
873
|
-
**archiveFile(sourcePath, archivePrefix?)** - Archive file with timestamp (template method from AbstractDataSource)
|
|
874
|
-
|
|
875
|
-
```typescript
|
|
876
|
-
// Archive to default 'archive/' prefix
|
|
877
|
-
const archivePath = await sftp.archiveFile('/data/inventory.csv');
|
|
878
|
-
// Returns: 'archive/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
879
|
-
|
|
880
|
-
// Archive to custom prefix
|
|
881
|
-
const archivePath = await sftp.archiveFile('/data/inventory.csv', '/backup/2025/');
|
|
882
|
-
// Returns: '/backup/2025/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
883
|
-
|
|
884
|
-
// Archive processed files after ingestion
|
|
885
|
-
const files = await sftp.listFiles({ remotePath: '/data/inbox' });
|
|
886
|
-
for (const file of files) {
|
|
887
|
-
await processFile(file);
|
|
888
|
-
const archivePath = await sftp.archiveFile(file.path, '/data/archive/');
|
|
889
|
-
console.log(`Archived ${file.name} to ${archivePath}`);
|
|
890
|
-
}
|
|
891
|
-
```
|
|
892
|
-
|
|
893
|
-
**Parameters:**
|
|
894
|
-
|
|
895
|
-
- `sourcePath: string` - Source file path
|
|
896
|
-
- `archivePrefix?: string` - Archive directory prefix (default: 'archive/')
|
|
897
|
-
|
|
898
|
-
**Returns:** `Promise<string>` - The archive path where file was moved
|
|
899
|
-
|
|
900
|
-
**How It Works:**
|
|
901
|
-
1. Generates timestamped filename: `{archivePrefix}{timestamp}_{originalFilename}`
|
|
902
|
-
2. Moves file to archive location using moveFile()
|
|
903
|
-
3. Returns the full archive path
|
|
904
|
-
|
|
905
|
-
**Important:** SFTP archiveFile() is atomic since it uses SFTP's atomic moveFile() operation.
|
|
906
|
-
|
|
907
|
-
### Multi-Format Support
|
|
908
|
-
|
|
909
|
-
#### CSV Operations
|
|
910
|
-
|
|
911
|
-
```typescript
|
|
912
|
-
// Write CSV content with custom options
|
|
913
|
-
const csvRecords = [
|
|
914
|
-
{ sku: 'PROD-001', qty: 100, location: 'DC-001' },
|
|
915
|
-
{ sku: 'PROD-002', qty: 50, location: 'DC-002' },
|
|
916
|
-
];
|
|
917
|
-
|
|
918
|
-
const csvContent = sftp.writeCsvContent(csvRecords, {
|
|
919
|
-
delimiter: ',',
|
|
920
|
-
headers: ['sku', 'qty', 'location'],
|
|
921
|
-
includeHeader: true,
|
|
922
|
-
quote: '"',
|
|
923
|
-
escape: '\\',
|
|
924
|
-
encoding: 'utf8',
|
|
925
|
-
});
|
|
926
|
-
|
|
927
|
-
// Upload CSV content
|
|
928
|
-
await sftp.uploadFile('/data/inventory.csv', csvContent);
|
|
929
|
-
```
|
|
930
|
-
|
|
931
|
-
#### JSON Operations
|
|
932
|
-
|
|
933
|
-
```typescript
|
|
934
|
-
// Write JSON content
|
|
935
|
-
const jsonRecords = [
|
|
936
|
-
{ productRef: 'PROD-001', quantity: 100 },
|
|
937
|
-
{ productRef: 'PROD-002', quantity: 50 },
|
|
938
|
-
];
|
|
939
|
-
|
|
940
|
-
const jsonContent = sftp.writeJsonContent(jsonRecords, {
|
|
941
|
-
format: 'json', // or 'jsonl' for JSON Lines
|
|
942
|
-
indent: 2,
|
|
943
|
-
sortKeys: true,
|
|
944
|
-
replacer: (key, value) => (key === 'quantity' ? Number(value) : value),
|
|
945
|
-
});
|
|
946
|
-
|
|
947
|
-
// Upload JSON content
|
|
948
|
-
await sftp.uploadFile('/data/products.json', jsonContent);
|
|
949
|
-
|
|
950
|
-
// Parse JSON content from downloaded file
|
|
951
|
-
const downloadedJson = await sftp.downloadFile('products.json');
|
|
952
|
-
const parsedRecords = sftp.parseJsonContent(downloadedJson, {
|
|
953
|
-
format: 'json',
|
|
954
|
-
validate: true,
|
|
955
|
-
maxDepth: 10,
|
|
956
|
-
});
|
|
957
|
-
```
|
|
958
|
-
|
|
959
|
-
#### JSON Lines Support
|
|
960
|
-
|
|
961
|
-
```typescript
|
|
962
|
-
// Write JSON Lines (JSONL) format
|
|
963
|
-
const jsonlContent = sftp.writeJsonContent(records, {
|
|
964
|
-
format: 'jsonl',
|
|
965
|
-
});
|
|
966
|
-
// Produces:
|
|
967
|
-
// {"id":1,"name":"Product A"}
|
|
968
|
-
// {"id":2,"name":"Product B"}
|
|
969
|
-
|
|
970
|
-
// Parse JSONL content
|
|
971
|
-
const jsonlRecords = sftp.parseJsonContent(jsonlContent, {
|
|
972
|
-
format: 'jsonl',
|
|
973
|
-
});
|
|
974
|
-
```
|
|
975
|
-
|
|
976
|
-
**Parquet Operations (SFTP)**
|
|
977
|
-
|
|
978
|
-
- Read/parse Parquet: Not implemented yet in SFTP data source. Attempting to call `parseParquetContent` will throw until hyparquet integration is added for SFTP. Use S3→download→parsers for Parquet reads.
|
|
979
|
-
- Write Parquet: Implemented via `writeParquetContent(records, options)` producing a Buffer that you can upload with `uploadContent`.
|
|
980
|
-
|
|
981
|
-
```typescript
|
|
982
|
-
// Write Parquet content (supported)
|
|
983
|
-
const parquetBuffer = await sftp.writeParquetContent(records, {
|
|
984
|
-
compression: 'gzip',
|
|
985
|
-
parquetSchema: {
|
|
986
|
-
productRef: 'string',
|
|
987
|
-
quantity: 'int32',
|
|
988
|
-
price: 'double',
|
|
989
|
-
},
|
|
990
|
-
parquetRowGroupSize: 1000,
|
|
991
|
-
});
|
|
992
|
-
await sftp.uploadFile('/exports/data.parquet', { overwrite: true }, parquetBuffer);
|
|
993
|
-
|
|
994
|
-
// Read Parquet content (not yet supported on SFTP data source)
|
|
995
|
-
// const records = await sftp.parseParquetContent(buffer, fileMetadata); // ❌ throws
|
|
996
|
-
```
|
|
997
|
-
|
|
998
|
-
### Error Handling
|
|
999
|
-
|
|
1000
|
-
The SFTP data source provides complete error handling:
|
|
1001
|
-
|
|
1002
|
-
```typescript
|
|
1003
|
-
try {
|
|
1004
|
-
await sftp.uploadFile(localPath, remotePath);
|
|
1005
|
-
} catch (error) {
|
|
1006
|
-
if (error instanceof DataSourceError) {
|
|
1007
|
-
console.error(`SFTP Error [${error.code}]:`, error.message);
|
|
1008
|
-
console.error('Context:', error.context);
|
|
1009
|
-
console.error('Operation:', error.operation);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
```
|
|
1013
|
-
|
|
1014
|
-
### Connection Management
|
|
1015
|
-
|
|
1016
|
-
The SFTP data source includes sophisticated connection management:
|
|
1017
|
-
|
|
1018
|
-
```typescript
|
|
1019
|
-
// Get connection information
|
|
1020
|
-
const connectionInfo = sftp.getConnectionInfo();
|
|
1021
|
-
console.log('Pool size:', connectionInfo.connectionPoolSize);
|
|
1022
|
-
console.log('Max pool size:', connectionInfo.maxPoolSize);
|
|
1023
|
-
|
|
1024
|
-
// Connection pooling is handled automatically
|
|
1025
|
-
// Multiple operations reuse connections efficiently
|
|
1026
|
-
```
|
|
1027
|
-
|
|
1028
|
-
## Complete Methods Reference
|
|
1029
|
-
|
|
1030
|
-
### S3 Data Source Methods
|
|
1031
|
-
|
|
1032
|
-
**File Operations:**
|
|
1033
|
-
|
|
1034
|
-
- `listFiles(params?): Promise<FileMetadata[]>` - List objects with filtering
|
|
1035
|
-
- `downloadFile(key, options?): Promise<string | Buffer>` - Download object content
|
|
1036
|
-
- `uploadFile(key, content, options?): Promise<void>` - Upload object (required abstract method)
|
|
1037
|
-
- `deleteFile(key): Promise<void>` - Delete object
|
|
1038
|
-
- `copyFile(sourceKey, destKey, options?): Promise<void>` - Copy object (supports cross-bucket)
|
|
1039
|
-
- `moveFile(sourcePath, destPath, deleteSource?): Promise<void>` - Move object within same bucket (template method)
|
|
1040
|
-
- `archiveFile(sourcePath, archivePrefix?): Promise<string>` - Archive file with timestamp (template method)
|
|
1041
|
-
- `validateConnection(): Promise<boolean>` - Test bucket access
|
|
1042
|
-
- `writeParquetContent(records, options?): Promise<Buffer>` - Write Parquet format
|
|
1043
|
-
|
|
1044
|
-
### SFTP Data Source Methods
|
|
1045
|
-
|
|
1046
|
-
**File Operations:**
|
|
1047
|
-
|
|
1048
|
-
- `listFiles(params?): Promise<FileMetadata[]>` - List files with wildcard pattern matching
|
|
1049
|
-
- `downloadFile(path, options?): Promise<string | Buffer>` - Download file content
|
|
1050
|
-
- `uploadFile(remotePath, content, options?): Promise<void>` - Upload content (required abstract method)
|
|
1051
|
-
- `deleteFile(remotePath): Promise<void>` - Delete file
|
|
1052
|
-
- `moveFile(oldPath, newPath, overwrite?): Promise<void>` - Move/rename file (atomic, template method)
|
|
1053
|
-
- `copyFile(sourcePath, destPath, overwrite?): Promise<void>` - Copy file
|
|
1054
|
-
- `archiveFile(sourcePath, archivePrefix?): Promise<string>` - Archive file with timestamp (template method)
|
|
1055
|
-
- `fileExists(remotePath): Promise<boolean>` - Check if file exists
|
|
1056
|
-
- `directoryExists(remotePath): Promise<boolean>` - Check if directory exists
|
|
1057
|
-
- `createDirectory(remotePath, recursive, permissions?): Promise<void>` - Create directory
|
|
1058
|
-
- `validateConnection(): Promise<boolean>` - Test SFTP connection
|
|
1059
|
-
- `dispose(): Promise<void>` - Clean up connections
|
|
1060
|
-
|
|
1061
|
-
**Format Operations:**
|
|
1062
|
-
|
|
1063
|
-
- `parseCsvContent(csvContent, fileMetadata): CsvRecord[]` - Parse CSV string
|
|
1064
|
-
- `writeCsvContent(records, options?): string` - Generate CSV string
|
|
1065
|
-
- `parseJsonContent(jsonContent, fileMetadata, options?): Record<string, unknown>[]` - Parse JSON/JSONL
|
|
1066
|
-
- `writeJsonContent(records, options?): string` - Generate JSON/JSONL string
|
|
1067
|
-
- `parseParquetContent(buffer, fileMetadata): Promise<ParquetDataRecord[]>` - Not supported; currently throws
|
|
1068
|
-
- `writeParquetContent(records, options?): Promise<Buffer>` - Generate Parquet buffer
|
|
1069
|
-
|
|
1070
|
-
**Utility Methods:**
|
|
1071
|
-
|
|
1072
|
-
- `getConnectionInfo(): ConnectionInfo` - Get connection pool status
|
|
1073
|
-
|
|
1074
|
-
## See Also
|
|
1075
|
-
|
|
1076
|
-
- [Module 07: Parsers](./api-reference-07-parsers.md) - Format-specific parsing
|
|
1077
|
-
- [Module 05: Extraction](../../extraction/extraction-readme.md) - Using data sources for extraction
|
|
1078
|
-
- [Module 10: Utilities](./api-reference-10-utilities.md) - Helper functions
|
|
1079
|
-
- [Getting Started Guide](../../../00-START-HERE/getting-started.md) - Basic setup
|
|
1080
|
-
|
|
1081
|
-
---
|
|
1082
|
-
|
|
1083
|
-
**[← Previous: Services](./api-reference-05-services.md)** | **[API Reference Home](../api-reference-readme.md)** | **[Next: Parsers →](./api-reference-07-parsers.md)**
|
|
1
|
+
# Module 06: Data Sources
|
|
2
|
+
|
|
3
|
+
**Level:** Intermediate
|
|
4
|
+
**Category:** Data Integration
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Data sources provide unified interfaces for reading and writing data from different storage systems (S3, SFTP, etc.). They handle connection management, file operations, format conversions, and error handling, allowing you to work with multiple data sources through a consistent API.
|
|
9
|
+
|
|
10
|
+
## Architecture
|
|
11
|
+
|
|
12
|
+
All data sources extend `AbstractDataSource`, which provides:
|
|
13
|
+
|
|
14
|
+
**Required Methods (must implement):**
|
|
15
|
+
- `listFiles()` - List files with filtering
|
|
16
|
+
- `downloadFile()` - Download file content
|
|
17
|
+
- `uploadFile()` - Upload file content (⚠️ **mandatory**)
|
|
18
|
+
- `deleteFile()` - Delete a file
|
|
19
|
+
- `copyFileInternal()` - Internal copy implementation
|
|
20
|
+
- `validateConnection()` - Test connectivity
|
|
21
|
+
|
|
22
|
+
**Template Methods (inherited):**
|
|
23
|
+
- `moveFile()` - Move file using copyFileInternal() + deleteFile()
|
|
24
|
+
- `archiveFile()` - Archive file to timestamped location using moveFile()
|
|
25
|
+
|
|
26
|
+
Both S3DataSource and SftpDataSource implement all required methods and inherit the template methods. For advanced use cases (e.g., cross-bucket S3 operations), use `copyFile()` directly.
|
|
27
|
+
|
|
28
|
+
## Table of Contents
|
|
29
|
+
|
|
30
|
+
- [S3 Data Source](#s3-data-source)
|
|
31
|
+
- [Constructor](#constructor)
|
|
32
|
+
- [File Listing](#file-listing)
|
|
33
|
+
- [File Download](#file-download)
|
|
34
|
+
- [File Upload](#file-upload)
|
|
35
|
+
- [File Deletion](#file-deletion)
|
|
36
|
+
- [File Copy](#file-copy)
|
|
37
|
+
- [File Move](#file-move)
|
|
38
|
+
- [Connection Validation](#connection-validation)
|
|
39
|
+
- [Writing Parquet Files](#writing-parquet-files)
|
|
40
|
+
- [SFTP Data Source](#sftp-data-source)
|
|
41
|
+
- [Constructor](#sftp-constructor)
|
|
42
|
+
- [Configuration Types](#configuration-types)
|
|
43
|
+
- [File Listing](#sftp-file-listing)
|
|
44
|
+
- [File Download](#sftp-file-download)
|
|
45
|
+
- [File Existence Checks](#file-existence-checks)
|
|
46
|
+
- [File Upload](#sftp-file-upload)
|
|
47
|
+
- [Directory Operations](#directory-operations)
|
|
48
|
+
- [File Deletion](#sftp-file-deletion)
|
|
49
|
+
- [File Move](#file-move-atomic)
|
|
50
|
+
- [File Copy](#sftp-file-copy)
|
|
51
|
+
- [Multi-Format Support](#multi-format-support)
|
|
52
|
+
- [Error Handling](#error-handling)
|
|
53
|
+
- [Connection Management](#connection-management)
|
|
54
|
+
- [Complete Methods Reference](#complete-methods-reference)
|
|
55
|
+
- [See Also](#see-also)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## S3 Data Source
|
|
60
|
+
|
|
61
|
+
Read and write files from Amazon S3 with presigned URLs.
|
|
62
|
+
|
|
63
|
+
### Constructor
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { S3DataSource } from '@fluentcommerce/fc-connect-sdk';
|
|
67
|
+
|
|
68
|
+
const s3Config: S3DataSourceConfig = {
|
|
69
|
+
type: 'S3_CSV',
|
|
70
|
+
connectionId: 's3-api-ref',
|
|
71
|
+
name: 'S3 API Reference',
|
|
72
|
+
s3Config: {
|
|
73
|
+
bucket: 'my-bucket',
|
|
74
|
+
region: 'us-east-1',
|
|
75
|
+
accessKeyId: 'your-access-key',
|
|
76
|
+
secretAccessKey: 'your-secret-key',
|
|
77
|
+
sessionToken: 'optional-session-token', // Optional for temporary credentials
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const s3 = new S3DataSource(s3Config, logger);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Configuration Notes:**
|
|
85
|
+
|
|
86
|
+
`S3DataSourceConfig` extends `DataSourceConfig`, which includes:
|
|
87
|
+
|
|
88
|
+
- `type: string` - Data source type ('S3_CSV')
|
|
89
|
+
- `connectionId?: string` - Optional connection identifier
|
|
90
|
+
- `name?: string` - Optional descriptive name
|
|
91
|
+
- `connection?: any` - Optional Versori platform connection object (for Versori integration)
|
|
92
|
+
|
|
93
|
+
For **standalone use** (without Versori), only provide `type` and `s3Config`.
|
|
94
|
+
For **Versori platform integration**, also provide `connection`, `connectionId`, and `name`.
|
|
95
|
+
|
|
96
|
+
### File Listing
|
|
97
|
+
|
|
98
|
+
**listFiles(params?)** - List objects in S3 bucket with filtering options
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// List all files in bucket
|
|
102
|
+
const files = await s3.listFiles();
|
|
103
|
+
|
|
104
|
+
// List files with prefix (folder)
|
|
105
|
+
const files = await s3.listFiles({
|
|
106
|
+
prefix: 'inventory/',
|
|
107
|
+
maxKeys: 100,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// List files with delimiter (folder separator)
|
|
111
|
+
const files = await s3.listFiles({
|
|
112
|
+
prefix: 'inventory/',
|
|
113
|
+
delimiter: '/',
|
|
114
|
+
maxKeys: 1000,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Returns: FileMetadata[]
|
|
118
|
+
// [
|
|
119
|
+
// {
|
|
120
|
+
// path: 'inventory/data.csv',
|
|
121
|
+
// name: 'data.csv',
|
|
122
|
+
// size: 2048,
|
|
123
|
+
// lastModified: '2025-01-15T10:30:00Z',
|
|
124
|
+
// contentType: 'text/csv',
|
|
125
|
+
// etag: '"abc123"',
|
|
126
|
+
// bucket: 'my-bucket',
|
|
127
|
+
// region: 'us-east-1',
|
|
128
|
+
// source: 'S3'
|
|
129
|
+
// }
|
|
130
|
+
// ]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Parameters:**
|
|
134
|
+
|
|
135
|
+
- `prefix?: string` - Filter by object key prefix (e.g., 'folder/')
|
|
136
|
+
- `delimiter?: string` - Delimiter for folder structure (typically '/')
|
|
137
|
+
- `maxKeys?: number` - Maximum number of keys to return (default: 1000)
|
|
138
|
+
- `continuationToken?: string` - Token for paginated results
|
|
139
|
+
|
|
140
|
+
**Note:** S3 does NOT support wildcard pattern matching. Use prefix + manual filtering:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// Get all CSV files in folder
|
|
144
|
+
const files = await s3.listFiles({ prefix: 'inventory/' });
|
|
145
|
+
|
|
146
|
+
// IMPORTANT: Use .endsWith('.csv') NOT .endsWith('*.csv')
|
|
147
|
+
// The asterisk is a glob pattern character, not part of the file extension
|
|
148
|
+
const csvFiles = files.filter(f => f.name.endsWith('.csv')); // ✓ Correct
|
|
149
|
+
|
|
150
|
+
// Common mistake to avoid:
|
|
151
|
+
// const csvFiles = files.filter(f => f.name.endsWith('*.csv')); // ✗ WRONG - Never matches!
|
|
152
|
+
|
|
153
|
+
// Get files matching pattern
|
|
154
|
+
const productFiles = files.filter(f => f.name.startsWith('products_'));
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### File Download
|
|
158
|
+
|
|
159
|
+
**downloadFile(key, options?)** - Download file content from S3
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Download as text (default UTF-8)
|
|
163
|
+
const csvContent = await s3.downloadFile('inventory/data.csv');
|
|
164
|
+
// Returns: string
|
|
165
|
+
|
|
166
|
+
// Download as binary (for images, Parquet, etc.)
|
|
167
|
+
const parquetBuffer = await s3.downloadFile('exports/data.parquet', {
|
|
168
|
+
encoding: 'binary',
|
|
169
|
+
});
|
|
170
|
+
// Returns: Buffer
|
|
171
|
+
|
|
172
|
+
// Download with custom response headers
|
|
173
|
+
const content = await s3.downloadFile('data/file.csv', {
|
|
174
|
+
responseHeaders: {
|
|
175
|
+
'Cache-Control': 'no-cache',
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Parameters:**
|
|
181
|
+
|
|
182
|
+
- `key: string` - S3 object key (path)
|
|
183
|
+
- `options.encoding?: 'utf8' | 'binary'` - Encoding format (default: 'utf8')
|
|
184
|
+
- `options.responseHeaders?: Record<string, string>` - Custom response headers
|
|
185
|
+
|
|
186
|
+
**Returns:**
|
|
187
|
+
|
|
188
|
+
- `Promise<string | Buffer>` - File content as string or Buffer
|
|
189
|
+
|
|
190
|
+
### File Upload
|
|
191
|
+
|
|
192
|
+
**uploadFile(key, content, options?)** - Upload file content to S3
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Upload text content
|
|
196
|
+
await s3.uploadFile('output/results.csv', csvContent, {
|
|
197
|
+
contentType: 'text/csv',
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Upload binary content (Buffer)
|
|
201
|
+
const parquetBuffer = await s3.writeParquetContent(records);
|
|
202
|
+
await s3.uploadFile('exports/data.parquet', parquetBuffer, {
|
|
203
|
+
contentType: 'application/octet-stream',
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Upload with metadata
|
|
207
|
+
await s3.uploadFile('data/inventory.json', jsonContent, {
|
|
208
|
+
contentType: 'application/json',
|
|
209
|
+
metadata: {
|
|
210
|
+
'upload-date': new Date().toISOString(),
|
|
211
|
+
source: 'fluent-commerce',
|
|
212
|
+
'record-count': '1000',
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Parameters:**
|
|
218
|
+
|
|
219
|
+
- `key: string` - Destination S3 object key
|
|
220
|
+
- `content: string | Buffer` - File content to upload
|
|
221
|
+
- `options.contentType?: string` - MIME type (default: 'application/octet-stream')
|
|
222
|
+
- `options.metadata?: Record<string, string>` - Custom metadata headers
|
|
223
|
+
|
|
224
|
+
### File Deletion
|
|
225
|
+
|
|
226
|
+
**deleteFile(key)** - Delete object from S3
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Delete single file
|
|
230
|
+
await s3.deleteFile('old-data/obsolete.csv');
|
|
231
|
+
|
|
232
|
+
// Delete with error handling
|
|
233
|
+
try {
|
|
234
|
+
await s3.deleteFile('temp/file.csv');
|
|
235
|
+
console.log('File deleted successfully');
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error.code === 'NoSuchKey') {
|
|
238
|
+
console.log('File does not exist');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Parameters:**
|
|
244
|
+
|
|
245
|
+
- `key: string` - S3 object key to delete
|
|
246
|
+
|
|
247
|
+
**Note:** Delete succeeds even if file doesn't exist (idempotent)
|
|
248
|
+
|
|
249
|
+
### File Copy
|
|
250
|
+
|
|
251
|
+
**copyFile(sourceKey, destKey, options?)** - Copy object within or across buckets
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// Copy within same bucket
|
|
255
|
+
await s3.copyFile('data/file.csv', 'archive/file.csv');
|
|
256
|
+
|
|
257
|
+
// Copy from different bucket
|
|
258
|
+
await s3.copyFile('original.csv', 'backup/copy.csv', {
|
|
259
|
+
sourceBucket: 'source-bucket',
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Copy with metadata update
|
|
263
|
+
await s3.copyFile('data/file.csv', 'processed/file.csv', {
|
|
264
|
+
metadata: {
|
|
265
|
+
'processed-date': new Date().toISOString(),
|
|
266
|
+
status: 'completed',
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Parameters:**
|
|
272
|
+
|
|
273
|
+
- `sourceKey: string` - Source object key
|
|
274
|
+
- `destKey: string` - Destination object key
|
|
275
|
+
- `options.sourceBucket?: string` - Source bucket (defaults to current bucket)
|
|
276
|
+
- `options.metadata?: Record<string, string>` - Metadata for destination object
|
|
277
|
+
|
|
278
|
+
### File Move
|
|
279
|
+
|
|
280
|
+
**moveFile(sourcePath, destPath, deleteSource?)** - Move object within same bucket (template method from AbstractDataSource)
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
// Move within same bucket
|
|
284
|
+
await s3.moveFile('temp/processing.csv', 'archive/completed.csv');
|
|
285
|
+
|
|
286
|
+
// Copy without deleting source
|
|
287
|
+
await s3.moveFile('data/file.csv', 'backup/file.csv', false);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Parameters:**
|
|
291
|
+
|
|
292
|
+
- `sourcePath: string` - Source object key
|
|
293
|
+
- `destPath: string` - Destination object key
|
|
294
|
+
- `deleteSource?: boolean` - Delete source after copy (default: true)
|
|
295
|
+
|
|
296
|
+
**Returns:** `Promise<void>`
|
|
297
|
+
|
|
298
|
+
**Important Notes:**
|
|
299
|
+
- S3 moveFile() is NOT atomic - it performs copy then delete. If delete fails, you'll have duplicate files.
|
|
300
|
+
- **Same-bucket only:** This method only works within the same bucket.
|
|
301
|
+
- **Cross-bucket moves:** For moving files between different S3 buckets, use `copyFile()` and `deleteFile()` directly.
|
|
302
|
+
|
|
303
|
+
**Cross-Bucket Move Example:**
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
// For cross-bucket operations, use copyFile() + deleteFile() directly
|
|
307
|
+
await s3.copyFile('source.csv', 'archive/source.csv', {
|
|
308
|
+
sourceBucket: 'source-bucket',
|
|
309
|
+
});
|
|
310
|
+
await s3.deleteFile('source.csv'); // Deletes from current bucket
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### File Archive
|
|
314
|
+
|
|
315
|
+
**archiveFile(sourcePath, archivePrefix?)** - Archive file with timestamp (template method from AbstractDataSource)
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
// Archive to default 'archive/' prefix
|
|
319
|
+
const archivePath = await s3.archiveFile('data/inventory.csv');
|
|
320
|
+
// Returns: 'archive/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
321
|
+
|
|
322
|
+
// Archive to custom prefix
|
|
323
|
+
const archivePath = await s3.archiveFile('data/inventory.csv', 'backup/2025/');
|
|
324
|
+
// Returns: 'backup/2025/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Parameters:**
|
|
328
|
+
|
|
329
|
+
- `sourcePath: string` - Source object key
|
|
330
|
+
- `archivePrefix?: string` - Archive directory prefix (default: 'archive/')
|
|
331
|
+
|
|
332
|
+
**Returns:** `Promise<string>` - The archive path where file was moved
|
|
333
|
+
|
|
334
|
+
**How It Works:**
|
|
335
|
+
1. Generates timestamped filename: `{archivePrefix}{timestamp}_{originalFilename}`
|
|
336
|
+
2. Moves file to archive location using moveFile()
|
|
337
|
+
3. Returns the full archive path
|
|
338
|
+
|
|
339
|
+
### Connection Validation
|
|
340
|
+
|
|
341
|
+
**validateConnection()** - Test S3 bucket access
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
const isValid = await s3.validateConnection();
|
|
345
|
+
if (!isValid) {
|
|
346
|
+
console.error('Cannot access S3 bucket');
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Writing Parquet Files
|
|
351
|
+
|
|
352
|
+
Both S3 and SFTP data sources support writing data records as Parquet format with automatic schema inference.
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { S3DataSource } from '@fluentcommerce/fc-connect-sdk';
|
|
356
|
+
|
|
357
|
+
const s3 = new S3DataSource(
|
|
358
|
+
{
|
|
359
|
+
type: 'S3_PARQUET',
|
|
360
|
+
connectionId: 's3-parquet-write',
|
|
361
|
+
name: 'S3 Parquet Write',
|
|
362
|
+
s3Config: config.s3Config,
|
|
363
|
+
},
|
|
364
|
+
logger
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
// Prepare data records
|
|
368
|
+
const records = [
|
|
369
|
+
{
|
|
370
|
+
id: 1,
|
|
371
|
+
name: 'Product A',
|
|
372
|
+
qty: 100,
|
|
373
|
+
price: 19.99,
|
|
374
|
+
active: true,
|
|
375
|
+
updatedAt: new Date(),
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
id: 2,
|
|
379
|
+
name: 'Product B',
|
|
380
|
+
qty: 50,
|
|
381
|
+
price: 29.99,
|
|
382
|
+
active: true,
|
|
383
|
+
updatedAt: new Date(),
|
|
384
|
+
},
|
|
385
|
+
];
|
|
386
|
+
|
|
387
|
+
// Write Parquet content with GZIP compression
|
|
388
|
+
const parquetBuffer = await s3.writeParquetContent(records, {
|
|
389
|
+
compression: 'GZIP',
|
|
390
|
+
rowGroupSize: 50000,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Upload to S3
|
|
394
|
+
await s3.uploadFile('output/inventory.parquet', parquetBuffer, {
|
|
395
|
+
contentType: 'application/octet-stream',
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**ParquetWriteOptions:**
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
interface ParquetWriteOptions {
|
|
403
|
+
compression?: 'UNCOMPRESSED' | 'GZIP' | 'SNAPPY' | 'LZO' | 'BROTLI';
|
|
404
|
+
schema?: Record<string, any>; // Custom schema, auto-infers if not provided
|
|
405
|
+
rowGroupSize?: number; // Default: 50000
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Automatic Schema Inference:**
|
|
410
|
+
|
|
411
|
+
The SDK automatically infers Parquet schema from your data types:
|
|
412
|
+
|
|
413
|
+
| JavaScript Type | Parquet Type |
|
|
414
|
+
| ------------------ | ------------------------- |
|
|
415
|
+
| `string` | UTF8 |
|
|
416
|
+
| `number` (integer) | INT64 |
|
|
417
|
+
| `number` (float) | DOUBLE |
|
|
418
|
+
| `boolean` | BOOLEAN |
|
|
419
|
+
| `Date` | TIMESTAMP_MILLIS |
|
|
420
|
+
| `null/undefined` | UTF8 (optional) |
|
|
421
|
+
| `object` | UTF8 (serialized as JSON) |
|
|
422
|
+
|
|
423
|
+
**Custom Schema Example:**
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
// Define custom schema for precise control
|
|
427
|
+
const customSchema = {
|
|
428
|
+
productRef: { type: 'UTF8' },
|
|
429
|
+
qty: { type: 'INT32' },
|
|
430
|
+
price: { type: 'DECIMAL', precision: 10, scale: 2 },
|
|
431
|
+
locationRef: { type: 'UTF8' },
|
|
432
|
+
updatedAt: { type: 'TIMESTAMP_MILLIS' },
|
|
433
|
+
active: { type: 'BOOLEAN', optional: true },
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const buffer = await s3.writeParquetContent(records, {
|
|
437
|
+
schema: customSchema,
|
|
438
|
+
compression: 'SNAPPY',
|
|
439
|
+
});
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Compression Options:**
|
|
443
|
+
|
|
444
|
+
- **UNCOMPRESSED**: No compression, fastest write, largest file
|
|
445
|
+
- **GZIP**: Good compression ratio, slower, widely compatible
|
|
446
|
+
- **SNAPPY**: Fast compression, good for large files
|
|
447
|
+
- **LZO**: Fast compression (requires native library)
|
|
448
|
+
- **BROTLI**: Best compression ratio, slower
|
|
449
|
+
|
|
450
|
+
**Complete Workflow Example:**
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import {
|
|
454
|
+
S3DataSource,
|
|
455
|
+
generateFileName,
|
|
456
|
+
generateFilePath,
|
|
457
|
+
generateDateSubdirectories,
|
|
458
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
459
|
+
|
|
460
|
+
// Fetch data from Fluent Commerce
|
|
461
|
+
const inventory = await client.graphql({
|
|
462
|
+
query: `query { inventoryPositions(first: 1000) { ... } }`,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Transform to records
|
|
466
|
+
const records = inventory.data.inventoryPositions.edges.map(e => ({
|
|
467
|
+
productRef: e.node.productRef,
|
|
468
|
+
locationRef: e.node.locationRef,
|
|
469
|
+
qty: e.node.qty,
|
|
470
|
+
updatedAt: new Date(),
|
|
471
|
+
}));
|
|
472
|
+
|
|
473
|
+
// Write as Parquet
|
|
474
|
+
const buffer = await s3.writeParquetContent(records, {
|
|
475
|
+
compression: 'GZIP',
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Generate file name with timestamp
|
|
479
|
+
const fileName = generateFileName('inventory', {
|
|
480
|
+
timestamp: 'yyyymmdd-hhmmss',
|
|
481
|
+
extension: 'parquet',
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Generate date-based path
|
|
485
|
+
const subdirs = generateDateSubdirectories();
|
|
486
|
+
const fullPath = generateFilePath('exports', fileName, subdirs);
|
|
487
|
+
// Result: 'exports/2025/10/06/inventory-20251006-123045.parquet'
|
|
488
|
+
|
|
489
|
+
// Upload to S3
|
|
490
|
+
await s3.uploadFile(fullPath, buffer);
|
|
491
|
+
|
|
492
|
+
console.log(`Exported ${records.length} records to ${fullPath}`);
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## SFTP Data Source
|
|
496
|
+
|
|
497
|
+
Direct SFTP file operations using `ssh2-sftp-client`. Works standalone without Versori dependencies.
|
|
498
|
+
|
|
499
|
+
### SFTP Constructor
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
import { SftpDataSource } from '@fluentcommerce/fc-connect-sdk';
|
|
503
|
+
|
|
504
|
+
const sftpConfig: SftpDataSourceConfig = {
|
|
505
|
+
type: 'SFTP_CSV', // or 'SFTP_JSON', 'SFTP_JSONL', 'SFTP_PARQUET'
|
|
506
|
+
connectionId: 'sftp-prod',
|
|
507
|
+
name: 'Production SFTP',
|
|
508
|
+
settings: {
|
|
509
|
+
// Direct connection credentials (no platform required)
|
|
510
|
+
host: 'sftp.example.com',
|
|
511
|
+
port: 22,
|
|
512
|
+
username: 'user',
|
|
513
|
+
password: 'password', // or use privateKey
|
|
514
|
+
privateKey: 'PEM string or Buffer', // Optional SSH key
|
|
515
|
+
passphrase: 'key passphrase', // Optional for encrypted keys
|
|
516
|
+
remotePath: '/data',
|
|
517
|
+
filePattern: '*.csv',
|
|
518
|
+
|
|
519
|
+
// Connection settings
|
|
520
|
+
connectionTimeout: 30000,
|
|
521
|
+
keepaliveInterval: 5000,
|
|
522
|
+
maxConnections: 5,
|
|
523
|
+
|
|
524
|
+
// Write operation settings
|
|
525
|
+
writeCreateDirectories: true,
|
|
526
|
+
writeOverwrite: false,
|
|
527
|
+
writePermissions: '0644',
|
|
528
|
+
},
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
const sftp = new SftpDataSource(sftpConfig, logger);
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Configuration Notes:**
|
|
535
|
+
|
|
536
|
+
`SftpDataSourceConfig` extends `DataSourceConfig`, which includes:
|
|
537
|
+
|
|
538
|
+
- `type: string` - Data source type ('SFTP_CSV', 'SFTP_JSON', 'SFTP_JSONL', or 'SFTP_PARQUET')
|
|
539
|
+
- `connectionId?: string` - Optional connection identifier
|
|
540
|
+
- `name?: string` - Optional descriptive name
|
|
541
|
+
- `connection?: SftpConnection` - **Optional** - Only required for Versori platform integration
|
|
542
|
+
|
|
543
|
+
**Authentication Options:**
|
|
544
|
+
|
|
545
|
+
- For **standalone use** (no Versori), provide `username` and either `password` or `privateKey` in settings
|
|
546
|
+
- For **Versori platform integration**, provide `connection` object (credentials managed by platform)
|
|
547
|
+
|
|
548
|
+
### Configuration Types
|
|
549
|
+
|
|
550
|
+
The SFTP data source uses ssh2-sftp-client internally:
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
interface SftpDataSourceConfig extends DataSourceConfig {
|
|
554
|
+
type: 'SFTP_CSV' | 'SFTP_JSON' | 'SFTP_JSONL' | 'SFTP_PARQUET';
|
|
555
|
+
connection?: SftpConnection; // Optional - only for Versori
|
|
556
|
+
settings: {
|
|
557
|
+
// Direct SFTP connection (no connection object needed)
|
|
558
|
+
host: string;
|
|
559
|
+
port?: number;
|
|
560
|
+
username?: string;
|
|
561
|
+
password?: string;
|
|
562
|
+
privateKey?: string | Buffer;
|
|
563
|
+
passphrase?: string;
|
|
564
|
+
remotePath: string;
|
|
565
|
+
filePattern: string;
|
|
566
|
+
|
|
567
|
+
// CSV settings
|
|
568
|
+
csvDelimiter?: string;
|
|
569
|
+
csvHeaders?: string[];
|
|
570
|
+
csvSkipEmptyLines?: boolean;
|
|
571
|
+
csvTrimValues?: boolean;
|
|
572
|
+
csvQuote?: string;
|
|
573
|
+
csvEscape?: string;
|
|
574
|
+
|
|
575
|
+
// JSON settings
|
|
576
|
+
jsonFormat?: 'json' | 'jsonl';
|
|
577
|
+
jsonValidate?: boolean;
|
|
578
|
+
jsonMaxDepth?: number;
|
|
579
|
+
jsonIndent?: number;
|
|
580
|
+
jsonSortKeys?: boolean;
|
|
581
|
+
|
|
582
|
+
// Parquet settings
|
|
583
|
+
parquetCompression?: 'none' | 'snappy' | 'gzip' | 'lz4';
|
|
584
|
+
parquetSchema?: Record<string, string>;
|
|
585
|
+
parquetRowGroupSize?: number;
|
|
586
|
+
|
|
587
|
+
// Write operation settings
|
|
588
|
+
writeCreateDirectories?: boolean;
|
|
589
|
+
writeOverwrite?: boolean;
|
|
590
|
+
writePermissions?: string;
|
|
591
|
+
|
|
592
|
+
// Connection settings
|
|
593
|
+
encoding?: string;
|
|
594
|
+
connectionTimeout?: number;
|
|
595
|
+
keepAliveInterval?: number;
|
|
596
|
+
maxConnections?: number;
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### SFTP File Listing
|
|
602
|
+
|
|
603
|
+
**listFiles(params?)** - List files on SFTP server with pattern matching and timestamp filtering
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
// List all files with default pattern
|
|
607
|
+
const files = await sftp.listFiles();
|
|
608
|
+
|
|
609
|
+
// List files with custom pattern (wildcard supported)
|
|
610
|
+
const files = await sftp.listFiles({
|
|
611
|
+
filePattern: '*.csv',
|
|
612
|
+
remotePath: '/data/inventory',
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// List files with wildcard patterns
|
|
616
|
+
const files = await sftp.listFiles({
|
|
617
|
+
filePattern: 'products_*.csv', // Match: products_2025.csv, products_test.csv
|
|
618
|
+
remotePath: '/data',
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// Incremental sync - files modified after timestamp
|
|
622
|
+
const files = await sftp.listFiles({
|
|
623
|
+
lastProcessedTimestamp: '2025-01-01T00:00:00Z',
|
|
624
|
+
filePattern: '*.csv',
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Filter by file name substring
|
|
628
|
+
const files = await sftp.listFiles({
|
|
629
|
+
fileName: 'inventory', // Matches files containing 'inventory'
|
|
630
|
+
remotePath: '/data',
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
// Returns: FileMetadata[]
|
|
634
|
+
// [
|
|
635
|
+
// {
|
|
636
|
+
// path: '/data/inventory/products.csv',
|
|
637
|
+
// name: 'products.csv',
|
|
638
|
+
// size: 1024,
|
|
639
|
+
// lastModified: '2025-01-15T10:30:00Z',
|
|
640
|
+
// contentType: 'text/csv',
|
|
641
|
+
// source: 'SFTP'
|
|
642
|
+
// }
|
|
643
|
+
// ]
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
**Parameters:**
|
|
647
|
+
|
|
648
|
+
- `remotePath?: string` - Remote directory path (defaults to config remotePath)
|
|
649
|
+
- `filePattern?: string` - Wildcard pattern for filtering (e.g., '\_.csv', 'products\_\_.json')
|
|
650
|
+
- `lastProcessedTimestamp?: string` - ISO timestamp for incremental sync
|
|
651
|
+
- `fileName?: string` - Filter by file name substring
|
|
652
|
+
|
|
653
|
+
**Pattern Matching:**
|
|
654
|
+
|
|
655
|
+
- `*.csv` - All CSV files
|
|
656
|
+
- `products_*.csv` - CSV files starting with 'products\_'
|
|
657
|
+
- `*_2025_*.json` - JSON files containing '_2025_'
|
|
658
|
+
- Case-insensitive matching
|
|
659
|
+
|
|
660
|
+
**Note:** Unlike S3, SFTP DOES support wildcard pattern matching natively.
|
|
661
|
+
|
|
662
|
+
### SFTP File Download
|
|
663
|
+
|
|
664
|
+
**downloadFile(path, options?)** - Download file content from SFTP server
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
// Download as text (default UTF-8)
|
|
668
|
+
const csvContent = await sftp.downloadFile('/data/inventory.csv');
|
|
669
|
+
// Returns: string
|
|
670
|
+
|
|
671
|
+
// Download as buffer (for binary files)
|
|
672
|
+
const buffer = await sftp.downloadFile('/data/file.parquet', {
|
|
673
|
+
asBuffer: true,
|
|
674
|
+
});
|
|
675
|
+
// Returns: Buffer
|
|
676
|
+
|
|
677
|
+
// Download with custom encoding
|
|
678
|
+
const content = await sftp.downloadFile('/data/file.txt', {
|
|
679
|
+
encoding: 'latin1',
|
|
680
|
+
});
|
|
681
|
+
// Returns: string
|
|
682
|
+
|
|
683
|
+
// Download with size limit
|
|
684
|
+
const content = await sftp.downloadFile('/data/large-file.csv', {
|
|
685
|
+
maxSize: 10 * 1024 * 1024, // 10 MB limit
|
|
686
|
+
});
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
**Parameters:**
|
|
690
|
+
|
|
691
|
+
- `path: string` - Remote file path
|
|
692
|
+
- `options.encoding?: string` - Text encoding (default: 'utf8')
|
|
693
|
+
- `options.asBuffer?: boolean` - Return Buffer instead of string
|
|
694
|
+
- `options.maxSize?: number` - Maximum file size in bytes
|
|
695
|
+
|
|
696
|
+
**Returns:**
|
|
697
|
+
|
|
698
|
+
- `Promise<string | Buffer>` - File content
|
|
699
|
+
|
|
700
|
+
### File Existence Checks
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
// Check if file exists
|
|
704
|
+
const fileExists = await sftp.fileExists('/data/inventory.csv');
|
|
705
|
+
|
|
706
|
+
// Check if directory exists
|
|
707
|
+
const dirExists = await sftp.directoryExists('/data/exports');
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### SFTP File Upload
|
|
711
|
+
|
|
712
|
+
**uploadContent(content, remotePath, options?)** - Upload content directly to SFTP server
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
// Upload text content
|
|
716
|
+
const csvContent = 'sku,qty\nPROD-001,100\nPROD-002,50';
|
|
717
|
+
await sftp.uploadFile('/data/inventory.csv', {
|
|
718
|
+
overwrite: true,
|
|
719
|
+
createDirectories: true,
|
|
720
|
+
}, csvContent);
|
|
721
|
+
|
|
722
|
+
// Upload binary content (Buffer)
|
|
723
|
+
const parquetBuffer = await sftp.writeParquetContent(records);
|
|
724
|
+
await sftp.uploadFile('/exports/data.parquet', {
|
|
725
|
+
overwrite: true,
|
|
726
|
+
encoding: 'binary',
|
|
727
|
+
}, parquetBuffer);
|
|
728
|
+
|
|
729
|
+
// Upload JSON with auto-directory creation
|
|
730
|
+
const jsonData = [
|
|
731
|
+
{ productRef: 'PROD-001', qty: 100 },
|
|
732
|
+
{ productRef: 'PROD-002', qty: 50 },
|
|
733
|
+
];
|
|
734
|
+
await sftp.uploadFile(null, 2, JSON.stringify(jsonData), '/exports/2025/01/15/data.json', {
|
|
735
|
+
createDirectories: true, // Creates /exports/2025/01/15/ if needed
|
|
736
|
+
permissions: '0644',
|
|
737
|
+
});
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
**Parameters:**
|
|
741
|
+
|
|
742
|
+
- `content: string | Buffer` - Content to upload
|
|
743
|
+
- `remotePath: string` - Destination file path
|
|
744
|
+
- `options.overwrite?: boolean` - Overwrite if file exists (default: false)
|
|
745
|
+
- `options.createDirectories?: boolean` - Create parent directories (default: false)
|
|
746
|
+
- `options.permissions?: string` - File permissions (default: '0644')
|
|
747
|
+
- `options.encoding?: string` - Text encoding (default: 'utf8')
|
|
748
|
+
|
|
749
|
+
**uploadFile(localPath, remotePath, options?)** - Upload local file to SFTP server
|
|
750
|
+
|
|
751
|
+
```typescript
|
|
752
|
+
// Upload local file
|
|
753
|
+
await sftp.uploadFile('/local/data/inventory.csv', '/remote/data/inventory.csv', {
|
|
754
|
+
overwrite: true,
|
|
755
|
+
createDirectories: true,
|
|
756
|
+
permissions: '0644',
|
|
757
|
+
});
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
**Parameters:**
|
|
761
|
+
|
|
762
|
+
- `localPath: string` - Local file path
|
|
763
|
+
- `remotePath: string` - Remote destination path
|
|
764
|
+
- `options` - Same as uploadContent
|
|
765
|
+
|
|
766
|
+
### Directory Operations
|
|
767
|
+
|
|
768
|
+
**createDirectory(remotePath, recursive, permissions?)** - Create directory on SFTP server
|
|
769
|
+
|
|
770
|
+
```typescript
|
|
771
|
+
// Create single directory
|
|
772
|
+
await sftp.createDirectory('/data/exports', false);
|
|
773
|
+
|
|
774
|
+
// Create directory tree
|
|
775
|
+
await sftp.createDirectory('/data/exports/2025/01/15', true, '0755');
|
|
776
|
+
|
|
777
|
+
// Check before creating
|
|
778
|
+
if (!(await sftp.directoryExists('/data/archive'))) {
|
|
779
|
+
await sftp.createDirectory('/data/archive', true);
|
|
780
|
+
}
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
**Parameters:**
|
|
784
|
+
|
|
785
|
+
- `remotePath: string` - Directory path to create
|
|
786
|
+
- `recursive: boolean` - Create parent directories (default: false)
|
|
787
|
+
- `permissions?: string` - Directory permissions (default: '0755')
|
|
788
|
+
|
|
789
|
+
### SFTP File Deletion
|
|
790
|
+
|
|
791
|
+
**deleteFile(remotePath)** - Delete file from SFTP server
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
// Delete single file
|
|
795
|
+
await sftp.deleteFile('/temp/processing.csv');
|
|
796
|
+
|
|
797
|
+
// Delete with existence check
|
|
798
|
+
if (await sftp.fileExists('/temp/old-file.csv')) {
|
|
799
|
+
await sftp.deleteFile('/temp/old-file.csv');
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// Bulk delete
|
|
803
|
+
const tempFiles = await sftp.listFiles({ remotePath: '/temp', filePattern: '*.tmp' });
|
|
804
|
+
for (const file of tempFiles) {
|
|
805
|
+
await sftp.deleteFile(file.path);
|
|
806
|
+
}
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
**Parameters:**
|
|
810
|
+
|
|
811
|
+
- `remotePath: string` - File path to delete
|
|
812
|
+
|
|
813
|
+
**Throws:** Error if file does not exist
|
|
814
|
+
|
|
815
|
+
### File Move (Atomic)
|
|
816
|
+
|
|
817
|
+
**moveFile(oldPath, newPath, overwrite?)** - Move/rename file on SFTP server
|
|
818
|
+
|
|
819
|
+
```typescript
|
|
820
|
+
// Move file between directories
|
|
821
|
+
await sftp.moveFile('/data/processing.csv', '/data/archive/processed.csv', false);
|
|
822
|
+
|
|
823
|
+
// Rename file in same directory
|
|
824
|
+
await sftp.moveFile(
|
|
825
|
+
'/data/temp_file.csv',
|
|
826
|
+
'/data/inventory_2025.csv',
|
|
827
|
+
true // overwrite if exists
|
|
828
|
+
);
|
|
829
|
+
|
|
830
|
+
// Archive processed files
|
|
831
|
+
const files = await sftp.listFiles({ remotePath: '/data/inbox' });
|
|
832
|
+
for (const file of files) {
|
|
833
|
+
const archivePath = `/data/archive/${file.name}`;
|
|
834
|
+
await sftp.moveFile(file.path, archivePath, false);
|
|
835
|
+
}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
**Parameters:**
|
|
839
|
+
|
|
840
|
+
- `oldPath: string` - Current file path
|
|
841
|
+
- `newPath: string` - New file path
|
|
842
|
+
- `overwrite?: boolean` - Overwrite destination (default: false)
|
|
843
|
+
|
|
844
|
+
**Important:** SFTP moveFile() is ATOMIC - single server-side operation (unlike S3)
|
|
845
|
+
|
|
846
|
+
### SFTP File Copy
|
|
847
|
+
|
|
848
|
+
**copyFile(sourcePath, destPath, overwrite?)** - Copy file on SFTP server
|
|
849
|
+
|
|
850
|
+
```typescript
|
|
851
|
+
// Create backup
|
|
852
|
+
await sftp.copyFile('/data/inventory.csv', '/backup/inventory_backup.csv', true);
|
|
853
|
+
|
|
854
|
+
// Copy to multiple locations
|
|
855
|
+
const sourceFile = '/data/master.csv';
|
|
856
|
+
const destinations = ['/backup/master.csv', '/archive/2025/master.csv', '/staging/master.csv'];
|
|
857
|
+
|
|
858
|
+
for (const dest of destinations) {
|
|
859
|
+
await sftp.copyFile(sourceFile, dest, true);
|
|
860
|
+
}
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
**Parameters:**
|
|
864
|
+
|
|
865
|
+
- `sourcePath: string` - Source file path
|
|
866
|
+
- `destPath: string` - Destination file path
|
|
867
|
+
- `overwrite?: boolean` - Overwrite destination (default: false)
|
|
868
|
+
|
|
869
|
+
**Note:** Implemented as download + upload (SFTP protocol has no native copy command)
|
|
870
|
+
|
|
871
|
+
### SFTP File Archive
|
|
872
|
+
|
|
873
|
+
**archiveFile(sourcePath, archivePrefix?)** - Archive file with timestamp (template method from AbstractDataSource)
|
|
874
|
+
|
|
875
|
+
```typescript
|
|
876
|
+
// Archive to default 'archive/' prefix
|
|
877
|
+
const archivePath = await sftp.archiveFile('/data/inventory.csv');
|
|
878
|
+
// Returns: 'archive/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
879
|
+
|
|
880
|
+
// Archive to custom prefix
|
|
881
|
+
const archivePath = await sftp.archiveFile('/data/inventory.csv', '/backup/2025/');
|
|
882
|
+
// Returns: '/backup/2025/2025-10-29T12-30-45-123Z_inventory.csv'
|
|
883
|
+
|
|
884
|
+
// Archive processed files after ingestion
|
|
885
|
+
const files = await sftp.listFiles({ remotePath: '/data/inbox' });
|
|
886
|
+
for (const file of files) {
|
|
887
|
+
await processFile(file);
|
|
888
|
+
const archivePath = await sftp.archiveFile(file.path, '/data/archive/');
|
|
889
|
+
console.log(`Archived ${file.name} to ${archivePath}`);
|
|
890
|
+
}
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
**Parameters:**
|
|
894
|
+
|
|
895
|
+
- `sourcePath: string` - Source file path
|
|
896
|
+
- `archivePrefix?: string` - Archive directory prefix (default: 'archive/')
|
|
897
|
+
|
|
898
|
+
**Returns:** `Promise<string>` - The archive path where file was moved
|
|
899
|
+
|
|
900
|
+
**How It Works:**
|
|
901
|
+
1. Generates timestamped filename: `{archivePrefix}{timestamp}_{originalFilename}`
|
|
902
|
+
2. Moves file to archive location using moveFile()
|
|
903
|
+
3. Returns the full archive path
|
|
904
|
+
|
|
905
|
+
**Important:** SFTP archiveFile() is atomic since it uses SFTP's atomic moveFile() operation.
|
|
906
|
+
|
|
907
|
+
### Multi-Format Support
|
|
908
|
+
|
|
909
|
+
#### CSV Operations
|
|
910
|
+
|
|
911
|
+
```typescript
|
|
912
|
+
// Write CSV content with custom options
|
|
913
|
+
const csvRecords = [
|
|
914
|
+
{ sku: 'PROD-001', qty: 100, location: 'DC-001' },
|
|
915
|
+
{ sku: 'PROD-002', qty: 50, location: 'DC-002' },
|
|
916
|
+
];
|
|
917
|
+
|
|
918
|
+
const csvContent = sftp.writeCsvContent(csvRecords, {
|
|
919
|
+
delimiter: ',',
|
|
920
|
+
headers: ['sku', 'qty', 'location'],
|
|
921
|
+
includeHeader: true,
|
|
922
|
+
quote: '"',
|
|
923
|
+
escape: '\\',
|
|
924
|
+
encoding: 'utf8',
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
// Upload CSV content
|
|
928
|
+
await sftp.uploadFile('/data/inventory.csv', csvContent);
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
#### JSON Operations
|
|
932
|
+
|
|
933
|
+
```typescript
|
|
934
|
+
// Write JSON content
|
|
935
|
+
const jsonRecords = [
|
|
936
|
+
{ productRef: 'PROD-001', quantity: 100 },
|
|
937
|
+
{ productRef: 'PROD-002', quantity: 50 },
|
|
938
|
+
];
|
|
939
|
+
|
|
940
|
+
const jsonContent = sftp.writeJsonContent(jsonRecords, {
|
|
941
|
+
format: 'json', // or 'jsonl' for JSON Lines
|
|
942
|
+
indent: 2,
|
|
943
|
+
sortKeys: true,
|
|
944
|
+
replacer: (key, value) => (key === 'quantity' ? Number(value) : value),
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// Upload JSON content
|
|
948
|
+
await sftp.uploadFile('/data/products.json', jsonContent);
|
|
949
|
+
|
|
950
|
+
// Parse JSON content from downloaded file
|
|
951
|
+
const downloadedJson = await sftp.downloadFile('products.json');
|
|
952
|
+
const parsedRecords = sftp.parseJsonContent(downloadedJson, {
|
|
953
|
+
format: 'json',
|
|
954
|
+
validate: true,
|
|
955
|
+
maxDepth: 10,
|
|
956
|
+
});
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
#### JSON Lines Support
|
|
960
|
+
|
|
961
|
+
```typescript
|
|
962
|
+
// Write JSON Lines (JSONL) format
|
|
963
|
+
const jsonlContent = sftp.writeJsonContent(records, {
|
|
964
|
+
format: 'jsonl',
|
|
965
|
+
});
|
|
966
|
+
// Produces:
|
|
967
|
+
// {"id":1,"name":"Product A"}
|
|
968
|
+
// {"id":2,"name":"Product B"}
|
|
969
|
+
|
|
970
|
+
// Parse JSONL content
|
|
971
|
+
const jsonlRecords = sftp.parseJsonContent(jsonlContent, {
|
|
972
|
+
format: 'jsonl',
|
|
973
|
+
});
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
**Parquet Operations (SFTP)**
|
|
977
|
+
|
|
978
|
+
- Read/parse Parquet: Not implemented yet in SFTP data source. Attempting to call `parseParquetContent` will throw until hyparquet integration is added for SFTP. Use S3→download→parsers for Parquet reads.
|
|
979
|
+
- Write Parquet: Implemented via `writeParquetContent(records, options)` producing a Buffer that you can upload with `uploadContent`.
|
|
980
|
+
|
|
981
|
+
```typescript
|
|
982
|
+
// Write Parquet content (supported)
|
|
983
|
+
const parquetBuffer = await sftp.writeParquetContent(records, {
|
|
984
|
+
compression: 'gzip',
|
|
985
|
+
parquetSchema: {
|
|
986
|
+
productRef: 'string',
|
|
987
|
+
quantity: 'int32',
|
|
988
|
+
price: 'double',
|
|
989
|
+
},
|
|
990
|
+
parquetRowGroupSize: 1000,
|
|
991
|
+
});
|
|
992
|
+
await sftp.uploadFile('/exports/data.parquet', { overwrite: true }, parquetBuffer);
|
|
993
|
+
|
|
994
|
+
// Read Parquet content (not yet supported on SFTP data source)
|
|
995
|
+
// const records = await sftp.parseParquetContent(buffer, fileMetadata); // ❌ throws
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
### Error Handling
|
|
999
|
+
|
|
1000
|
+
The SFTP data source provides complete error handling:
|
|
1001
|
+
|
|
1002
|
+
```typescript
|
|
1003
|
+
try {
|
|
1004
|
+
await sftp.uploadFile(localPath, remotePath);
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
if (error instanceof DataSourceError) {
|
|
1007
|
+
console.error(`SFTP Error [${error.code}]:`, error.message);
|
|
1008
|
+
console.error('Context:', error.context);
|
|
1009
|
+
console.error('Operation:', error.operation);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
### Connection Management
|
|
1015
|
+
|
|
1016
|
+
The SFTP data source includes sophisticated connection management:
|
|
1017
|
+
|
|
1018
|
+
```typescript
|
|
1019
|
+
// Get connection information
|
|
1020
|
+
const connectionInfo = sftp.getConnectionInfo();
|
|
1021
|
+
console.log('Pool size:', connectionInfo.connectionPoolSize);
|
|
1022
|
+
console.log('Max pool size:', connectionInfo.maxPoolSize);
|
|
1023
|
+
|
|
1024
|
+
// Connection pooling is handled automatically
|
|
1025
|
+
// Multiple operations reuse connections efficiently
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
## Complete Methods Reference
|
|
1029
|
+
|
|
1030
|
+
### S3 Data Source Methods
|
|
1031
|
+
|
|
1032
|
+
**File Operations:**
|
|
1033
|
+
|
|
1034
|
+
- `listFiles(params?): Promise<FileMetadata[]>` - List objects with filtering
|
|
1035
|
+
- `downloadFile(key, options?): Promise<string | Buffer>` - Download object content
|
|
1036
|
+
- `uploadFile(key, content, options?): Promise<void>` - Upload object (required abstract method)
|
|
1037
|
+
- `deleteFile(key): Promise<void>` - Delete object
|
|
1038
|
+
- `copyFile(sourceKey, destKey, options?): Promise<void>` - Copy object (supports cross-bucket)
|
|
1039
|
+
- `moveFile(sourcePath, destPath, deleteSource?): Promise<void>` - Move object within same bucket (template method)
|
|
1040
|
+
- `archiveFile(sourcePath, archivePrefix?): Promise<string>` - Archive file with timestamp (template method)
|
|
1041
|
+
- `validateConnection(): Promise<boolean>` - Test bucket access
|
|
1042
|
+
- `writeParquetContent(records, options?): Promise<Buffer>` - Write Parquet format
|
|
1043
|
+
|
|
1044
|
+
### SFTP Data Source Methods
|
|
1045
|
+
|
|
1046
|
+
**File Operations:**
|
|
1047
|
+
|
|
1048
|
+
- `listFiles(params?): Promise<FileMetadata[]>` - List files with wildcard pattern matching
|
|
1049
|
+
- `downloadFile(path, options?): Promise<string | Buffer>` - Download file content
|
|
1050
|
+
- `uploadFile(remotePath, content, options?): Promise<void>` - Upload content (required abstract method)
|
|
1051
|
+
- `deleteFile(remotePath): Promise<void>` - Delete file
|
|
1052
|
+
- `moveFile(oldPath, newPath, overwrite?): Promise<void>` - Move/rename file (atomic, template method)
|
|
1053
|
+
- `copyFile(sourcePath, destPath, overwrite?): Promise<void>` - Copy file
|
|
1054
|
+
- `archiveFile(sourcePath, archivePrefix?): Promise<string>` - Archive file with timestamp (template method)
|
|
1055
|
+
- `fileExists(remotePath): Promise<boolean>` - Check if file exists
|
|
1056
|
+
- `directoryExists(remotePath): Promise<boolean>` - Check if directory exists
|
|
1057
|
+
- `createDirectory(remotePath, recursive, permissions?): Promise<void>` - Create directory
|
|
1058
|
+
- `validateConnection(): Promise<boolean>` - Test SFTP connection
|
|
1059
|
+
- `dispose(): Promise<void>` - Clean up connections
|
|
1060
|
+
|
|
1061
|
+
**Format Operations:**
|
|
1062
|
+
|
|
1063
|
+
- `parseCsvContent(csvContent, fileMetadata): CsvRecord[]` - Parse CSV string
|
|
1064
|
+
- `writeCsvContent(records, options?): string` - Generate CSV string
|
|
1065
|
+
- `parseJsonContent(jsonContent, fileMetadata, options?): Record<string, unknown>[]` - Parse JSON/JSONL
|
|
1066
|
+
- `writeJsonContent(records, options?): string` - Generate JSON/JSONL string
|
|
1067
|
+
- `parseParquetContent(buffer, fileMetadata): Promise<ParquetDataRecord[]>` - Not supported; currently throws
|
|
1068
|
+
- `writeParquetContent(records, options?): Promise<Buffer>` - Generate Parquet buffer
|
|
1069
|
+
|
|
1070
|
+
**Utility Methods:**
|
|
1071
|
+
|
|
1072
|
+
- `getConnectionInfo(): ConnectionInfo` - Get connection pool status
|
|
1073
|
+
|
|
1074
|
+
## See Also
|
|
1075
|
+
|
|
1076
|
+
- [Module 07: Parsers](./api-reference-07-parsers.md) - Format-specific parsing
|
|
1077
|
+
- [Module 05: Extraction](../../extraction/extraction-readme.md) - Using data sources for extraction
|
|
1078
|
+
- [Module 10: Utilities](./api-reference-10-utilities.md) - Helper functions
|
|
1079
|
+
- [Getting Started Guide](../../../00-START-HERE/getting-started.md) - Basic setup
|
|
1080
|
+
|
|
1081
|
+
---
|
|
1082
|
+
|
|
1083
|
+
**[← Previous: Services](./api-reference-05-services.md)** | **[API Reference Home](../api-reference-readme.md)** | **[Next: Parsers →](./api-reference-07-parsers.md)**
|