Module: Tina4::ErrorOverlay
- Defined in:
- lib/tina4/error_overlay.rb
Constant Summary collapse
- BG =
── Colour palette (Catppuccin Mocha) ──────────────────────────────
"#1e1e2e"- SURFACE =
"#313244"- OVERLAY_COLOR =
"#45475a"- TEXT_COLOR =
"#cdd6f4"- SUBTEXT =
"#a6adc8"- RED =
"#f38ba8"- YELLOW =
"#f9e2af"- BLUE =
"#89b4fa"- GREEN =
"#a6e3a1"- LAVENDER =
"#b4befe"- PEACH =
"#fab387"- ERROR_LINE_BG =
"rgba(243,139,168,0.15)"- CONTEXT_LINES =
7- MAX_FRAMES =
OVERLAY-DEC-03: cap the rendered frames so a deep/recursive stack yields a bounded page, not one source-file read per frame.
50- SENSITIVE_KEY_RE =
OVERLAY-DEC-02: request fields whose KEY matches this are masked in the dev overlay (Authorization/Cookie/Set-Cookie headers via authorization|cookie — Rack spells them HTTP_AUTHORIZATION / HTTP_COOKIE; password/token/secret/api_key body/param keys via the rest). Over-matching a benign field is the SAFE direction in a dev tool — over-masking leaks nothing; under-masking leaks a secret.
/password|passwd|secret|token|authorization|cookie|key/i- REDACTED =
"[redacted]"
Class Method Summary collapse
-
.is_debug_mode ⇒ Object
Return true if TINA4_DEBUG is enabled.
-
.render_error_overlay(exception, request: nil) ⇒ String
Render a rich HTML error overlay.
Class Method Details
.is_debug_mode ⇒ Object
Return true if TINA4_DEBUG is enabled.
153 154 155 |
# File 'lib/tina4/error_overlay.rb', line 153 def is_debug_mode Tina4::Env.is_truthy(ENV.fetch("TINA4_DEBUG", "")) end |
.render_error_overlay(exception, request: nil) ⇒ String
Render a rich HTML error overlay.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/tina4/error_overlay.rb', line 59 def (exception, request: nil) exc_type = exception.class.name exc_msg = exception. # Stamp captured_at once when the overlay is generated. Each frame # compares its source file's mtime to this single timestamp and # flags itself stale if the file changed afterwards — protects # against the "browser cached an old overlay, then the AI rewrote # the file" confusion where the displayed source no longer matches # what actually raised the error. captured_at = Time.now.to_f # ── Stack trace (OVERLAY-DEC-03: capped) ── # A recursive stack of thousands of frames would otherwise do one source-file # read per frame and emit an unbounded page; render only the innermost # MAX_FRAMES and note the rest. frames_html = +"" backtrace = exception.backtrace || [] backtrace.first(MAX_FRAMES).each do |line| file, lineno, method = parse_backtrace_line(line) frames_html << format_frame(file, lineno, method, captured_at: captured_at) end hidden = backtrace.length - [backtrace.length, MAX_FRAMES].min if hidden.positive? frames_html << "<div style=\"color:#{SUBTEXT};padding:8px 0;font-size:13px;\">" \ "… #{hidden} more stack frames hidden (truncated at #{MAX_FRAMES})</div>" end # ── Request info (OVERLAY-DEC-02: sensitive fields redacted) ── request_pairs = [] if request.is_a?(Hash) request.each do |k, v| key = k.to_s if v.is_a?(Hash) v.each do |hk, hv| pair_key = "#{key}.#{hk}" request_pairs << [pair_key, redact(pair_key, hv.to_s)] end elsif key.start_with?("HTTP_") || %w[REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL REMOTE_ADDR SERVER_PORT QUERY_STRING CONTENT_TYPE CONTENT_LENGTH method url path].include?(key) request_pairs << [key, redact(key, v.to_s)] end end end request_section = request_pairs.empty? ? "" : collapsible("Request Details", table(request_pairs)) # ── Environment ── env_pairs = [ ["Framework", "Tina4 Ruby"], ["Version", defined?(Tina4::VERSION) ? Tina4::VERSION : "unknown"], ["Ruby", RUBY_VERSION], ["Platform", RUBY_PLATFORM], ["Debug", ENV.fetch("TINA4_DEBUG", "false")], ["Log Level", ENV.fetch("TINA4_LOG_LEVEL", "ERROR")] ] env_section = collapsible("Environment", table(env_pairs)) stack_section = collapsible("Stack Trace", frames_html, open_by_default: true) <<~HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Tina4 Error — #{esc(exc_type)}</title> <style> *{margin:0;padding:0;box-sizing:border-box;} body{background:#{BG};color:#{TEXT_COLOR};font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;padding:24px;line-height:1.5;} </style> </head> <body> <div style="max-width:960px;margin:0 auto;"> <div style="margin-bottom:24px;"> <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;"> <span style="background:#{RED};color:#{BG};padding:4px 12px;border-radius:4px;font-weight:700;font-size:13px;text-transform:uppercase;">Error</span> <span style="color:#{SUBTEXT};font-size:14px;">Tina4 Debug Overlay</span> </div> <h1 style="color:#{RED};font-size:28px;font-weight:700;margin-bottom:8px;">#{esc(exc_type)}</h1> <p style="color:#{TEXT_COLOR};font-size:18px;font-family:'SF Mono','Fira Code','Consolas',monospace;background:#{SURFACE};padding:12px 16px;border-radius:6px;border-left:4px solid #{RED};">#{esc(exc_msg)}</p> </div> #{stack_section} #{request_section} #{env_section} <div style="margin-top:32px;padding-top:16px;border-top:1px solid #{OVERLAY_COLOR};color:#{SUBTEXT};font-size:12px;"> Tina4 Debug Overlay — This page is only shown in debug mode. Set TINA4_DEBUG=false in production. </div> </div> </body> </html> HTML end |