multiwoven-integrations 0.1.41 → 0.1.42
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.
- checksums.yaml +4 -4
- data/lib/multiwoven/integrations/core/utils.rb +2 -1
- data/lib/multiwoven/integrations/destination/sftp/client.rb +124 -0
- data/lib/multiwoven/integrations/destination/sftp/config/catalog.json +16 -0
- data/lib/multiwoven/integrations/destination/sftp/config/meta.json +16 -0
- data/lib/multiwoven/integrations/destination/sftp/config/spec.json +44 -0
- data/lib/multiwoven/integrations/destination/sftp/icon.svg +1 -0
- data/lib/multiwoven/integrations/protocol/protocol.rb +2 -0
- data/lib/multiwoven/integrations/rollout.rb +2 -1
- data/lib/multiwoven/integrations.rb +4 -0
- metadata +35 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: eee51b7ba03e877f2765da694f9ca7b4ede8e44e07ca74931d808f79fb828c06
         | 
| 4 | 
            +
              data.tar.gz: 21a23a656e09175222172eea24e562c95ccc97e7bebe92443cc60678d68050bf
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 388d743e298e3296fbd9bd12e5d29037d72bf4912f93ae8ae8b9d7f5285dbb2d39f39f1500f6ee3b6214e186564287eec8c3fe14d66f55cc53861585e3929e33
         | 
| 7 | 
            +
              data.tar.gz: e527726e1e69c57c07d7d6ab28194f2a84dfbbffb941f61e2b5fca927cecf486edcb7fa2cecbbcc8ccc1713c396e1723161e5ea55f0cc8d310ce2d888f6de845
         | 
| @@ -95,7 +95,8 @@ module Multiwoven | |
| 95 95 | 
             
                      request_rate_limit: stream_json["request_rate_limit"].to_i,
         | 
| 96 96 | 
             
                      request_rate_limit_unit: stream_json["request_rate_limit_unit"] || "minute",
         | 
| 97 97 | 
             
                      request_rate_concurrency: stream_json["request_rate_concurrency"].to_i,
         | 
| 98 | 
            -
                      supported_sync_modes: stream_json["supported_sync_modes"]
         | 
| 98 | 
            +
                      supported_sync_modes: stream_json["supported_sync_modes"],
         | 
| 99 | 
            +
                      schema_mode: stream_json["schema_mode"]
         | 
| 99 100 | 
             
                    )
         | 
| 100 101 | 
             
                  end
         | 
| 101 102 | 
             
                end
         | 
| @@ -0,0 +1,124 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Multiwoven::Integrations::Destination
         | 
| 4 | 
            +
              module Sftp
         | 
| 5 | 
            +
                include Multiwoven::Integrations::Core
         | 
| 6 | 
            +
                class Client < DestinationConnector
         | 
| 7 | 
            +
                  prepend Multiwoven::Integrations::Core::Fullrefresher
         | 
| 8 | 
            +
                  prepend Multiwoven::Integrations::Core::RateLimiter
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def check_connection(connection_config)
         | 
| 11 | 
            +
                    connection_config = connection_config.with_indifferent_access
         | 
| 12 | 
            +
                    with_sftp_client(connection_config) do |sftp|
         | 
| 13 | 
            +
                      stream = SecureRandom.uuid
         | 
| 14 | 
            +
                      test_path = "/path/to/test/#{stream}"
         | 
| 15 | 
            +
                      test_file_operations(sftp, test_path)
         | 
| 16 | 
            +
                      return success_status
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  rescue StandardError => e
         | 
| 19 | 
            +
                    handle_exception("SFTP:CHECK_CONNECTION:EXCEPTION", "error", e)
         | 
| 20 | 
            +
                    failure_status(e)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def discover(_connection_config = nil)
         | 
| 24 | 
            +
                    catalog_json = read_json(CATALOG_SPEC_PATH)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    catalog = build_catalog(catalog_json)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    catalog.to_multiwoven_message
         | 
| 29 | 
            +
                  rescue StandardError => e
         | 
| 30 | 
            +
                    handle_exception(
         | 
| 31 | 
            +
                      "SFTP:DISCOVER:EXCEPTION",
         | 
| 32 | 
            +
                      "error",
         | 
| 33 | 
            +
                      e
         | 
| 34 | 
            +
                    )
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def write(sync_config, records, _action = "insert")
         | 
| 38 | 
            +
                    connection_config = sync_config.destination.connection_specification.with_indifferent_access
         | 
