tep 0.11.4 → 0.11.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: 440ba4bc444318eb021fa61653935297e7fee6876f7ce09e06bd45e091f5a14a
4
- data.tar.gz: 3babc819f652798441f6f9ecc0f088afb398dae0e977186e9bb3c3e9fc455562
3
+ metadata.gz: 33b663dcc38571d71f8a729f7ed1f8da6ea8a89e1eb6bd49619beac977da2727
4
+ data.tar.gz: af7b47e7e3440372325744d1274e70e41216db757ac224ca2364c1a422b5064a
5
5
  SHA512:
6
- metadata.gz: 514652e89448eef94073b1680228ccbc876f53df63712f580f1c3c8e8b50b0852d0630f456ca26df93844456d7b124ee1681c794e997d41dffd8299e8cb3058d
7
- data.tar.gz: be8785d792ad05e0dcde98a04aba8426b967230a42797e47d1536ad67057a7f78bf03f23ded9194c0abd10d3e33c8d0b6023964e7735020d2ca002fb0afc90d1
6
+ metadata.gz: ed5ce816c591c5464d624e3094798d3ce8c8c03c7128e3881541cf874a0735e62f468d7d4f781e793e6ae02f2bcb642119fdc49157394acb69cb027a014d9b6e
7
+ data.tar.gz: 484a1cdae65a65cbe5da98d8c2aa22add1b4a562e35ab7cfb38f9137856bcad77ad773b07d191fb425a5e6307fe18a71856d47ad3766e8a03191622314ba2989
data/Makefile CHANGED
@@ -34,6 +34,16 @@ TEP_PG_LIBS ?= $(shell \
34
34
  (pg_config --libdir 2>/dev/null | sed -e 's|^|-L|' ; echo "-lpq") | tr '\n' ' ')
35
35
  export TEP_PG_CFLAGS TEP_PG_LIBS
36
36
 
37
+ # OpenSSL cflags / libs for sphttp.c's outbound-TLS include (#148). On Linux
38
+ # the headers/libs are on the default search path so this is usually empty;
39
+ # on macOS Homebrew keeps openssl@3 keg-only (/opt/homebrew/opt/openssl@3),
40
+ # off the default path, so pkg-config supplies the -I (compile) and -L/-lssl
41
+ # /-lcrypto (link). If pkg-config can't find openssl, fall back to the bare
42
+ # libs and let the include path come from the system default.
43
+ TEP_SPHTTP_CFLAGS ?= $(shell pkg-config --cflags openssl 2>/dev/null)
44
+ TEP_SPHTTP_LIBS ?= $(shell pkg-config --libs openssl 2>/dev/null || echo "-lssl -lcrypto")
45
+ export TEP_SPHTTP_CFLAGS TEP_SPHTTP_LIBS
46
+
37
47
  .PHONY: all clean helper hello sinatra_style bench bench-tep bench-sinatra demo test test-parallel spinel-fresh test-pg vendor-examples vendor-spinelkit doctor
38
48
 
39
49
  # Re-sync the vendored SpinelKit lib (lib/spinel_kit/, sig/spinel_kit/) from the
@@ -73,7 +83,7 @@ all: spinel-fresh helper hello sinatra_style bench
73
83
  helper: spinel-fresh $(LIB_DIR)/sphttp.o $(LIB_DIR)/tep_sqlite.o $(LIB_DIR)/tep_pg.o
74
84
 
75
85
  $(LIB_DIR)/sphttp.o: $(LIB_DIR)/sphttp.c
76
- cc -O2 -c $< -o $@
86
+ cc -O2 -c $(TEP_SPHTTP_CFLAGS) $< -o $@
77
87
 
78
88
  $(LIB_DIR)/tep_sqlite.o: $(LIB_DIR)/tep_sqlite.c
79
89
  cc -O2 -c $< -o $@
data/README.md CHANGED
@@ -4,37 +4,41 @@
4
4
 
5
5
  # Tep
6
6
 
7
- A Sinatra-flavoured web framework that compiles to a native binary
8
- via [Spinel][spinel].
7
+ A Sinatra-flavoured web framework that compiles to a **native binary**
8
+ via [Spinel][spinel]. You write a Sinatra-style `app.rb`:
9
9
 
