Module: Mxrb::Protocols

Defined in:
lib/mxrb/protocols.rb,
lib/mxrb/protocols/plan.rb

Overview

Preview/apply orchestration for verified protocol connector packages.

Defined Under Namespace

Classes: Adapter, Audit, Entry, Plan, Request

Constant Summary collapse

REGISTRY =

Verified from official Mendix Marketplace pages. Public component ids are useful for planning; module recognition remains GUID-only and fail-closed.

[
  Entry.new(
    protocol: :mqtt, name: 'MQTT', publisher: 'Mendix', category: 'Messaging',
    marketplace_id: '119508', content_type: 'Service', appstore_guids: [].freeze,
    source_url: 'https://marketplace.mendix.com/link/component/119508',
    evidence_date: '2026-08-04'
  ),
  Entry.new(
    protocol: :opc_ua, name: 'OPC-UA Connector', publisher: 'Mendix', category: 'Industrial',
    marketplace_id: '230843', content_type: 'Module', appstore_guids: [].freeze,
    source_url: 'https://marketplace.mendix.com/link/component/230843',
    evidence_date: '2026-08-04'
  ),
  Entry.new(
    protocol: :opc_ua, name: 'OPC UA Client Connector', publisher: 'Mendix', category: 'Industrial',
    marketplace_id: '117391', content_type: 'Service', appstore_guids: [].freeze,
    source_url: 'https://marketplace.mendix.com/link/component/117391',
    evidence_date: '2026-08-04'
  ),
  Entry.new(
    protocol: :kafka, name: 'Kafka', publisher: 'Mendix', category: 'Messaging',
    marketplace_id: '105878', content_type: 'Module', appstore_guids: [].freeze,
    source_url: 'https://marketplace.mendix.com/link/component/105878',
    evidence_date: '2026-08-04'
  ),
  Entry.new(
    protocol: :websocket, name: 'WebsocketClient', publisher: 'Mendix', category: 'Communication',
    marketplace_id: '235426', content_type: 'Module', appstore_guids: [].freeze,
    source_url: 'https://marketplace.mendix.com/link/component/235426',
    evidence_date: '2026-08-04'
  ),
  Entry.new(
    protocol: :amqp, name: 'eMagiz Mendix Connector (Legacy)', publisher: 'eMagiz',
    category: 'Communication', marketplace_id: '118800', content_type: 'Service',
    appstore_guids: [].freeze,
    source_url: 'https://marketplace.mendix.com/link/component/118800',
    evidence_date: '2026-08-04'
  )
].freeze

Class Method Summary collapse

Class Method Details

.adapter(installer:, api:) ⇒ Object



64
# File 'lib/mxrb/protocols/plan.rb', line 64

def adapter(installer:, api:) = Adapter.new(installer:, api:)

.allObject



74
# File 'lib/mxrb/protocols.rb', line 74

def all = REGISTRY

.audit(project, registry: REGISTRY) ⇒ Object

Walks the project's imported marketplace modules and classifies each one as a recognized connector or an unrecognized marketplace module. Never mutates the project and never installs anything.



93
94
95
96
97
98
99
100
101
# File 'lib/mxrb/protocols.rb', line 93

def audit(project, registry: REGISTRY)
  recognized = []
  unknown = []
  project.modules.select(&:from_app_store).each do |mod|
    entry = identify(mod.app_store_guid, registry: registry)
    entry ? recognized << connector_for(mod, entry) : unknown << mod.name.to_s
  end
  Audit.new(connectors: recognized.freeze, unknown_marketplace_modules: unknown.sort.freeze)
end

.connector_for(mod, entry) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/mxrb/protocols.rb', line 103

def connector_for(mod, entry)
  readable = mod.export_level.to_s != 'Hidden'
  Model::Connector.new(
    module_name: mod.name, protocol: entry.protocol,
    appstore_guid: mod.app_store_guid, appstore_version: mod.app_store_version.to_s,
    entities: readable ? surface_names(mod.entities) : [],
    microflows: readable ? surface_names(mod.microflows) : [],
    protected: !readable,
    metadata: { name: entry.name, marketplace_id: entry.marketplace_id, source_url: entry.source_url }
  )
end

.find_by_protocol(protocol) ⇒ Object



76
77
78
79
# File 'lib/mxrb/protocols.rb', line 76

def find_by_protocol(protocol)
  key = normalize_protocol(protocol)
  REGISTRY.select { _1.protocol == key }
end

.identify(guid, registry: REGISTRY) ⇒ Object



81
82
83
84
85
86
# File 'lib/mxrb/protocols.rb', line 81

def identify(guid, registry: REGISTRY)
  key = guid.to_s
  return nil if key.empty?

  registry.find { _1.matches_guid?(key) }
end

.known_guid?(guid, registry: REGISTRY) ⇒ Boolean

Returns:

  • (Boolean)


88
# File 'lib/mxrb/protocols.rb', line 88

def known_guid?(guid, registry: REGISTRY) = !identify(guid, registry: registry).nil?

.normalize_protocol(protocol) ⇒ Object



117
118
119
# File 'lib/mxrb/protocols.rb', line 117

def normalize_protocol(protocol)
  protocol.to_s.strip.downcase.tr('- ', '__').to_sym
end

.plan(protocol, mendix_version:, version: nil, marketplace_id: nil, adapter: nil) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/mxrb/protocols/plan.rb', line 66

def plan(protocol, mendix_version:, version: nil, marketplace_id: nil, adapter: nil)
  connector_request = request(protocol, version:, marketplace_id:)
  entry = planning_entry(connector_request)
  package = adapter&.api&.resolve(
    entry.marketplace_id, version: connector_request.version, mendix_version:
  )
  Plan.new(
    request: connector_request, entry:,
    context: { mendix_version:, adapter:, package: }
  )
end

.planning_entry(request) ⇒ Object

Raises:



78
79
80
81
82
83
84
# File 'lib/mxrb/protocols/plan.rb', line 78

def planning_entry(request)
  candidates = find_by_protocol(request.protocol)
  candidates = candidates.select { _1.marketplace_id == request.marketplace_id } if request.marketplace_id
  raise MarketplaceError, "no verified Marketplace connector for #{request.protocol.inspect}" if candidates.empty?

  candidates.find { _1.content_type == 'Module' } || candidates.first
end

.request(protocol, version: nil, marketplace_id: nil) ⇒ Object



57
58
59
60
61
62
# File 'lib/mxrb/protocols/plan.rb', line 57

def request(protocol, version: nil, marketplace_id: nil)
  Request.new(
    protocol: normalize_protocol(protocol), version: version&.to_s,
    marketplace_id: marketplace_id&.to_s
  )
end

.surface_names(items) ⇒ Object



115
# File 'lib/mxrb/protocols.rb', line 115

def surface_names(items) = items.map(&:name).compact.sort