@rip-lang/api 0.7.3 → 0.7.5

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.
package/api.rip CHANGED
@@ -590,6 +590,6 @@ export read = (keyOrTag = null, tagOrMiss = null, missOrNil = null) ->
590
590
  return miss?() if typeof miss is 'function'
591
591
  throw new Error "Missing required field: #{key}"
592
592
  else
593
- return (miss?() if typeof miss is 'function') or miss or null
593
+ return if typeof miss is 'function' then miss?() else miss
594
594
 
595
595
  v
package/middleware.rip CHANGED
@@ -3,13 +3,14 @@
3
3
  # ==============================================================================
4
4
  #
5
5
  # Usage:
6
- # import { cors, logger, compress, sessions } from '@rip-lang/api/middleware'
6
+ # import { cors, logger, compress, sessions, prettyJson } from '@rip-lang/api/middleware'
7
7
  # import { session } from '@rip-lang/api'
8
8
  #
9
9
  # use logger()
10
10
  # use cors origin: 'https://myapp.com'
11
11
  # use compress()
12
12
  # use sessions()
13
+ # use prettyJson # Pretty JSON for iOS mobile browsers
13
14
  #
14
15
  # before ->
15
16
  # session.userId = 123 # Works anywhere via AsyncLocalStorage
@@ -390,3 +391,73 @@ export bodyLimit = (opts = {}) ->
390
391
  return c.json { error: message }, 413
391
392
 
392
393
  await next()
394
+
395
+ # ==============================================================================
396
+ # prettyJson — Pretty JSON for iOS Mobile Browsers
397
+ # ==============================================================================
398
+ #
399
+ # Renders JSON as syntax-highlighted HTML for iOS mobile browsers.
400
+ # Solves the iOS Safari/Chrome "download" footer issue when viewing JSON.
401
+ #
402
+ # Usage:
403
+ # use prettyJson
404
+ #
405
+ # Only activates when:
406
+ # 1. Request is from iOS (iPhone/iPad)
407
+ # 2. Browser is directly viewing (Accept: text/html, not API call)
408
+ #
409
+
410
+ export prettyJson = (c, next) ->
411
+ originalJson = c.json.bind(c)
412
+
413
+ c.json = (data, status = 200, headers = {}) ->
414
+ if _shouldRenderHtmlJson(c.req.raw)
415
+ return _renderHtmlJson(data, status)
416
+ originalJson(data, status, headers)
417
+
418
+ next!()
419
+
420
+ _shouldRenderHtmlJson = (req) ->
421
+ ua = req.headers.get('user-agent') or ''
422
+ accept = req.headers.get('accept') or ''
423
+ dest = req.headers.get('sec-fetch-dest') or ''
424
+
425
+ isIOS = /iPhone|iPad|iPod/i.test(ua)
426
+ acceptsHtml = accept.includes('text/html')
427
+ isNavigation = dest is 'document' or (acceptsHtml and not accept.startsWith('application/json'))
428
+
429
+ isIOS and isNavigation
430
+
431
+ _renderHtmlJson = (data, status) ->
432
+ json = JSON.stringify(data, null, 2)
433
+
434
+ # HTML escape then syntax highlight
435
+ escaped = json
436
+ .replace(/&/g, '&')
437
+ .replace(/</g, '&lt;')
438
+ .replace(/>/g, '&gt;')
439
+
440
+ highlighted = escaped
441
+ .replace(/"([^"]+)":/g, '<span class="k">"$1"</span>:')
442
+ .replace(/: "([^"]*)"/g, ': <span class="s">"$1"</span>')
443
+ .replace(/: (-?\d+\.?\d*)/g, ': <span class="n">$1</span>')
444
+ .replace(/: (true|false)/g, ': <span class="b">$1</span>')
445
+ .replace(/: (null)/g, ': <span class="b">$1</span>')
446
+
447
+ html = """<!DOCTYPE html>
448
+ <html><head>
449
+ <meta charset="utf-8">
450
+ <meta name="viewport" content="width=device-width,initial-scale=1">
451
+ <title>JSON</title>
452
+ <style>
453
+ *{box-sizing:border-box}
454
+ body{font:14px/1.5 ui-monospace,monospace;background:#1a1a2e;color:#e0e0e0;margin:0;padding:16px}
455
+ pre{margin:0;white-space:pre-wrap;word-break:break-word}
456
+ .k{color:#82aaff}.s{color:#c3e88d}.n{color:#f78c6c}.b{color:#89ddff}
457
+ </style>
458
+ </head><body><pre>#{highlighted}</pre></body></html>"""
459
+
460
+ new Response html, {
461
+ status: status
462
+ headers: new Headers({ 'content-type': 'text/html; charset=utf-8' })
463
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rip-lang/api",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "Pure Rip API framework — elegant, fast, zero dependencies",
5
5
  "type": "module",
6
6
  "main": "api.rip",