bug_bunny 3.1.4 → 3.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28bb35f1140309e9527c44f108cba3b58b85aae52c7253d17f35f7b35e248661
4
- data.tar.gz: f3b30d3b77b1c242c3e8c8fc9576d8143b2587b60da83a0d633604eaca464ebd
3
+ metadata.gz: 7fec9f487076682121e6d8586e44fe9d70f380bd809fb46014265105421a0d8f
4
+ data.tar.gz: e847fc6f1943f9921f2250a46a20bd6f76b20736812fcbf6bfc437ab49a8a30c
5
5
  SHA512:
6
- metadata.gz: a069a81c26762bedc55cb8c0be70ac6ff2154d70d4b54f10d7650ddc27160cf400c4c8b680e50e0fd3529f39447ccfcb83864ae7d99396ee7ce62ef5d84da6fd
7
- data.tar.gz: d8e5130f3d6830023f85516a2dec1db036c49cc0963af8f92255987c32b6e721e2785ed54c4d2b9ac94931c5b3e1073c1b1a549265aabb39839f0b95348deaaa
6
+ metadata.gz: 199faaa596f52cc1c192259e8fe3e7da95152d117db9ded079051bebdff985793e63acde11cb8ceed5e0e216d6934ff35056993947609f2818d8429f524a789a
7
+ data.tar.gz: dfefdd78b4597f90dc059ef07d7423dda86d2630cdab409c514941708cc539d174a763d1a6e18c918dee7058d25c0a996aac0bb52f1b440573b42480e723e284
data/CHANGELOG.md CHANGED
@@ -1,4 +1,18 @@
1
1
  # Changelog
2
+ ## [3.1.6] - 2026-02-27
3
+
4
+ ### 🐛 Bug Fixes & Router Improvements
5
+ * **Enhanced Heuristic Router (ID Detection):** Mejoras críticas en `Consumer#router_dispatch` para soportar una gama mucho más amplia de formatos de identificadores y evitar colisiones con namespaces:
6
+ * **Soporte para Swarm/NanoID:** Se amplió la expresión regular de detección de IDs para capturar hashes alfanuméricos de 20 o más caracteres (`[a-zA-Z0-9_-]{20,}`), permitiendo el correcto ruteo de IDs generados por Docker Swarm (25 caracteres) o NanoID.
7
+ * **Escaneo Inverso (Right-to-Left):** Se modificó la búsqueda del ID para que escanee los segmentos de la URL desde el final hacia el principio (`rindex`). Esto evita falsos positivos donde namespaces cortos como `v1` (ej. `api/v1/...`) eran confundidos accidentalmente con un ID.
8
+ * **Fallback Semántico Posicional:** Se introdujo una red de seguridad (fallback) que infiere la posición del ID basándose en el Verbo HTTP. Si el ID no coincide con ningún patrón Regex (ej. es un ID corto como `node-1`), pero el método es `PUT`, `PATCH` o `DELETE`, el enrutador ahora asume inteligentemente que el penúltimo/último segmento corresponde al ID del recurso.
9
+
10
+ ## [3.1.5] - 2026-02-25
11
+
12
+ ### ✨ New Features & Improvements
13
+ * **Smart Heuristic Router (Namespace Support):** El enrutador interno del consumidor (`Consumer#router_dispatch`) fue reescrito para soportar namespaces profundos y rutas anidadas sin necesidad de configuración manual. Utiliza una heurística basada en Regex para detectar dinámicamente identificadores (Enteros, UUIDs o hashes alfanuméricos largos) dentro de la URL.
14
+ * Esto permite que rutas complejas como `GET api/v1/ecommerce/orders/a1b2c3d4/cancel` resuelvan automáticamente al controlador `Api::V1::Ecommerce::OrdersController`, asignando `id: a1b2c3d4` y `action: cancel`.
15
+
2
16
  ## [3.1.4] - 2026-02-21
3
17
 
4
18
  ### 🚀 Cloud Native & Infrastructure Features
@@ -179,44 +179,77 @@ module BugBunny
179
179
 
180
180
  # Interpreta la URL y el verbo para decidir qué controlador ejecutar.
181
181
  #
182
- # Utiliza `Rack::Utils.parse_nested_query` para soportar parámetros anidados
183
- # como `q[service]=rabbit`.
182
+ # Implementa un Router Heurístico que soporta namespaces y acciones custom
183
+ # buscando dinámicamente el ID en la ruta mediante Regex y Fallback Semántico.
184
184
  #
185
185
  # @param method [String] Verbo HTTP (GET, POST, etc).
186
- # @param path [String] URL virtual del recurso (ej: 'users/1?active=true').
186
+ # @param path [String] URL virtual del recurso (ej: 'foo/bar/algo/13/test').
187
187
  # @return [Hash] Estructura con keys {:controller, :action, :id, :params}.
188
188
  def router_dispatch(method, path)
189
- # Usamos URI para separar path de query string
190
189
  uri = URI.parse("http://dummy/#{path}")
191
190
  segments = uri.path.split('/').reject(&:empty?)
192
191
 
193
- # --- FIX: Uso de Rack para soportar params anidados ---
194
192
  query_params = uri.query ? Rack::Utils.parse_nested_query(uri.query) : {}
