hyperion-rb 2.15.0 → 2.16.0
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 +4 -4
- data/CHANGELOG.md +63 -0
- data/bin/check +85 -0
- data/lib/hyperion/cli.rb +36 -8
- data/lib/hyperion/config.rb +19 -1
- data/lib/hyperion/master.rb +17 -2
- data/lib/hyperion/version.rb +1 -1
- data/lib/hyperion/worker.rb +16 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d599cad6595983a3aef241b7e5895b613c6275e44e8f05925f29c82fba99072c
|
|
4
|
+
data.tar.gz: c733f8b8e0f2d7de93a5bed82d4cea1331bbafafde347334cf08bbb00f8c1474
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8311ce71399125875a3bab4499244801dfeac405512a6a3339762dc075e495a86e961f1135eb33ec8ac30c7d2e0bb46d0951a53ba144f42a1a40fce855889a74
|
|
7
|
+
data.tar.gz: c1eee7b3bdc928bdf328223abf54c80d5a1d9742a770968063659a98943a04e7c0f3b5530c4b5e5fef62847ccf29d6ddafb4cf8e7b4ee187968a82c27ad0f8b5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.16.0 — 2026-05-04
|
|
4
|
+
|
|
5
|
+
### 2.16-A — `preload false`: macOS fork+resolver escape hatch
|
|
6
|
+
|
|
7
|
+
**Why.** On macOS, Hyperion's "always preload" model deadlocks
|
|
8
|
+
post-fork DNS resolution for any deployment whose master process
|
|
9
|
+
ends up touching `Network.framework` — typically through native
|
|
10
|
+
gems loaded transitively via `Bundler.require` (OpenSSL session
|
|
11
|
+
caches, observability agents, Foundation-backed clients). The
|
|
12
|
+
master's `Network.framework` path evaluator initializes against XPC
|
|
13
|
+
peers in `mDNSResponder`; after `fork()` those XPC connections are
|
|
14
|
+
invalid in the workers, and the next `getaddrinfo` call hangs
|
|
15
|
+
forever inside `nw_path_evaluator_evaluate` →
|
|
16
|
+
`nw_nat64_v4_address_requires_synthesis`. The symptom: workers
|
|
17
|
+
spin at 99% CPU, requests TCP-connect but never get a response,
|
|
18
|
+
no per-request log line ever fires.
|
|
19
|
+
`OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` does not help — that
|
|
20
|
+
flag only covers Foundation / Obj-C runtime init, not
|
|
21
|
+
`Network.framework`.
|
|
22
|
+
|
|
23
|
+
The reason Puma users don't hit this: Puma without explicit
|
|
24
|
+
`preload_app! true` runs in non-preload mode, so the master is a
|
|
25
|
+
thin supervisor and each worker loads the Rack app post-fork
|
|
26
|
+
against a clean process. Hyperion shipped no such option — preload
|
|
27
|
+
was the only mode.
|
|
28
|
+
|
|
29
|
+
**What 2.16-A ships.**
|
|
30
|
+
|
|
31
|
+
1. **`preload` config field** (default `true` to preserve current
|
|
32
|
+
behaviour). When `preload false` is set in `config/hyperion.rb`
|
|
33
|
+
or `--no-preload` is passed on the CLI, the master never loads
|
|
34
|
+
`config.ru` and never calls `Hyperion.warmup!`. Each worker
|
|
35
|
+
parses the rackup itself post-fork via the same
|
|
36
|
+
`Hyperion::CLI.load_rack_app` path the master used to use; the
|
|
37
|
+
admin middleware wrap is preserved per-worker. `--preload` is
|
|
38
|
+
the inverse for argv overrides.
|
|
39
|
+
|
|
40
|
+
2. **Single-worker mode is exempt.** With `workers <= 1` there is
|
|
41
|
+
no fork to protect against, so `run_single` always loads the
|
|
42
|
+
app in-process — deferring the parse buys nothing and would
|
|
43
|
+
surface lifecycle hooks against an unloaded app.
|
|
44
|
+
|
|
45
|
+
3. **Master/Worker plumbing.** `Master.new` gains a `rackup_path:`
|
|
46
|
+
kwarg; `Worker.new` mirrors it and lazy-parses if `@app` is
|
|
47
|
+
`nil` and a path was provided. Both keep their existing
|
|
48
|
+
contract for the preload path (master receives `app:`, workers
|
|
49
|
+
inherit via fork).
|
|
50
|
+
|
|
51
|
+
**Trade-off.** Non-preload loses copy-on-write — each worker pays
|
|
52
|
+
the full Rails-boot RSS independently. Steady-state memory is N×
|
|
53
|
+
higher and worker boot is slower. The escape hatch is meant for
|
|
54
|
+
operators who hit the macOS deadlock; Linux users should leave it
|
|
55
|
+
at the default (`preload true`).
|
|
56
|
+
|
|
57
|
+
**Verification.**
|
|
58
|
+
|
|
59
|
+
- `bin/check` green (81 examples, 0 failures).
|
|
60
|
+
- Hand-reproduced against a Rails 8.1 application with a typical
|
|
61
|
+
native-gem stack (OpenSSL, observability agent, multi-A-record
|
|
62
|
+
DNS host for the database). Without `preload false`: deadlock
|
|
63
|
+
reproduces deterministically; CPU pegs at 99% per worker; curl
|
|
64
|
+
times out. With `preload false`: requests return promptly.
|
|
65
|
+
|
|
3
66
|
## 2.15.0 — 2026-05-02
|
|
4
67
|
|
|
5
68
|
### 2.15-A — Fresh bench, README split, CI flake fix
|
data/bin/check
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hyperion health-check. Run this BEFORE claiming a change is "all green".
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bin/check # default: compile + syntax + smoke specs (~10s)
|
|
6
|
+
# bin/check --quick # same as default
|
|
7
|
+
# bin/check --full # compile + syntax + full rspec (perf excluded)
|
|
8
|
+
# bin/check --syntax-only # compile + ruby -wc on lib/
|
|
9
|
+
# bin/check spec/path/foo_spec.rb [more...] # compile + targeted specs
|
|
10
|
+
#
|
|
11
|
+
# Exits non-zero on the first failing stage. Hooks-friendly: stdout is
|
|
12
|
+
# stage-tagged so .claude/bin/run-bounded.sh shows the right slice on tail.
|
|
13
|
+
#
|
|
14
|
+
# Smoke set covers the request hot path: parser, request, response writer,
|
|
15
|
+
# connection lifecycle, server loop, runtime. Each spec runs in <1s on a
|
|
16
|
+
# warm bundler cache; the full set lands in ~5–10s total.
|
|
17
|
+
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
|
|
20
|
+
cd "$(dirname "$0")/.."
|
|
21
|
+
|
|
22
|
+
mode="quick"
|
|
23
|
+
specs=()
|
|
24
|
+
if [ $# -gt 0 ]; then
|
|
25
|
+
case "$1" in
|
|
26
|
+
--quick) mode="quick"; shift ;;
|
|
27
|
+
--full) mode="full"; shift ;;
|
|
28
|
+
--syntax-only) mode="syntax" ;;
|
|
29
|
+
-h|--help)
|
|
30
|
+
sed -n '2,15p' "$0"
|
|
31
|
+
exit 0 ;;
|
|
32
|
+
*) mode="targeted"; specs=("$@") ;;
|
|
33
|
+
esac
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
stage() { printf '\n=== %s ===\n' "$1"; }
|
|
37
|
+
fail() { printf '\n!!! FAIL: %s\n' "$1"; exit 1; }
|
|
38
|
+
|
|
39
|
+
# --- 1. Compile (always; cheap if already built) -----------------------------
|
|
40
|
+
stage "compile (rake compile)"
|
|
41
|
+
bundle exec rake compile || fail "rake compile"
|
|
42
|
+
|
|
43
|
+
# --- 2. Syntax check on lib/ (fast, catches typos before specs load) --------
|
|
44
|
+
stage "ruby -wc on lib/hyperion/**/*.rb"
|
|
45
|
+
syntax_errors=0
|
|
46
|
+
while IFS= read -r -d '' f; do
|
|
47
|
+
if ! ruby -wc "$f" >/dev/null 2>/tmp/hyperion-check-syntax.err; then
|
|
48
|
+
printf ' syntax: %s\n' "$f"
|
|
49
|
+
cat /tmp/hyperion-check-syntax.err
|
|
50
|
+
syntax_errors=$((syntax_errors + 1))
|
|
51
|
+
fi
|
|
52
|
+
done < <(find lib -name '*.rb' -type f -print0)
|
|
53
|
+
[ "$syntax_errors" -eq 0 ] || fail "$syntax_errors file(s) failed ruby -wc"
|
|
54
|
+
|
|
55
|
+
if [ "$mode" = "syntax" ]; then
|
|
56
|
+
printf '\nOK (compile + syntax only)\n'
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# --- 3. Specs ---------------------------------------------------------------
|
|
61
|
+
case "$mode" in
|
|
62
|
+
quick)
|
|
63
|
+
stage "rspec smoke set"
|
|
64
|
+
bundle exec rspec --fail-fast \
|
|
65
|
+
spec/hyperion/c_parser_spec.rb \
|
|
66
|
+
spec/hyperion/parser_spec.rb \
|
|
67
|
+
spec/hyperion/request_spec.rb \
|
|
68
|
+
spec/hyperion/response_writer_spec.rb \
|
|
69
|
+
spec/hyperion/connection_spec.rb \
|
|
70
|
+
spec/hyperion/runtime_spec.rb \
|
|
71
|
+
spec/hyperion/server_spec.rb \
|
|
72
|
+
spec/hyperion/config_spec.rb \
|
|
73
|
+
|| fail "smoke specs"
|
|
74
|
+
;;
|
|
75
|
+
full)
|
|
76
|
+
stage "rspec (full; :perf excluded by spec_helper)"
|
|
77
|
+
bundle exec rspec --fail-fast || fail "full rspec"
|
|
78
|
+
;;
|
|
79
|
+
targeted)
|
|
80
|
+
stage "rspec ${specs[*]}"
|
|
81
|
+
bundle exec rspec --fail-fast "${specs[@]}" || fail "targeted specs"
|
|
82
|
+
;;
|
|
83
|
+
esac
|
|
84
|
+
|
|
85
|
+
printf '\nOK (mode=%s)\n' "$mode"
|
data/lib/hyperion/cli.rb
CHANGED
|
@@ -97,8 +97,6 @@ module Hyperion
|
|
|
97
97
|
Hyperion.logger.info { { message: 'FiberLocal shim installed' } } if Hyperion::FiberLocal.installed?
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
-
app = load_rack_app(rackup)
|
|
101
|
-
app = wrap_admin_middleware(app, config)
|
|
102
100
|
workers = config.workers.zero? ? Etc.nprocessors : config.workers
|
|
103
101
|
|
|
104
102
|
# 2.0 default flip (RFC A7): resolve the `h2.max_total_streams`
|
|
@@ -107,10 +105,30 @@ module Hyperion
|
|
|
107
105
|
# (operator-requested unbounded).
|
|
108
106
|
config.finalize!(workers: workers)
|
|
109
107
|
|
|
108
|
+
# 2.16 — preload toggle. In preload mode (default) the master
|
|
109
|
+
# parses config.ru once and workers inherit the loaded app via
|
|
110
|
+
# copy-on-write. In non-preload mode the master never touches
|
|
111
|
+
# the app; each worker parses post-fork. The non-preload path
|
|
112
|
+
# is the documented escape hatch for macOS getaddrinfo+fork
|
|
113
|
+
# deadlocks; it costs CoW (each worker pays the full boot RSS).
|
|
114
|
+
preload = config.preload != false
|
|
115
|
+
if preload
|
|
116
|
+
app = wrap_admin_middleware(load_rack_app(rackup), config)
|
|
117
|
+
else
|
|
118
|
+
app = nil
|
|
119
|
+
Hyperion.logger.info do
|
|
120
|
+
{ message: 'preload disabled; each worker will parse rackup after fork',
|
|
121
|
+
rackup: File.expand_path(rackup) }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
110
125
|
if workers <= 1
|
|
126
|
+
# Single-mode always preloads — there's no fork to protect from
|
|
127
|
+
# global state poisoning, so deferring the parse buys nothing.
|
|
128
|
+
app ||= wrap_admin_middleware(load_rack_app(rackup), config)
|
|
111
129
|
run_single(config, app)
|
|
112
130
|
else
|
|
113
|
-
run_cluster(config, app, workers)
|
|
131
|
+
run_cluster(config, app, workers, rackup_path: preload ? nil : File.expand_path(rackup))
|
|
114
132
|
end
|
|
115
133
|
end
|
|
116
134
|
|
|
@@ -258,6 +276,15 @@ WARNING: argv is visible via `ps`; prefer --admin-token-file PATH for production
|
|
|
258
276
|
'Explicit `--preload-static` dirs still take effect.') do
|
|
259
277
|
cli_opts[:auto_preload_static_disabled] = true
|
|
260
278
|
end
|
|
279
|
+
# 2.16 — app preload toggle.
|
|
280
|
+
o.on('--[no-]preload',
|
|
281
|
+
'Preload the Rack app in the master before fork (default ON). ' \
|
|
282
|
+
'--no-preload makes each worker parse config.ru post-fork; ' \
|
|
283
|
+
'needed on macOS when native gems loaded in the master ' \
|
|
284
|
+
'(anything that touches Network.framework via XPC) ' \
|
|
285
|
+
'deadlock getaddrinfo in workers post-fork.') do |v|
|
|
286
|
+
cli_opts[:preload] = v
|
|
287
|
+
end
|
|
261
288
|
o.on('-h', '--help', 'show help') do
|
|
262
289
|
puts o
|
|
263
290
|
exit 0
|
|
@@ -345,20 +372,22 @@ WARNING: argv is visible via `ps`; prefer --admin-token-file PATH for production
|
|
|
345
372
|
Hyperion.logger.flush_all
|
|
346
373
|
end
|
|
347
374
|
|
|
348
|
-
def self.run_cluster(config, app, workers)
|
|
375
|
+
def self.run_cluster(config, app, workers, rackup_path: nil)
|
|
349
376
|
tls = build_tls_from_config(config)
|
|
350
377
|
Master.new(host: config.host, port: config.port, app: app,
|
|
351
378
|
workers: workers, tls: tls, thread_count: config.thread_count,
|
|
352
|
-
read_timeout: config.read_timeout, config: config
|
|
379
|
+
read_timeout: config.read_timeout, config: config,
|
|
380
|
+
rackup_path: rackup_path).run
|
|
353
381
|
end
|
|
354
382
|
|
|
355
383
|
# Rack 3's parse_file returns a single app value; Rack 2 returned [app, options].
|
|
356
|
-
# Normalize so we get just the app either way.
|
|
384
|
+
# Normalize so we get just the app either way. Used by both the preload
|
|
385
|
+
# path (master parses once, before fork) and the non-preload path
|
|
386
|
+
# (each worker parses post-fork) — see Worker#run.
|
|
357
387
|
def self.load_rack_app(path)
|
|
358
388
|
result = ::Rack::Builder.parse_file(path)
|
|
359
389
|
result.is_a?(Array) ? result.first : result
|
|
360
390
|
end
|
|
361
|
-
private_class_method :load_rack_app
|
|
362
391
|
|
|
363
392
|
def self.build_tls_from_config(config)
|
|
364
393
|
return nil unless config.tls_cert || config.tls_key
|
|
@@ -610,7 +639,6 @@ WARNING: argv is visible via `ps`; prefer --admin-token-file PATH for production
|
|
|
610
639
|
end
|
|
611
640
|
AdminMiddleware.new(app, token: config.admin.token)
|
|
612
641
|
end
|
|
613
|
-
private_class_method :wrap_admin_middleware
|
|
614
642
|
|
|
615
643
|
# Read the admin token from a file on disk. Refuses to load if the file
|
|
616
644
|
# is missing, unreadable, or world-readable — the whole point of using a
|
data/lib/hyperion/config.rb
CHANGED
|
@@ -71,7 +71,25 @@ module Hyperion
|
|
|
71
71
|
# the `--no-preload-static` CLI flag; lets operators turn off
|
|
72
72
|
# auto-warming on a Rails app while still keeping the option to
|
|
73
73
|
# configure explicit dirs via `preload_static`.
|
|
74
|
-
auto_preload_static_disabled: false
|
|
74
|
+
auto_preload_static_disabled: false,
|
|
75
|
+
# 2.16: app preload toggle. When true (default) the master loads
|
|
76
|
+
# `config.ru` once before forking — workers inherit the loaded app
|
|
77
|
+
# via copy-on-write, the canonical Hyperion model. When false, the
|
|
78
|
+
# master stays a thin supervisor and each worker parses `config.ru`
|
|
79
|
+
# itself post-fork. Mirrors Puma's `preload_app! false` mode.
|
|
80
|
+
#
|
|
81
|
+
# The non-preload mode is the documented escape hatch for macOS
|
|
82
|
+
# workloads where loading native gems in the master (anything that
|
|
83
|
+
# initializes Network.framework / CoreFoundation via XPC) leaves
|
|
84
|
+
# the post-fork resolver in a deadlocked state — `getaddrinfo`
|
|
85
|
+
# hangs forever in `nw_path_evaluator_evaluate`. Setting `preload
|
|
86
|
+
# false` keeps the master's address space free of those globals so
|
|
87
|
+
# workers fork from a clean slate.
|
|
88
|
+
#
|
|
89
|
+
# Trade-off: each worker pays the boot cost (CPU + RSS) on its own,
|
|
90
|
+
# so steady-state RSS is N× higher and worker boot is slower. Linux
|
|
91
|
+
# users should leave this true.
|
|
92
|
+
preload: true
|
|
75
93
|
}.freeze
|
|
76
94
|
|
|
77
95
|
HOOKS = %i[before_fork on_worker_boot on_worker_shutdown].freeze
|
data/lib/hyperion/master.rb
CHANGED
|
@@ -68,10 +68,15 @@ module Hyperion
|
|
|
68
68
|
|
|
69
69
|
def initialize(host:, port:, app:, workers: DEFAULT_WORKER_COUNT,
|
|
70
70
|
read_timeout: Server::DEFAULT_READ_TIMEOUT_SECONDS, tls: nil,
|
|
71
|
-
thread_count: Server::DEFAULT_THREAD_COUNT, config: nil
|
|
71
|
+
thread_count: Server::DEFAULT_THREAD_COUNT, config: nil,
|
|
72
|
+
rackup_path: nil)
|
|
72
73
|
@host = host
|
|
73
74
|
@port = port
|
|
74
75
|
@app = app
|
|
76
|
+
# 2.16 — non-preload mode: master holds a path; each worker parses
|
|
77
|
+
# post-fork. Mutually exclusive with @app (asserted by CLI flow:
|
|
78
|
+
# exactly one of the two is non-nil).
|
|
79
|
+
@rackup_path = rackup_path
|
|
75
80
|
@workers = workers || Etc.nprocessors
|
|
76
81
|
@read_timeout = read_timeout
|
|
77
82
|
@tls = tls
|
|
@@ -118,7 +123,13 @@ module Hyperion
|
|
|
118
123
|
# BEFORE we fork. Children inherit the warm memory via copy-on-write
|
|
119
124
|
# so the first batch of requests on each fresh worker doesn't pay
|
|
120
125
|
# the allocation/autoload tax.
|
|
121
|
-
|
|
126
|
+
#
|
|
127
|
+
# 2.16: skipped in non-preload mode. The whole point of `preload:
|
|
128
|
+
# false` is to keep the master's address space free of native-gem
|
|
129
|
+
# globals (OpenSSL session caches, Network.framework XPC state,
|
|
130
|
+
# etc.) so workers fork from a clean slate. Warming up here would
|
|
131
|
+
# re-introduce exactly the state we're trying to avoid.
|
|
132
|
+
Hyperion.warmup! if @app
|
|
122
133
|
|
|
123
134
|
# `before_fork` runs ONCE in the master before any worker is forked.
|
|
124
135
|
# Operators use it to close shared resources (DB pools, Redis sockets)
|
|
@@ -226,6 +237,10 @@ module Hyperion
|
|
|
226
237
|
Signal.trap('TERM', 'DEFAULT')
|
|
227
238
|
worker_args = {
|
|
228
239
|
host: @host, port: @port, app: @app,
|
|
240
|
+
# 2.16 — propagate the deferred rackup path. Worker#run loads
|
|
241
|
+
# via Hyperion::CLI.load_rack_app + wraps admin middleware
|
|
242
|
+
# post-fork when @app is nil.
|
|
243
|
+
rackup_path: @rackup_path,
|
|
229
244
|
read_timeout: @read_timeout, tls: @tls,
|
|
230
245
|
thread_count: @thread_count, config: @config,
|
|
231
246
|
worker_index: worker_index,
|
data/lib/hyperion/version.rb
CHANGED
data/lib/hyperion/worker.rb
CHANGED
|
@@ -30,7 +30,8 @@ module Hyperion
|
|
|
30
30
|
io_uring: :off,
|
|
31
31
|
max_in_flight_per_conn: nil,
|
|
32
32
|
tls_handshake_rate_limit: :unlimited,
|
|
33
|
-
preload_static_dirs: nil
|
|
33
|
+
preload_static_dirs: nil,
|
|
34
|
+
rackup_path: nil)
|
|
34
35
|
@host = host
|
|
35
36
|
@port = port
|
|
36
37
|
@app = app
|
|
@@ -57,6 +58,7 @@ module Hyperion
|
|
|
57
58
|
@max_in_flight_per_conn = max_in_flight_per_conn
|
|
58
59
|
@tls_handshake_rate_limit = tls_handshake_rate_limit
|
|
59
60
|
@preload_static_dirs = preload_static_dirs
|
|
61
|
+
@rackup_path = rackup_path
|
|
60
62
|
end
|
|
61
63
|
|
|
62
64
|
def run
|
|
@@ -70,6 +72,19 @@ module Hyperion
|
|
|
70
72
|
}
|
|
71
73
|
end
|
|
72
74
|
|
|
75
|
+
# 2.16 — non-preload mode: master never loaded the Rack app, so we
|
|
76
|
+
# parse it here, post-fork. Native gems load against THIS process's
|
|
77
|
+
# address space, not the master's, which avoids the macOS
|
|
78
|
+
# Network.framework + fork getaddrinfo deadlock (where post-fork
|
|
79
|
+
# XPC peers are wedged forever in `nw_path_evaluator_evaluate`).
|
|
80
|
+
if @app.nil? && @rackup_path
|
|
81
|
+
require_relative 'cli'
|
|
82
|
+
@app = ::Hyperion::CLI.wrap_admin_middleware(
|
|
83
|
+
::Hyperion::CLI.load_rack_app(@rackup_path),
|
|
84
|
+
@config
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
73
88
|
server = Server.new(host: @host, port: @port, app: @app,
|
|
74
89
|
read_timeout: @read_timeout, tls: @tls,
|
|
75
90
|
thread_count: @thread_count,
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hyperion-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrey Lobanov
|
|
@@ -154,6 +154,7 @@ files:
|
|
|
154
154
|
- CHANGELOG.md
|
|
155
155
|
- LICENSE
|
|
156
156
|
- README.md
|
|
157
|
+
- bin/check
|
|
157
158
|
- bin/hyperion
|
|
158
159
|
- ext/hyperion_h2_codec/Cargo.lock
|
|
159
160
|
- ext/hyperion_h2_codec/Cargo.toml
|