| 39 | 
            +
                    file_path = generate_file_path(sync_config)
         | 
| 40 | 
            +
                    csv_content = generate_csv_content(records)
         | 
| 41 | 
            +
                    write_success = 0
         | 
| 42 | 
            +
                    write_failure = 0
         | 
| 43 | 
            +
                    # 10000 records in single
         | 
| 44 | 
            +
                    with_sftp_client(connection_config) do |sftp|
         | 
| 45 | 
            +
                      sftp.file.open(file_path, "w") { |file| file.puts(csv_content) }
         | 
| 46 | 
            +
                      write_success += records.size
         | 
| 47 | 
            +
                    rescue StandardError => e
         | 
| 48 | 
            +
                      handle_exception("SFTP:RECORD:WRITE:EXCEPTION", "error", e)
         | 
| 49 | 
            +
                      write_failure += records.size
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                    tracking_message(write_success, write_failure)
         | 
| 52 | 
            +
                  rescue StandardError => e
         | 
| 53 | 
            +
                    handle_exception(
         | 
| 54 | 
            +
                      "SFTP:WRITE:EXCEPTION",
         | 
| 55 | 
            +
                      "error",
         | 
| 56 | 
            +
                      e
         | 
| 57 | 
            +
                    )
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def clear_all_records(sync_config)
         | 
| 61 | 
            +
                    connection_specification = sync_config.destination.connection_specification.with_indifferent_access
         | 
| 62 | 
            +
                    with_sftp_client(connection_specification) do |sftp|
         | 
| 63 | 
            +
                      files = sftp.dir.glob(connection_specification[:destination_path], "*")
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      files.each do |file|
         | 
| 66 | 
            +
                        sftp.remove!(File.join(connection_specification[:destination_path], file.name))
         | 
| 67 | 
            +
                      end
         | 
| 68 | 
            +
                      if sftp.dir.entries(connection_specification[:destination_path]).size == 2
         | 
| 69 | 
            +
                        control_message("Successfully cleared data.", "succeeded")
         | 
| 70 | 
            +
                      else
         | 
| 71 | 
            +
                        control_message("Failed to clear data.", "failed")
         | 
| 72 | 
            +
                      end
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                  rescue StandardError => e
         | 
| 75 | 
            +
                    control_message(e.message, "failed")
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  private
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def generate_file_path(sync_config)
         | 
| 81 | 
            +
                    timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
         | 
| 82 | 
            +
                    file_name = "#{sync_config.stream.name}_#{timestamp}.csv"
         | 
| 83 | 
            +
                    File.join(sync_config.destination.connection_specification[:destination_path], file_name)
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  def generate_csv_content(records)
         | 
| 87 | 
            +
                    CSV.generate do |csv|
         | 
| 88 | 
            +
                      headers = records.first.keys
         | 
| 89 | 
            +
                      csv << headers
         | 
| 90 | 
            +
                      records.each { |record| csv << record.values_at(*headers) }
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  def tracking_message(success, failure)
         | 
| 95 | 
            +
                    Multiwoven::Integrations::Protocol::TrackingMessage.new(
         | 
| 96 | 
            +
                      success: success, failed: failure
         | 
| 97 | 
            +
                    ).to_multiwoven_message
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  def with_sftp_client(connection_config, &block)
         | 
| 101 | 
            +
                    Net::SFTP.start(
         | 
| 102 | 
            +
                      connection_config[:host],
         | 
| 103 | 
            +
                      connection_config[:username],
         | 
| 104 | 
            +
                      password: connection_config[:password],
         | 
| 105 | 
            +
                      port: connection_config.fetch(:port, 22), &block
         | 
| 106 | 
            +
                    )
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  def test_file_operations(sftp, test_path)
         | 
| 110 | 
            +
                    sftp.file.open(test_path, "w") { |file| file.puts("connection_check") }
         | 
| 111 | 
            +
                    sftp.remove!(test_path)
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  def control_message(message, status)
         | 
| 115 | 
            +
                    ControlMessage.new(
         | 
| 116 | 
            +
                      type: "full_refresh",
         | 
| 117 | 
            +
                      emitted_at: Time.now.to_i,
         | 
| 118 | 
            +
                      status: ConnectionStatusType[status],
         | 
| 119 | 
            +
                      meta: { detail: message }
         | 
| 120 | 
            +
                    ).to_multiwoven_message
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "request_rate_limit": 600,
         | 
| 3 | 
            +
              "request_rate_limit_unit": "minute",
         | 
| 4 | 
            +
              "request_rate_concurrency": 10,
         | 
| 5 | 
            +
              "streams": [
         | 
| 6 | 
            +
                {
         | 
| 7 | 
            +
                  "name": "sftp",
         | 
| 8 | 
            +
                  "batch_support": true,
         | 
| 9 | 
            +
                  "batch_size": 10000,
         | 
| 10 | 
            +
                  "action": "create",
         | 
| 11 | 
            +
                  "schema_mode": ["schemaless"],
         | 
| 12 | 
            +
                  "json_schema": {},
         | 
| 13 | 
            +
                  "supported_sync_modes": ["full_refresh","incremental"]
         | 
| 14 | 
            +
                }
         | 
| 15 | 
            +
              ]
         | 
| 16 | 
            +
            }
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "data": {
         | 
| 3 | 
            +
                "name": "Sftp",
         | 
| 4 | 
            +
                "title": "SFTP",
         | 
| 5 | 
            +
                "connector_type": "destination",
         | 
| 6 | 
            +
                "connectorSubtype": "file",
         | 
| 7 | 
            +
                "category": "File Storage",
         | 
| 8 | 
            +
                "documentation_url": "https://docs.mutliwoven.com",
         | 
| 9 | 
            +
                "github_issue_label": "destination-sftp",
         | 
| 10 | 
            +
                "icon": "icon.svg",
         | 
| 11 | 
            +
                "license": "MIT",
         | 
| 12 | 
            +
                "release_stage": "alpha",
         | 
| 13 | 
            +
                "support_level": "community",
         | 
| 14 | 
            +
                "tags": ["language:ruby", "multiwoven"]
         | 
| 15 | 
            +
              }
         | 
| 16 | 
            +
            }
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "documentation_url": "https://docs.multiwoven.com/integrations/destination/klaviyo",
         | 
| 3 | 
            +
              "stream_type": "static",
         | 
| 4 | 
            +
              "connection_specification": {
         | 
| 5 | 
            +
                "$schema": "http://json-schema.org/draft-07/schema#",
         | 
| 6 | 
            +
                "title": "SFTP",
         | 
| 7 | 
            +
                "required": ["host", "username", "password", "destination_path"],
         | 
| 8 | 
            +
                "properties": {
         | 
| 9 | 
            +
                  "host": {
         | 
| 10 | 
            +
                    "title": "Host",
         | 
| 11 | 
            +
                    "description": "Hostname of the SFTP server.",
         | 
| 12 | 
            +
                    "type": "string",
         | 
| 13 | 
            +
                    "order": 0
         | 
| 14 | 
            +
                  },
         | 
| 15 | 
            +
                  "port": {
         | 
| 16 | 
            +
                    "title": "Port",
         | 
| 17 | 
            +
                    "description": "Port of the SFTP server.",
         | 
| 18 | 
            +
                    "type": "integer",
         | 
| 19 | 
            +
                    "minimum": 0,
         | 
| 20 | 
            +
                    "maximum": 65536,
         | 
| 21 | 
            +
                    "default": 22,
         | 
| 22 | 
            +
                    "order": 1
         | 
| 23 | 
            +
                  },
         | 
| 24 | 
            +
                  "username": {
         | 
| 25 | 
            +
                    "title": "User Name",
         | 
| 26 | 
            +
                    "description": "Username to use to access the SFTP server.",
         | 
| 27 | 
            +
                    "type": "string",
         | 
| 28 | 
            +
                    "order": 2
         | 
| 29 | 
            +
                  },
         | 
| 30 | 
            +
                  "password": {
         | 
| 31 | 
            +
                    "title": "Password",
         | 
| 32 | 
            +
                    "description": "Password associated with the username.",
         | 
| 33 | 
            +
                    "type": "string",
         | 
| 34 | 
            +
                    "order": 3
         | 
| 35 | 
            +
                  },
         | 
| 36 | 
            +
                  "destination_path": {
         | 
| 37 | 
            +
                    "title": "Destination path",
         | 
| 38 | 
            +
                    "type": "string",
         | 
| 39 | 
            +
                    "description": "Path to the directory where files will be written.",
         | 
| 40 | 
            +
                    "order": 4
         | 
| 41 | 
            +
                  }
         | 
| 42 | 
            +
                }
         | 
| 43 | 
            +
              }
         | 