195
-
196
- # Si estamos en Rails, convertimos a HashWithIndifferentAccess para comodidad
197
193
  if defined?(ActiveSupport::HashWithIndifferentAccess)
198
194
  query_params = query_params.with_indifferent_access
199
195
  end
200
196
 
201
- # Lógica de Ruteo Convencional
202
- controller_name = segments[0]
203
- id = segments[1]
204
-
205
- action = case method.to_s.upcase
206
- when 'GET' then id ? 'show' : 'index'
207
- when 'POST' then 'create'
208
- when 'PUT', 'PATCH' then 'update'
209
- when 'DELETE' then 'destroy'
210
- else id || 'index'
211
- end
212
-
213
- # Soporte para rutas miembro custom (POST users/1/promote)
214
- if segments.size >= 3
215
- id = segments[1]
216
- action = segments[2]
197
+ # 1. Acción Built-in: Health Check Global (/up o /api/up)
198
+ if segments.last == 'up' && method.to_s.upcase == 'GET'
199
+ ctrl = segments.size > 1 ? segments[0...-1].join('/') : 'application'
200
+ return { controller: ctrl, action: 'up', id: nil, params: query_params }
201
+ end
202
+
203
+ # 2. Búsqueda dinámica del ID (Heurística por Regex)
204
+ # Patrón: Enteros, UUIDs, o Hashes largos (Docker Swarm 25 chars, Mongo 24 chars)
205
+ id_pattern = /^(?:\d+|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[a-zA-Z0-9_-]{20,})$/
206
+
207
+ # FIX: Usamos rindex (de derecha a izquierda) para evitar falsos positivos con namespaces como 'v1'
208
+ id_index = segments.rindex { |s| s.match?(id_pattern) }
209
+
210
+ # 3. Fallback Semántico Posicional
211
+ # Si el regex no detectó el ID (ej: ID corto como "node-1"), pero la semántica HTTP
212
+ # indica que es una operación singular (PUT/DELETE/GET), asumimos que el último segmento es el ID.
213
+ if id_index.nil? && segments.size >= 2
214
+ last_segment = segments.last
215
+ method_up = method.to_s.upcase
216
+
217
+ is_member_verb = %w[PUT PATCH DELETE].include?(method_up)
218
+ # En GET, nos aseguramos que la última palabra no sea una acción estándar de REST
219
+ is_get_member = method_up == 'GET' && !%w[index new edit up action].include?(last_segment)
220
+
221
+ if is_member_verb || is_get_member
222
+ # Si tiene 3 o más segmentos (ej. nodes/node-1/stats), el ID no está al final.
223
+ # Este fallback asume que para IDs raros, el formato clásico es recurso/id
224
+ id_index = segments.size - 1
225
+ end
226
+ end
227
+
228
+ # 4. Asignación de variables según escenario
229
+ if id_index
230
+ # ESCENARIO A: Ruta Miembro (ej. nodes/4bv445vgc158hk4twlxmdjo0v/stats)
231
+ controller_name = segments[0...id_index].join('/')
232
+ id = segments[id_index]
233
+ action = segments[id_index + 1] # Puede ser nil si no hay acción extra al final
234
+ else
235
+ # ESCENARIO B: Ruta Colección (ej. api/v1/nodes)
236
+ controller_name = segments.join('/')
237
+ id = nil
238
+ action = nil
239
+ end
240
+
241
+ # 5. Inferimos la acción clásica de Rails si no hay una explícita
242
+ unless action
243
+ action = case method.to_s.upcase
244
+ when 'GET' then id ? 'show' : 'index'
245
+ when 'POST' then 'create'
246
+ when 'PUT', 'PATCH' then 'update'
247
+ when 'DELETE' then 'destroy'
248
+ else id ? 'show' : 'index'
249
+ end
217
250
  end
218
251
 
219
- # Inyectamos el ID en los params si existe en la ruta
252
+ # 6. Inyectamos el ID en los parámetros para fácil acceso en el Controlador
220
253
  query_params['id'] = id if id
221
254
 
222
255
  { controller: controller_name, action: action, id: id, params: query_params }
@@ -110,7 +110,7 @@ module BugBunny
110
110
  BugBunny.configuration.logger.info("[BugBunny::Producer] 📤 #{verb} /#{target} | RK: '#{rk}' | ID: #{id}")
111
111
 
112
112
  # DEBUG: Detalle completo de Infraestructura y Payload
113
- BugBunny.configuration.logger.debug("[BugBunny::Producer] ⚙️ Exchange Opts: #{final_x_opts}")
113
+ BugBunny.configuration.logger.debug("[BugBunny::Producer] ⚙️ Exchange #{request.exchange} | Opts: #{final_x_opts}")
114
114
  BugBunny.configuration.logger.debug("[BugBunny::Producer] 📦 Payload: #{payload.truncate(300)}") if payload.is_a?(String)
115
115
  end
116
116
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BugBunny
4
- VERSION = "3.1.4"
4
+ VERSION = "3.1.6"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bug_bunny
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.4
4
+ version: 3.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - gabix
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-21 00:00:00.000000000 Z
11
+ date: 2026-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny