Module: Clacky::Server::ApiExtensionDispatcher

Defined in:
lib/clacky/server/api_extension_dispatcher.rb

Overview

Routes /api/ext/<name>/<sub-path> requests to the matching ApiExtension subclass. Wraps each handler invocation with a timeout and a unified JSON error envelope so a misbehaving extension cannot break neighboring extensions or the host process.

Constant Summary collapse

MOUNT_PREFIX =
"/api/ext/"

Class Method Summary collapse

Class Method Details

.handle(req, res, http_server:) ⇒ Object

Public entry called from HttpServer#_dispatch_rest. Returns true to indicate the request was handled (200/4xx/5xx).



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/clacky/server/api_extension_dispatcher.rb', line 19

def handle(req, res, http_server:)
  ext_id, sub_path = parse_path(req.path)
  return not_found(res, "extension id missing") unless ext_id

  klass = Clacky::ApiExtension.registry[ext_id]
  return not_found(res, "extension '#{ext_id}' not found") unless klass

  method = req.request_method.to_s.downcase.to_sym
  route, params = find_route(klass, method, sub_path)
  return not_found(res, "no route for #{req.request_method} #{req.path}") unless route

  # Public-endpoint check is done at HttpServer level (it owns access-key
  # logic); by the time we get here, auth has already been resolved.

  timeout_sec = route.options[:timeout] || klass.class_timeout || Clacky::ApiExtension::DEFAULT_TIMEOUT
  invoke_route(klass, route, params, req, res, http_server, timeout_sec)
  true
end

.public_path?(path, method) ⇒ Boolean

Tells HttpServer whether a given /api/ext/… path can skip access-key auth, so the host can keep its single-source-of-truth auth logic.

Returns:

  • (Boolean)


40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/clacky/server/api_extension_dispatcher.rb', line 40

def public_path?(path, method)
  ext_id, sub_path = parse_path(path)
  return false unless ext_id

  klass = Clacky::ApiExtension.registry[ext_id]
  return false unless klass
  return false if klass.public_paths.empty?

  route, _params = find_route(klass, method.to_s.downcase.to_sym, sub_path)
  return false unless route

  klass.public_paths.include?(route.pattern)
end