| 44 | 
            +
            }
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            <svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="none"><g clip-path="url(#a)"><path fill="#615EFF" d="M200.745 218.706a12.051 12.051 0 0 1-3.483 8.475 11.837 11.837 0 0 1-8.4 3.514H62.072c-3.15 0-6.173-1.261-8.403-3.507a12.053 12.053 0 0 1-3.49-8.472V31.485a12.08 12.08 0 0 1 .903-4.593 11.996 11.996 0 0 1 2.578-3.894 11.875 11.875 0 0 1 3.86-2.6 11.791 11.791 0 0 1 4.552-.912h81.371l57.302 58.96v140.26Z"/><path fill="#fff" d="M83.868 156.832c-.142-1.429-.75-2.539-1.822-3.33-1.074-.792-2.53-1.187-4.37-1.187-1.25 0-2.305.177-3.166.531-.861.343-1.522.821-1.981 1.435a3.457 3.457 0 0 0-.673 2.09c-.023.65.112 1.217.407 1.701.307.484.725.903 1.256 1.258.53.342 1.144.643 1.84.903a19.02 19.02 0 0 0 2.229.638l3.255.779c1.58.354 3.03.827 4.352 1.417 1.32.591 2.464 1.317 3.431 2.179a9.057 9.057 0 0 1 2.247 3.047c.542 1.169.82 2.509.831 4.021-.011 2.22-.578 4.145-1.698 5.775-1.109 1.617-2.712 2.875-4.811 3.773-2.088.885-4.606 1.328-7.554 1.328-2.925 0-5.472-.449-7.642-1.346-2.158-.898-3.845-2.226-5.06-3.986-1.202-1.771-1.833-3.962-1.892-6.572h7.412c.082 1.217.43 2.232 1.044 3.047.625.803 1.456 1.411 2.494 1.825 1.05.401 2.235.602 3.555.602 1.298 0 2.424-.189 3.38-.567.966-.378 1.715-.903 2.246-1.576.53-.673.796-1.447.796-2.321 0-.815-.242-1.5-.725-2.055-.472-.555-1.168-1.027-2.088-1.417-.908-.39-2.022-.744-3.343-1.063l-3.945-.992c-3.054-.744-5.466-1.907-7.235-3.489-1.77-1.583-2.648-3.714-2.636-6.395-.012-2.196.572-4.116 1.751-5.757 1.192-1.641 2.825-2.923 4.9-3.844 2.076-.921 4.435-1.382 7.076-1.382 2.69 0 5.036.461 7.04 1.382 2.018.921 3.586 2.203 4.706 3.844 1.12 1.641 1.699 3.543 1.734 5.704h-7.341Zm12.988 25.844v-36.278h23.988v6.324h-16.328v8.645h14.736v6.324h-14.736v14.985h-7.66Zm27.76-29.954v-6.324h29.754v6.324h-11.091v29.954h-7.571v-29.954h-11.092Zm34.654 29.954v-36.278h14.294c2.748 0 5.089.526 7.023 1.577 1.934 1.039 3.408 2.486 4.422 4.34 1.026 1.842 1.539 3.968 1.539 6.377s-.519 4.535-1.557 6.377c-1.037 1.842-2.541 3.277-4.51 4.304-1.958 1.028-4.329 1.541-7.112 1.541h-9.11v-6.146h7.872c1.474 0 2.689-.254 3.644-.762.967-.52 1.686-1.234 2.158-2.143.484-.921.725-1.978.725-3.171 0-1.205-.241-2.256-.725-3.153-.472-.91-1.191-1.612-2.158-2.108-.967-.508-2.194-.762-3.679-.762h-5.166v30.007h-7.66Z"/><path fill="#1A194D" d="m149.75 76.907 50.996 49.177V78.101h-45.173a11.33 11.33 0 0 1-5.643-1.433l-.18.24Z" opacity=".3"/><path fill="#C5C4FF" d="M200.746 78.35h-45.297a11.836 11.836 0 0 1-8.399-3.514 12.055 12.055 0 0 1-3.484-8.475v-47.2l57.18 59.189Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M50 19h151v212H50z"/></clipPath></defs></svg>
         | 
| @@ -24,6 +24,7 @@ module Multiwoven | |
| 24 24 | 
             
                )
         | 
| 25 25 | 
             
                LogLevel = Types::String.enum("fatal", "error", "warn", "info", "debug", "trace")
         | 
| 26 26 | 
             
                RequestRateLimitingUnit = Types::String.default("minute").enum("minute", "hour", "day")
         | 
| 27 | 
            +
                SchemaMode = Types::String.enum("schema", "schemaless")
         | 
| 27 28 |  | 
| 28 29 | 
             
                class ProtocolModel < Dry::Struct
         | 