10
- > **Current release:** [v0.11.0](https://github.com/OriPekelman/tep/releases/tag/v0.11.0)
11
- > — now on [RubyGems](https://rubygems.org/gems/tep) (`gem install tep`):
12
- > TLS, HTTP caching, connection pooling, PG raise-on-error + embeddings,
13
- > on top of the agentic surface (Auth, Broadcast, Presence, LiveView, MCP).
10
+ ```ruby
11
+ require 'sinatra'
12
+
13
+ get '/hi/:name' do
14
+ "hi, " + params[:name] + "!"
15
+ end
16
+ ```
17
+
18
+ …and get `./app` — a single static executable, ~80 KB, **no Ruby
19
+ runtime**, doing ~150k req/s. Beyond routing / sessions / templates, the
20
+ [batteries ↓](#whats-in-the-box) cover auth (bearer / cookie / OAuth2),
21
+ SQLite, opt-in PostgreSQL, WebSockets, Broadcast + Presence + LiveView,
22
+ an MCP tool catalog, TLS, a pooled HTTP client, and an OpenAI-compatible
23
+ LLM client + server.
24
+
25
+ > **Current release:** [v0.11.6](https://github.com/OriPekelman/tep/releases/tag/v0.11.6)
26
+ > on [RubyGems](https://rubygems.org/gems/tep) — `gem install tep`.
14
27
  > Pre-alpha; API still in motion.
15
28
 
16
- > **Why Tep exists.** Two complementary goals:
17
- >
18
- > 1. **Exercise Spinel against real-world Ruby code.** Tep is the
19
- > largest pure-Ruby application Spinel compiles end-to-end. Every
20
- > Sinatra idiom, every battery, every demo doubles as a torture
21
- > test for the AOT compiler's codegen + analyzer. Bugs surface
22
- > here, get reduced to minimal repros, and land upstream as PRs
23
- > or issues against [matz/spinel](https://github.com/matz/spinel).
24
- > If something doesn't work in Tep, the bug is usually in Spinel,
25
- > and that's the point.
26
- >
27
- > 2. **Be the harness for [toy][toy].** Toy is Tep's sibling
28
- > project: a machine-learning framework written in pure Ruby and
29
- > compiled by Spinel. Toy needs an HTTP/MCP layer for serving
30
- > models, exposing training tools to agents (Claude Code et al.),
31
- > streaming inference results, and wiring presence into
32
- > collaborative training sessions. Tep is that layer. Every
33
- > battery in Tep is shaped by what Toy actually needs to ship.
34
- >
35
- > Tep happens to be useful as a general web framework too — fast,
36
- > single-binary, Sinatra-shaped — but the design choices are made
37
- > through these two lenses.
29
+ <details>
30
+ <summary><b>Why Tep exists</b> — it's a deliberate Spinel torture test + toy's serving layer</summary>
31
+
32
+ Tep is the largest pure-Ruby application Spinel compiles end-to-end:
33
+ every Sinatra idiom and battery doubles as a torture test for the AOT
34
+ compiler's codegen + analyzer, and bugs found here get reduced to
35
+ minimal repros and land upstream as
36
+ [matz/spinel](https://github.com/matz/spinel) PRs. It's also the
37
+ HTTP / MCP / serving layer for its sibling [toy][toy] a pure-Ruby ML
38
+ framework Spinel compiles — so every battery is shaped by what toy
39
+ needs to ship. Tep is a genuinely useful general web framework too, but
40
+ the design choices are made through those two lenses.
41
+ </details>
38
42
 
39
43
  [toy]: https://github.com/OriPekelman/toy
40
44
 
@@ -107,7 +111,7 @@ gem install. Recommended Ruby manager:
107
111
  [`rv`](https://github.com/spinel-coop/rv) — fast version+gem
108
112
  manager from the Spinel Cooperative (separate project from the
109
113
  matz/spinel AOT compiler Tep compiles through; same Ruby
110
- neighbourhood). `.ruby-version` in this repo pins 3.4.0; `rv
114
+ neighbourhood). `.ruby-version` in this repo pins 4.0.0; `rv
111
115
  shell` makes `rv run rake test` just work. Build deps on Linux:
112
116
  `build-essential`, `libsqlite3-dev`. macOS: Xcode CLI tools.
113
117
 
@@ -174,7 +178,7 @@ through Spinel.
174
178
  | `Tep::WebSocket` | RFC 6455 server-side WebSocket. `websocket '/chat' do \|ws\| ... end` DSL lowers to Frame + Handshake + Driver + Connection. Requires `set :scheduler, :scheduled`. |
175
179
  | `Tep::Parallel` | grosser/parallel-shaped fork fan-out. |
176
180
  | `Tep::Job` | sidekiq-shaped queue over SQLite. |
177
- | `PG` | ruby-pg-shape libpq client: `PG::Connection`, `PG::Result`, `PG::Error`; surface mirrors the `pg` gem (`exec` / `exec_params` / `escape_*` / `fields` / `values` / `getvalue` / `sql_state`). Designed so an eventual ActiveRecord-on-spinel port reuses the existing AR adapter with minimal divergence — see `docs/PG-BATTERY.md`. |
181
+ | `PG` | **Opt-in** ruby-pg-shape libpq client `require "tep/pg"` (so non-PG apps don't link libpq). `PG::Connection`, `PG::Result`, `PG::Error`; surface mirrors the `pg` gem (`exec` / `exec_params` / `escape_*` / `fields` / `values` / `getvalue` / `sql_state`). Designed so an eventual ActiveRecord-on-spinel port reuses the existing AR adapter with minimal divergence — see `docs/PG-BATTERY.md`. |
178
182
  | `Tep::Auth` | Principal+delegate identity (`Tep::Identity` / `Tep::AgentDelegation`) + provider chain. Three providers shipped: `Tep::AuthBearerToken` (JWT-HS256), `Tep::AuthSessionCookie` (signed cookie), `Tep::AuthOAuth2` (authorization-code grant issuance for bots/agents). Same `req.identity` surface regardless of provider; agents are first-class (`identity.agent?`, `identity.acting_via.agent_id`, capability subsetting). |
179
183
  | `Tep::Broadcast` | In-process pub-sub + cross-worker via PG LISTEN/NOTIFY. Subscribe an fd to a topic (`subscribe` raw, `subscribe_ws` WS-frame-wrapped); publish writes to every matching subscriber. The seam Presence and LiveView build on. |
180
184
  | `Tep::Presence` | Topic-keyed who's-here registry, agent-aware. `Tep::Presence.track(req, topic, fd)` records a (principal, session, topic) tuple with a 3-state structured status (`:available | :busy | :blocked` + free-text note + expiry). Diffs broadcast on join/leave/status; PG-mirror for cross-worker `list_global` snapshots. |
data/bin/tep CHANGED
@@ -1366,6 +1366,30 @@ def handle_top_call(node, routes, websockets, mcp_tools, mcp_resources, filters,
1366
1366
 
1367
1367
  case name
1368
1368
  when "require", "require_relative"
1369
+ # tep/pg is OPT-IN (#216): it is NOT part of the wholesale-inlined
1370
+ # core (lib/tep.rb no longer require_relative's it). An app, test, or
1371
+ # example that needs PostgreSQL says `require "tep/pg"` (or, by path,
1372
+ # `require_relative ".../lib/tep/pg"`); we splice lib/tep/pg.rb in
1373
+ # once here. A non-PG app never names it, so the whole pg closure
1374
+ # (the 74 tep_pg_* FFI symbols + libpq) DCEs away. This must run
1375
+ # BEFORE the is_tep_lib no-op below, which would otherwise swallow
1376
+ # any "tep/..." spelling as already-inlined.
1377
+ pg_arg = node.arguments&.arguments&.first
1378
+ if pg_arg.is_a?(Prism::StringNode) &&
1379
+ (pg_arg.unescaped == "tep/pg" || pg_arg.unescaped.end_with?("/tep/pg"))
1380
+ pgpath = File.join(LIB_DIR, "tep", "pg.rb")
1381
+ if inlined_seen && File.file?(pgpath) && !inlined_seen[pgpath]
1382
+ pgtext = inline_require_relative_tree(pgpath, inlined_seen, warnings)
1383
+ # Resolve pg.rb's @TEP_PG_O@ / @TEP_PG_CFLAGS@ placeholders the
1384
+ # same way inlined_tep_library does for the wholesale core -- the
1385
+ # opt-in splice bypasses that pass, so without this the literal
1386
+ # placeholders reach the linker ("ld: cannot find @TEP_PG_O@").
1387
+ tep_ext_subs.each { |placeholder, value| pgtext = pgtext.gsub(placeholder, value) }
1388
+ passthrough << "# --- inlined opt-in require #{pg_arg.unescaped.inspect} (pg.rb) ---"
1389
+ passthrough << pgtext
1390
+ end
1391
+ return
1392
+ end
1369
1393
  # tep's own library is inlined wholesale (see inlined_tep_library), so
1370
1394
  # `require_relative "tep"` / "tep/..." is a no-op. A plain `require
1371
1395
  # "gem"` (by name) is dropped -- spinel has no gem load path. But an
@@ -1586,7 +1610,14 @@ def rewrite_block(src, force_string: true)
1586
1610
  # are handled separately so they can contain commas or spaces.
1587
1611
  pairs = $2.scan(/(\w+):\s*("[^"]*"|'[^']*'|[^,}]+?)\s*(?=,|\z)/)
1588
1612
  setters = pairs.map { |k, v| %{__l["#{k}"] = (#{v.strip}).to_s} }.join("; ")
1589
- "(__l = Tep.str_hash; #{setters}; tep_view_#{view}(__l, req.ivars))"
1613
+ # Build the locals hash INSIDE the first argument (a sequence
1614
+ # expression that returns __l), rather than `(__l = ...; render(__l))`
1615
+ # with __l a bare arg. In the latter shape spinel (recent master)
1616
+ # hoists the `render`'s arg temp -- `_t = __l` -- above the in-sequence
1617
+ # `__l = str_hash()` assignment, so render receives the pre-assignment
1618
+ # (empty) hash and every interpolated value blanks (matz/spinel#1478).
1619
+ # Keeping the assignment inside the arg evaluation defeats the hoist.
1620
+ "tep_view_#{view}((__l = Tep.str_hash; #{setters}; __l), req.ivars)"
1590
1621
  end
1591
1622
  s = s.gsub(/(?<![\w.])erb\s+:(\w+)/, 'tep_view_\1(Tep.str_hash, req.ivars)')
1592
1623
 
@@ -1595,7 +1626,8 @@ def rewrite_block(src, force_string: true)
1595
1626
  view = $1
1596
1627
  pairs = $2.scan(/(\w+):\s*("[^"]*"|'[^']*'|[^,}]+?)\s*(?=,|\z)/)
1597
1628
  setters = pairs.map { |k, v| %{__l["#{k}"] = (#{v.strip}).to_s} }.join("; ")
1598
- "(__l = Tep.str_hash; #{setters}; tep_mustache_#{view}(__l, req.ivars))"
1629
+ # Same arg-hoist avoidance as the erb form above (matz/spinel#1478).
1630
+ "tep_mustache_#{view}((__l = Tep.str_hash; #{setters}; __l), req.ivars)"
1599
1631
  end
1600
1632
  s = s.gsub(/(?<![\w.])mustache\s+:(\w+)/, 'tep_mustache_\1(Tep.str_hash, req.ivars)')
1601
1633
 
@@ -1947,7 +1979,11 @@ def tep_ext_subs
1947
1979
  else
1948
1980
  cflags = ENV.fetch(env_var, "")
1949
1981
  libs_var = env_var.sub(/_CFLAGS\z/, "_LIBS")
1950
- default_libs = entry["pkg_config"] ? "-l" + entry["pkg_config"].sub(/\Alib/, "") : ""
1982
+ # Prefer an explicit pkg_config_fallback (e.g. openssl -> "-lssl
1983
+ # -lcrypto"); the bare "-l<pkg_config>" derivation is only right when
1984
+ # the lib name matches the .pc name (libpq -> -lpq), not for openssl.
1985
+ default_libs = entry["pkg_config_fallback"] ||
1986
+ (entry["pkg_config"] ? "-l" + entry["pkg_config"].sub(/\Alib/, "") : "")
1951
1987
  libs = ENV.fetch(libs_var, default_libs)
1952
1988
  subs[placeholder] = "#{cflags} #{libs}".strip
1953
1989
  end
@@ -1979,7 +2015,16 @@ def resolve_ext_o(entry, entries, env_var)
1979
2015
  entries.each do |sib|
1980
2016
  next unless sib["name"] == entry["name"] && sib["pkg_config"]
1981
2017
  pc = `pkg-config --cflags #{sib["pkg_config"]} 2>/dev/null`
1982
- $?.success? ? cflags.concat(pc.split) : (missing = sib["pkg_config"])
2018
+ if $?.success?
2019
+ cflags.concat(pc.split)
2020
+ elsif sib["pkg_config_fallback"]
2021
+ # pkg-config can't find a .pc (e.g. openssl on a host without it):
2022
+ # assume the headers are on the default include path -- the
2023
+ # historical behavior before this sibling existed -- and let the
2024
+ # link use the fallback libs. Don't fail an otherwise-fine compile.
2025
+ else
2026
+ missing = sib["pkg_config"]
2027
+ end
1983
2028
  end
1984
2029
  if missing
1985
2030
  return "" if entry["optional"]
data/examples/pg_hello.rb CHANGED
@@ -16,6 +16,7 @@
16
16
  # today (matz/spinel#627). Once that lands, this example collapses
17
17
  # to the AR-shape `rescue PG::Error => e`.
18
18
  require_relative "../lib/tep"
19
+ require_relative "../lib/tep/pg" # opt-in PG backend (#216)
19
20
 
20
21
  PG_URL = ENV["PG_URL"] != nil && ENV["PG_URL"].length > 0 ? ENV["PG_URL"] : "postgresql:///postgres"
21
22
 
@@ -67,7 +68,17 @@ get '/error' do
67
68
  out = "rescued PG::UndefinedTable\n" +
68
69
  "sqlstate: " + c.last_sqlstate + "\n" +
69
70
  "is undefined-table? " + (c.last_sqlstate == "42P01" ? "yes" : "no") + "\n" +
70
- "is PG::Error? " + (e.is_a?(PG::Error) ? "yes" : "no") + "\n" +
71
+ # WORKAROUND -- still open at SPINEL_PIN (re-checked at the
72
+ # ad2b71ad re-pin: `e.is_a?(PG::Error)` here is rejected as
73
+ # `unsupported call: is_a? recv=LocalVariableRead argc=1`).
74
+ # `e` is the rescued exception, typed PG::UndefinedTable -- a
75
+ # whole-program is_a? against the namespaced ancestor PG::Error
76
+ # isn't lowered yet. Minimal `rescue Sub => e; e.is_a?(Super)`
77
+ # compiles fine; only the full program trips it. Since `e` is
78
+ # always a PG::Error subclass here, hardcode "yes". Restore
79
+ # (e.is_a?(PG::Error) ? "yes" : "no")
80
+ # once is_a?-on-rescued-namespaced-ancestor lowers. See tep#196.
81
+ "is PG::Error? " + "yes" + "\n" +
71
82
  "message: " + e.message
72
83
  end
73
84
  c.close
data/lib/tep/broadcast.rb CHANGED
@@ -114,14 +114,21 @@ module Tep
114
114
  # remote deliveries are best-effort and not counted here.
115
115
  def self.publish(topic, payload)
116
116
  matched = Tep::Broadcast.publish_local_only(topic, payload)
117
- if Tep::APP.broadcast_pg_enabled != 0
118
- wire = Tep::Broadcast.encode_wire(topic, payload)
119
- Tep::APP.broadcast_pg_conn.notify(
120
- Tep::APP.broadcast_pg_channel, wire)
121
- end
117
+ # Cross-worker fan-out is an OPT-IN hook (#216): the core build
118
+ # has no PG reference, so a non-PG app DCEs the entire libpq
119
+ # closure. `require "tep/pg"` redefines cross_worker_notify with
120
+ # the real broadcast_pg_conn.notify (last-definition-wins).
121
+ Tep::Broadcast.cross_worker_notify(topic, payload)
122
122
  matched
123
123
  end
124
124
 
125
+ # No-op cross-worker hook. Overridden by lib/tep/pg.rb when the PG
126
+ # backend is loaded. Keeping the PG NOTIFY out of core is what lets
127
+ # `Tep::Broadcast.publish` compile without pulling tep_pg_*/libpq.
128
+ def self.cross_worker_notify(topic, payload)
129
+ 0
130
+ end
131
+
125
132
  # Total subscription count across all topics. Useful for
126
133
  # diagnostics and the v1 test surface.
127
134
  def self.subscriber_count
@@ -157,81 +164,12 @@ module Tep
157
164
 
158
165
  # ---- PG backend (cross-worker pub/sub) ----
159
166
  #
160
- # Opens a dedicated PG connection and issues `LISTEN <channel>`.
161
- # Subsequent publishes NOTIFY this channel too -- other workers
162
- # subscribed to the same channel can receive the message via
163
- # poll_pg_once.
164
- #
165
- # `conninfo` is the libpq connect string. `channel` must be a
166
- # safe SQL identifier (e.g. "tep_broadcast") since it lands
167
- # inside a LISTEN / NOTIFY command unescaped.
168
- #
169
- # Returns 0 on success, -1 on connection or LISTEN failure.
170
- def self.enable_pg_backend(conninfo, channel)
171
- conn = PG::Connection.new(conninfo)
172
- if conn.pgh < 0
173
- return -1
174
- end
175
- if conn.listen(channel) < 0
176
- return -1
177
- end
178
- Tep::APP.set_broadcast_pg_conn(conn)
179
- Tep::APP.set_broadcast_pg_channel(channel)
180
- Tep::APP.set_broadcast_pg_enabled(1)
181
- 0
182
- end
183
-
184
- def self.disable_pg_backend
185
- if Tep::APP.broadcast_pg_enabled == 0
186
- return 0
187
- end
188
- Tep::APP.broadcast_pg_conn.unlisten(Tep::APP.broadcast_pg_channel)
189
- Tep::APP.broadcast_pg_conn.finish
190
- Tep::APP.set_broadcast_pg_enabled(0)
191
- 0
192
- end
193
-
194
- # Process one notification from the PG channel: parse the wire
195
- # format, dispatch to local subscribers as if `publish` had
196
- # been called locally (but WITHOUT re-NOTIFYing -- that would
197
- # loop). Returns 1 if a notification was processed, 0 on
198
- # timeout, -1 on connection error or unenabled backend.
199
- def self.poll_pg_once(timeout_ms)
200
- if Tep::APP.broadcast_pg_enabled == 0
201
- return -1
202
- end
203
- r = Tep::APP.broadcast_pg_conn.poll_notification(timeout_ms)
204
- if r != 1
205
- return r
206
- end
207
- wire = Tep::APP.broadcast_pg_conn.last_notify_payload
208
- Tep::Broadcast.deliver_wire_local(wire)
209
- 1
210
- end
211
-
212
- # Wire format: "<topic_byte_length>:<topic><payload>".
213
- # Length-prefixed so topics and payloads with arbitrary chars
214
- # (commas, colons, embedded quotes, newlines) round-trip
215
- # unambiguously. Encoded by `publish` when the PG backend is
216
- # enabled; decoded by `deliver_wire_local`.
217
- def self.encode_wire(topic, payload)
218
- topic.length.to_s + ":" + topic + payload
219
- end
220
-
221
- def self.deliver_wire_local(wire)
222
- colon = Tep.str_find(wire, ":", 0)
223
- if colon <= 0
224
- return -1
225
- end
226
- len_str = wire[0, colon]
227
- tlen = len_str.to_i
228
- if tlen < 0 || colon + 1 + tlen > wire.length
229
- return -1
230
- end
231
- topic = wire[colon + 1, tlen]
232
- payload = wire[colon + 1 + tlen, wire.length - colon - 1 - tlen]
233
- Tep::Broadcast.publish_local_only(topic, payload)
234
- end
167
+ # The PG LISTEN/NOTIFY backend is OPT-IN (#216). enable_pg_backend /
168
+ # disable_pg_backend / poll_pg_once, plus the wire encode/decode
169
+ # helpers (encode_wire / deliver_wire_local) and the
170
+ # cross_worker_notify override, live in lib/tep/pg.rb and only
171
+ # compile into apps that `require "tep/pg"`. Core Broadcast carries
172
+ # no PG reference so a non-PG app DCEs the libpq closure entirely.
235
173
 
236
174
  # Same fan-out as #publish but skips the PG NOTIFY step. Used
237
175
  # internally by poll_pg_once when delivering a cross-worker
data/lib/tep/net.rb CHANGED
@@ -12,9 +12,14 @@ module Sock
12
12
  # libssl/libcrypto. Linked for every app (like sqlite3 elsewhere);
13
13
  # the plaintext path never calls into it, so apps that make no HTTPS
14
14
  # requests pay only the link cost, not runtime. See tep#148.
15
- # (When OpenSSL is off the default path -- macOS/Homebrew -- the build
16
- # finds it via CPATH/LIBRARY_PATH in the environment, not a cflag
17
- # here; spinel's ffi_cflags rejects an empty-string placeholder.)
15
+ #
16
+ # OpenSSL include/lib paths come via @TEP_SPHTTP_CFLAGS@ (the
17
+ # pkg_config sibling in spinel-ext.json -- `pkg-config openssl`,
18
+ # fallback `-lssl -lcrypto`), mirroring @TEP_PG_CFLAGS@. On Linux it's
19
+ # often just the libs (headers on the default path); on macOS/Homebrew
20
+ # it supplies the keg-only -I/-L too, so sphttp.c compiles + the
21
+ # ffi_lib "ssl"/"crypto" below resolve. See tep#208.
22
+ ffi_cflags "@TEP_SPHTTP_CFLAGS@"
18
23
  ffi_lib "ssl"
19
24
  ffi_lib "crypto"
20
25