| 29 30 | 
             
                  extend Multiwoven::Integrations::Core::Utils
         | 
| @@ -124,6 +125,7 @@ module Multiwoven | |
| 124 125 | 
             
                  attribute? :request_rate_limit, Types::Integer
         | 
| 125 126 | 
             
                  attribute? :request_rate_limit_unit, RequestRateLimitingUnit
         | 
| 126 127 | 
             
                  attribute? :request_rate_concurrency, Types::Integer
         | 
| 128 | 
            +
                  attribute? :schema_mode, Types::Array.of(SchemaMode).optional.default(["schema"])
         | 
| 127 129 |  | 
| 128 130 | 
             
                  def rate_limit_unit_seconds
         | 
| 129 131 | 
             
                    case request_rate_limit_unit
         | 
| @@ -19,6 +19,9 @@ require "hubspot-api-client" | |
| 19 19 | 
             
            require "google/apis/sheets_v4"
         | 
| 20 20 | 
             
            require "stringio"
         | 
| 21 21 | 
             
            require "stripe"
         | 
| 22 | 
            +
            require "net/sftp"
         | 
| 23 | 
            +
            require "csv"
         | 
| 24 | 
            +
            require "securerandom"
         | 
| 22 25 |  | 
| 23 26 | 
             
            # Service
         | 
| 24 27 | 
             
            require_relative "integrations/config"
         | 
| @@ -54,6 +57,7 @@ require_relative "integrations/destination/google_sheets/client" | |
| 54 57 | 
             
            require_relative "integrations/destination/airtable/client"
         | 
| 55 58 | 
             
            require_relative "integrations/destination/stripe/client"
         | 
| 56 59 | 
             
            require_relative "integrations/destination/salesforce_consumer_goods_cloud/client"
         | 
| 60 | 
            +
            require_relative "integrations/destination/sftp/client"
         | 
| 57 61 |  | 
| 58 62 | 
             
            module Multiwoven
         | 
| 59 63 | 
             
              module Integrations
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: multiwoven-integrations
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.1. | 
| 4 | 
            +
              version: 0.1.42
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Subin T P
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024-03- | 
| 11 | 
            +
            date: 2024-03-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -38,6 +38,20 @@ dependencies: | |
| 38 38 | 
             
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 40 | 
             
                    version: '0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: csv
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 41 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 56 | 
             
              name: dry-schema
         | 
| 43 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -136,6 +150,20 @@ dependencies: | |
| 136 150 | 
             
                - - ">="
         | 
| 137 151 | 
             
                  - !ruby/object:Gem::Version
         | 
| 138 152 | 
             
                    version: '0'
         | 
| 153 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 154 | 
            +
              name: net-sftp
         | 
| 155 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
                requirements:
         | 
| 157 | 
            +
                - - ">="
         | 
| 158 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                    version: '0'
         | 
| 160 | 
            +
              type: :runtime
         | 
| 161 | 
            +
              prerelease: false
         | 
| 162 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 163 | 
            +
                requirements:
         | 
| 164 | 
            +
                - - ">="
         | 
| 165 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 166 | 
            +
                    version: '0'
         | 
| 139 167 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 140 168 | 
             
              name: pg
         | 
| 141 169 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -395,6 +423,11 @@ files: | |
| 395 423 | 
             
            - lib/multiwoven/integrations/destination/salesforce_crm/config/meta.json
         | 
| 396 424 | 
             
            - lib/multiwoven/integrations/destination/salesforce_crm/config/spec.json
         | 
| 397 425 | 
             
            - lib/multiwoven/integrations/destination/salesforce_crm/icon.svg
         | 
| 426 | 
            +
            - lib/multiwoven/integrations/destination/sftp/client.rb
         | 
| 427 | 
            +
            - lib/multiwoven/integrations/destination/sftp/config/catalog.json
         | 
| 428 | 
            +
            - lib/multiwoven/integrations/destination/sftp/config/meta.json
         | 
| 429 | 
            +
            - lib/multiwoven/integrations/destination/sftp/config/spec.json
         | 
| 430 | 
            +
            - lib/multiwoven/integrations/destination/sftp/icon.svg
         | 
| 398 431 | 
             
            - lib/multiwoven/integrations/destination/slack/client.rb
         | 
| 399 432 | 
             
            - lib/multiwoven/integrations/destination/slack/config/catalog.json
         | 
| 400 433 | 
             
            - lib/multiwoven/integrations/destination/slack/config/meta.json
         |