connectrpc 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +501 -0
- data/docs/design.md +504 -0
- data/docs/development.md +566 -0
- data/docs/grpc-web.md +165 -0
- data/docs/grpc.md +75 -0
- data/docs/rbs.md +469 -0
- data/docs/streaming.md +251 -0
- data/exe/protoc-gen-connectrpc-ruby +23 -0
- data/lib/connectrpc/bindings/descriptors/status.bin +15 -0
- data/lib/connectrpc/bindings/google_protobuf.rb +92 -0
- data/lib/connectrpc/cancellation.rb +220 -0
- data/lib/connectrpc/client.rb +260 -0
- data/lib/connectrpc/compression.rb +120 -0
- data/lib/connectrpc/deadline.rb +81 -0
- data/lib/connectrpc/error.rb +72 -0
- data/lib/connectrpc/generator/names.rb +105 -0
- data/lib/connectrpc/generator/rbs_renderer.rb +93 -0
- data/lib/connectrpc/generator/renderer.rb +115 -0
- data/lib/connectrpc/generator/runtime_names.rb +84 -0
- data/lib/connectrpc/generator/schema.rb +218 -0
- data/lib/connectrpc/generator/streaming_methods.rb +29 -0
- data/lib/connectrpc/generator.rb +42 -0
- data/lib/connectrpc/get_query.rb +159 -0
- data/lib/connectrpc/grpc.rb +200 -0
- data/lib/connectrpc/grpc_client.rb +23 -0
- data/lib/connectrpc/grpc_server.rb +158 -0
- data/lib/connectrpc/grpc_web.rb +131 -0
- data/lib/connectrpc/grpc_web_cors.rb +135 -0
- data/lib/connectrpc/grpc_web_io.rb +156 -0
- data/lib/connectrpc/grpc_web_server.rb +207 -0
- data/lib/connectrpc/instrumentation.rb +216 -0
- data/lib/connectrpc/message_io.rb +47 -0
- data/lib/connectrpc/metadata.rb +105 -0
- data/lib/connectrpc/method.rb +68 -0
- data/lib/connectrpc/protocol.rb +189 -0
- data/lib/connectrpc/server.rb +398 -0
- data/lib/connectrpc/streaming/client.rb +104 -0
- data/lib/connectrpc/streaming/client_execution.rb +87 -0
- data/lib/connectrpc/streaming/client_scope.rb +105 -0
- data/lib/connectrpc/streaming/framing.rb +123 -0
- data/lib/connectrpc/streaming/framing_io.rb +61 -0
- data/lib/connectrpc/streaming/method.rb +33 -0
- data/lib/connectrpc/streaming/server.rb +122 -0
- data/lib/connectrpc/streaming/server_execution.rb +88 -0
- data/lib/connectrpc/streaming/server_terminal.rb +70 -0
- data/lib/connectrpc/streaming/session.rb +143 -0
- data/lib/connectrpc/streaming/session_completion.rb +134 -0
- data/lib/connectrpc/streaming/session_io.rb +107 -0
- data/lib/connectrpc/streaming/session_messages.rb +119 -0
- data/lib/connectrpc/streaming/strategy.rb +95 -0
- data/lib/connectrpc/streaming/streams.rb +116 -0
- data/lib/connectrpc/streaming/terminal.rb +52 -0
- data/lib/connectrpc/transports/net_http.rb +246 -0
- data/lib/connectrpc/version.rb +5 -0
- data/lib/connectrpc.rb +38 -0
- data/rbs/google_protobuf_4_36/runtime.rbs +41 -0
- data/sig/connectrpc.rbs +772 -0
- data/sig/manifest.yaml +2 -0
- data/third_party/README.md +16 -0
- data/third_party/google/LICENSE +201 -0
- data/third_party/google/rpc/status.proto +48 -0
- data/third_party/protobuf-LICENSE +32 -0
- metadata +106 -0
data/docs/rbs.md
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# Public API signatures
|
|
2
|
+
|
|
3
|
+
The [supported 0.x contract](support.md) defines the target compatibility
|
|
4
|
+
boundary and the remaining adoption gates.
|
|
5
|
+
|
|
6
|
+
Every package ships its own gem-discovered signatures and dependency manifest.
|
|
7
|
+
Core also generates mixed unary/streaming service signatures. RBS
|
|
8
|
+
and Steep are development tools; neither is required by the runtime. Default
|
|
9
|
+
Connect generation produces exactly the same Ruby files as before. Only the
|
|
10
|
+
plugin parameter `rbs=true` adds `<stem>_connect.rbs` for each service-bearing
|
|
11
|
+
input. Unknown, duplicate, invalid and trailing parameters fail without files.
|
|
12
|
+
|
|
13
|
+
## Generate messages and services
|
|
14
|
+
|
|
15
|
+
Use protoc 36.2, google-protobuf 4.36.2, RBS 4.2.0 and Steep 2.1.0 for the
|
|
16
|
+
tested upstream message-signature path. Create `generated/`, then run the
|
|
17
|
+
installed plugin alongside the official Ruby and RBS generators:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
protoc -I proto --ruby_out=generated --rbs_out=generated \
|
|
21
|
+
--connectrpc-ruby_out=rbs=true:generated example.proto
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Use schema-relative input names with `-I`. Also generate
|
|
25
|
+
`--rbs_out` for imported message schemas. If your schema imports Timestamp or
|
|
26
|
+
Empty, include `google/protobuf/timestamp.proto` and
|
|
27
|
+
`google/protobuf/empty.proto` as additional compiler inputs. Their official
|
|
28
|
+
Ruby implementations may come from google-protobuf; their signatures must enter
|
|
29
|
+
the RBS environment too. The compiler's standard include directory supplies
|
|
30
|
+
these schemas. Other imports need their normal `-I` directories.
|
|
31
|
+
|
|
32
|
+
Buf 1.75.0 supports the official RBS builtin. An equivalent v2 template is:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
version: v2
|
|
36
|
+
plugins:
|
|
37
|
+
- protoc_builtin: ruby
|
|
38
|
+
out: generated
|
|
39
|
+
- protoc_builtin: rbs
|
|
40
|
+
out: generated
|
|
41
|
+
- local: protoc-gen-connectrpc-ruby
|
|
42
|
+
out: generated
|
|
43
|
+
opt: rbs=true
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Buf generates local inputs by default. Generate imported/WKT signatures with
|
|
47
|
+
protoc as above or include their schema closure in your generation inputs.
|
|
48
|
+
Connect emits service signatures only. It never generates or rewrites message
|
|
49
|
+
fields, constructors or official `_pb.rbs` output.
|
|
50
|
+
|
|
51
|
+
## Check an application
|
|
52
|
+
|
|
53
|
+
Select the small protobuf bridge explicitly in your Steepfile. It lives outside
|
|
54
|
+
the gem's automatically discovered `sig/`, so `library "connectrpc"` introduces
|
|
55
|
+
no Google declarations. With the gem installed, use a path relative to your
|
|
56
|
+
Steepfile for the bridge (Steep signature patterns use project-relative paths):
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
require "pathname"
|
|
60
|
+
bridge = Pathname(Gem::Specification.find_by_name("connectrpc").full_gem_path)
|
|
61
|
+
.join("rbs/google_protobuf_4_36")
|
|
62
|
+
.relative_path_from(Pathname(__dir__)).to_s
|
|
63
|
+
|
|
64
|
+
target :app do
|
|
65
|
+
library "connectrpc"
|
|
66
|
+
signature "generated", "sig", bridge
|
|
67
|
+
check "app"
|
|
68
|
+
configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run `bundle exec steep check` with your application's development bundle.
|
|
73
|
+
Strict diagnostics are required: Steep's defaults classify some incorrect
|
|
74
|
+
request constraints and assignments as hints, which do not fail a normal check.
|
|
75
|
+
The repository's `typecheck/consumers/` has executable positive and negative
|
|
76
|
+
examples, including concrete callable objects and inline lambdas. Each negative
|
|
77
|
+
file must produce exactly its expected diagnostic at its own source path.
|
|
78
|
+
|
|
79
|
+
The bridge is deliberately limited to the shapes emitted by protoc 36.2:
|
|
80
|
+
`AbstractMessage`, the empty `_MessageClass[T]` compatibility marker,
|
|
81
|
+
`RepeatedField` indexing/writing/appending, `Map` indexing/writing, enum
|
|
82
|
+
lookup/resolve, and descriptor-pool lookup/message-class/enum-module access.
|
|
83
|
+
Upstream literal lookup overloads retain specific message/enum tokens; arbitrary
|
|
84
|
+
lookup results stay opaque because the runtime can also return other descriptors.
|
|
85
|
+
It promises no collection iteration, Enumerable or Enumerator behavior. The
|
|
86
|
+
marker does not promise codec methods. The binding signature erases custom
|
|
87
|
+
runtime tokens at its encode/decode boundary instead of inventing a generic
|
|
88
|
+
decode association.
|
|
89
|
+
|
|
90
|
+
Official field signatures are best effort, as their generated header states.
|
|
91
|
+
They do not validate numeric ranges, serialization, every protobuf runtime API,
|
|
92
|
+
or arbitrary custom bindings. Do not combine this bridge with the old
|
|
93
|
+
collection google-protobuf 3.22 signatures, whose collection shapes differ.
|
|
94
|
+
Applications supplying protobuf runtime signatures must omit the bridge.
|
|
95
|
+
|
|
96
|
+
## Keep application-owned message signatures
|
|
97
|
+
|
|
98
|
+
Existing application message signatures work without the bridge. Alternatively,
|
|
99
|
+
minimal nominal declarations check RPC identities, and need no custom
|
|
100
|
+
`initialize` declaration:
|
|
101
|
+
|
|
102
|
+
```rbs
|
|
103
|
+
module Example
|
|
104
|
+
class Request
|
|
105
|
+
end
|
|
106
|
+
class Reply
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Declare every referenced message class, including imported/nested types, in
|
|
112
|
+
your application's `sig/`. A separate field extension remains application-owned:
|
|
113
|
+
|
|
114
|
+
```rbs
|
|
115
|
+
class Example::Request
|
|
116
|
+
attr_accessor text: String
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use these declarations instead of duplicate official message signatures. Nominal
|
|
121
|
+
identities alone do not check field or constructor arguments. The repository's
|
|
122
|
+
`typecheck/nominal/` checks this alternative with a separate field extension.
|
|
123
|
+
|
|
124
|
+
## Associations and typed construction
|
|
125
|
+
|
|
126
|
+
Generated method constants describe `Method[Request, Reply]`; generated client
|
|
127
|
+
methods accept Request and return `Response[Reply]`. Both Method and Response
|
|
128
|
+
are invariant. Handlers receive `(Request, Context)` and return the reply
|
|
129
|
+
message, rather than a Response envelope. Their argument signatures accept a
|
|
130
|
+
concrete proc or a signed callable object. The proc arm lets Steep infer inline
|
|
131
|
+
lambda request/context types. Returned handler-map values retain `call`;
|
|
132
|
+
heterogeneous maps do not encode a particular key's method association. The
|
|
133
|
+
core Server registration map erases those associations only after generated
|
|
134
|
+
`.handlers` has checked each callable.
|
|
135
|
+
|
|
136
|
+
Method's `request_type` and `response_type` are arbitrary binding tokens typed
|
|
137
|
+
as Object. A manual `Method.new` cannot infer instance types from those tokens.
|
|
138
|
+
Supply an explicit application assertion after verifying your binding contract:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
# @type var method: ConnectRPC::Method[Example::Request, Example::Reply]
|
|
142
|
+
method = ConnectRPC::Method.new(service: "example.API", name: "Call",
|
|
143
|
+
request_type: Example::Request,
|
|
144
|
+
response_type: Example::Reply)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This annotation asserts the association; it does not prove that a custom
|
|
148
|
+
binding honors it. Generated constants establish it from schema information.
|
|
149
|
+
|
|
150
|
+
Response, TransportRequest and TransportResponse remain mutable Ruby Structs.
|
|
151
|
+
Fully initialized `new` and class `[]` calls return precise records. Response's
|
|
152
|
+
message type is inferred, and Client still returns `Response[Reply]` with
|
|
153
|
+
non-null Metadata and trailers. Omitted or nil fields produce a partial-record
|
|
154
|
+
interface with nullable readers; a supplied Response message retains its own
|
|
155
|
+
type. Keyword arguments and positional keyword Hashes are both accepted.
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
complete = ConnectRPC::Response.new(message: reply,
|
|
159
|
+
metadata: ConnectRPC::Metadata.new, trailers: ConnectRPC::Metadata.new)
|
|
160
|
+
complete[:metadata].to_h
|
|
161
|
+
partial = ConnectRPC::Response[message: reply]
|
|
162
|
+
partial.metadata&.to_h
|
|
163
|
+
partial[:metadata] = nil
|
|
164
|
+
# complete[:metadata] = nil # Rejected: precise records retain their field types.
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Field readers, writers and literal Symbol/String/integer indexing preserve each
|
|
168
|
+
field's type, including negative indices. Common read-only Struct operations
|
|
169
|
+
(`to_h`, `members`, `size`, `length`, `to_a`, `values`, `each`, `each_pair`,
|
|
170
|
+
`values_at`, `deconstruct`, `deconstruct_keys`) are declared. Unrestricted
|
|
171
|
+
reflection, such as `send` or `instance_variable_set` that invalidates precise
|
|
172
|
+
fields, is an application escape boundary. Arbitrary computed member names,
|
|
173
|
+
recursive `dig`, block-form `to_h` and custom Struct subclass behavior are outside
|
|
174
|
+
this declared surface. These signatures do not change Ruby's runtime mutation.
|
|
175
|
+
|
|
176
|
+
## Unary GET options
|
|
177
|
+
|
|
178
|
+
`Method#idempotency` is the immutable `:unknown | :no_side_effects | :idempotent`
|
|
179
|
+
enum. Generated constants preserve standard protobuf method options. Core
|
|
180
|
+
Client accepts `use_get: bool` and `get_url_limit: Integer`; Server accepts
|
|
181
|
+
`get_query_limit: Integer?` and `call(query: String)`. Runtime constructors still
|
|
182
|
+
validate booleans and positive integer bounds. Rails `connect_limits` also
|
|
183
|
+
accepts `get_query_limit`. Generated wrappers keep their existing call options.
|
|
184
|
+
The strict implementation target includes the private GET parser and builder;
|
|
185
|
+
manual/generated positive callers and exact negative diagnostics cover these
|
|
186
|
+
options alongside installed package discovery.
|
|
187
|
+
|
|
188
|
+
## Package APIs and extension contracts
|
|
189
|
+
|
|
190
|
+
Use the installed package names in a Steepfile:
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
target :app do
|
|
194
|
+
library "connectrpc"
|
|
195
|
+
library "connectrpc-rack" # Only the integrations in your application bundle.
|
|
196
|
+
library "connectrpc-testing"
|
|
197
|
+
library "connectrpc-on-rails"
|
|
198
|
+
library "connectrpc-async"
|
|
199
|
+
library "connectrpc-falcon"
|
|
200
|
+
library "connectrpc-otel"
|
|
201
|
+
check "app"
|
|
202
|
+
configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
|
|
203
|
+
end
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Each optional manifest resolves only its dependency closure. Core declares no
|
|
207
|
+
Google runtime or optional hosting/tracing namespace and has no runtime tool
|
|
208
|
+
dependencies. Its GoogleProtobuf binding class signature is available without
|
|
209
|
+
the explicit message-runtime bridge; the binding itself still requires the
|
|
210
|
+
optional runtime require.
|
|
211
|
+
|
|
212
|
+
| Owner | Supported API and extension SPI |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| Core | Method, non-generic Service, Client/Server options and calls, records, Metadata, CancellationSource/Token/Registration, Deadline/Context, Error/ErrorDetail, explicit NetHTTP and Google binding entry points |
|
|
215
|
+
| Core shared, unary and observation SPI | `_Cancellation`, `_Binding`, `_Transport`, `_Input`, `_Handler`, `_Invoker`, callable clocks/error handlers, `_Subscriber`, four separate optional observer callback capabilities, host lifecycle Handle |
|
|
216
|
+
| Core streaming and gRPC/Web SPI | `_StreamingTransport`, `_StreamExchange`, streaming input/output, `_GRPCTransport`, `_GRPCStreamExchange`, `_GRPCStatusCodec`, native server publication/output interfaces including `_GRPCWebOutput`; see the protocol-specific sections below |
|
|
217
|
+
| Rack | Middleware constructor/call and shared `_App`, `_Body`, `_CallableBody`, `_Stream`, env and response contracts |
|
|
218
|
+
| Testing | In-process Transport constructor/call, reusable as the core transport |
|
|
219
|
+
| Rails | Controller inclusion and `connect`; documented private overrides for service, binding, handlers, limits, instrumentation and Web protocol/status/CORS; nullable request/context/method readers |
|
|
220
|
+
| Async | Application/native HTTP capabilities, Host, Transport, HTTP1Transport, ServerSession/accepted handles, TLSConfiguration, complete static/provider record shapes, status/error callbacks, rotation/drain/identity |
|
|
221
|
+
| Falcon | Endpoint's supported operations, Environment overrides and Server/native application/TLS lifecycle |
|
|
222
|
+
| OTel | Subscriber configuration and narrow tracer-provider/tracer/span/propagator capabilities; SDK and context implementation remain application owned |
|
|
223
|
+
|
|
224
|
+
`Async::Host#close`, `Async::ServerSession#close` and `Falcon::Server#close`
|
|
225
|
+
return `bool?`. Nil means a nonjoining owned request or coordinator reentry is
|
|
226
|
+
pending. External callers join actual cleanup and receive the final shared
|
|
227
|
+
boolean; once closed, all calls receive that boolean. Owned positive-grace
|
|
228
|
+
initiation preserves ordinary asynchronous drain and admitted sibling progress.
|
|
229
|
+
Repeated requests retain the first closer and expiry. Pending nil does not
|
|
230
|
+
decide an outcome or publish completion. The API callers narrow nil separately
|
|
231
|
+
from completed booleans, and the negative inventory rejects treating a pending
|
|
232
|
+
server close as an unconditional bool. Client transport close signatures remain
|
|
233
|
+
`bool`.
|
|
234
|
+
|
|
235
|
+
Constructors include their actual options and return types. Type checks reject
|
|
236
|
+
wrong field, callback and configuration types. Runtime checks still enforce
|
|
237
|
+
names, byte limits, finite numeric ranges, required TLS key presence, TLS/wire
|
|
238
|
+
validity, reactor affinity, admission and lifecycle ordering. RBS records with
|
|
239
|
+
nullable fields do not prove those keys were explicitly present. There is no
|
|
240
|
+
claim of fully type-safe RPC execution.
|
|
241
|
+
|
|
242
|
+
Custom hosts must pass the actual HTTP method to
|
|
243
|
+
`Server#start_call(path:, headers:, http_method: "POST")` before dispatch. Omitting
|
|
244
|
+
the keyword retains POST classification for existing direct callers. Core,
|
|
245
|
+
Rack and native hosts forward it. Server subclasses overriding `start_call`
|
|
246
|
+
must accept and forward `http_method:` (or compatible keyword arguments);
|
|
247
|
+
external overrides with narrower keyword signatures require an update.
|
|
248
|
+
The method fixes `Call.protocol` before subscribers start while preserving the
|
|
249
|
+
raw immutable header carrier. Native packages share core's private selection;
|
|
250
|
+
it is not an additional public protocol API.
|
|
251
|
+
|
|
252
|
+
Instrumentation subscribers return an opaque object or nil. They may implement
|
|
253
|
+
any subset of attach, detach, processing_finished and finished. The separate
|
|
254
|
+
`_ObserverAttach`, `_ObserverDetach`, `_ObserverProcessingFinished` and
|
|
255
|
+
`_ObserverFinished` interfaces let applications deliberately check a capability;
|
|
256
|
+
returning an arbitrary object from `start` does not automatically validate all
|
|
257
|
+
its optional callbacks. Core resolves methods once into private typed callback
|
|
258
|
+
records at one reflection boundary. Call, Outcome and Completion are shallowly
|
|
259
|
+
immutable Data values. In particular, the client Call's carrier remains mutable
|
|
260
|
+
for validated propagation injection. Handle exposes `activate`, `finish`,
|
|
261
|
+
`record_failure`, `host_rejected!` and `host_rejected?` for hosting. Construction,
|
|
262
|
+
processing bookkeeping and Instrumentation.start/safely/carrier are internal.
|
|
263
|
+
|
|
264
|
+
Optional class signatures describe ConnectRPC-owned supported operations. They
|
|
265
|
+
do not promise full upstream framework inheritance or describe all Rack/Rails,
|
|
266
|
+
Async/Falcon or OpenTelemetry APIs. No broad external namespace declarations are
|
|
267
|
+
shipped through normal discovery. Falcon checks fallback status, scalar/repeated
|
|
268
|
+
headers and enumerable/callable response bodies using small local structural
|
|
269
|
+
capabilities. These also accept `ConnectRPC::Rack::_App`; the Falcon closure does
|
|
270
|
+
not require the `connectrpc-rack` gem. Async owns shared native HTTP/TLS
|
|
271
|
+
capabilities reused by Falcon.
|
|
272
|
+
|
|
273
|
+
## Source inventory and implementation checks
|
|
274
|
+
|
|
275
|
+
The reviewed `typecheck/surface.json` records definitions, attributes, visibility,
|
|
276
|
+
constructor parameters/defaults and Struct/Data members across all maintained
|
|
277
|
+
library source. Each entry is explicitly supported, extension SPI or internal.
|
|
278
|
+
`rbs:inventory` checks the syntax tree against that inventory and requires shipped
|
|
279
|
+
declarations for supported members, including record readers/writers. A new
|
|
280
|
+
source method, changed option/visibility/member or omitted signature fails.
|
|
281
|
+
Review source and docs before updating an inventory entry; Ruby-public helpers
|
|
282
|
+
are not automatically compatibility promises. This is a practical source drift
|
|
283
|
+
check, not semantic proof of arbitrary Ruby metaprogramming.
|
|
284
|
+
|
|
285
|
+
Protocol, Compression, MessageIO, Method.validate_name!, private callback records,
|
|
286
|
+
core processing helpers, socket internals, framework glue internals and generator
|
|
287
|
+
implementation helpers stay outside the supported API. Generator invocation and
|
|
288
|
+
schema-generated service APIs retain their existing contract and parity checks.
|
|
289
|
+
|
|
290
|
+
`typecheck/Steepfile` checks actual core source and private state under
|
|
291
|
+
`Steep::Diagnostic::Ruby.strict`, including streaming and gRPC/Web.
|
|
292
|
+
[`typecheck/source.rb`](../typecheck/source.rb) defines the exact source set.
|
|
293
|
+
`rbs:source` validates the resolved source list and Ruby syntax before checking.
|
|
294
|
+
Its implementation-only declarations live outside every gem's `sig/` directory.
|
|
295
|
+
Erasure is limited to custom bindings/heterogeneous messages, external JSON and
|
|
296
|
+
optional observer discovery. The internal Numeric arithmetic declaration fills
|
|
297
|
+
a missing upstream base signature; custom numeric arithmetic remains a runtime
|
|
298
|
+
requirement. Narrow assertions record established phase, slice and format facts.
|
|
299
|
+
|
|
300
|
+
NetHTTP socket/watchdog implementation, Google codec internals, generator
|
|
301
|
+
internals and optional backend/framework implementation checking are later stages.
|
|
302
|
+
Their supported public signatures and consumer checks are included here.
|
|
303
|
+
|
|
304
|
+
Callable-body stream capabilities include the standard Rack read, write, `<<`,
|
|
305
|
+
flush, close, half-close and closed-state operations. Native HTTP header
|
|
306
|
+
capabilities return an Enumerator of name/value tuples. Struct `each_pair`
|
|
307
|
+
yields one name/value tuple, which a block may explicitly destructure.
|
|
308
|
+
|
|
309
|
+
Custom OpenTelemetry providers must supply the finite span-context capabilities
|
|
310
|
+
used by the default W3C propagator: valid state, raw trace/span ids, sampled
|
|
311
|
+
flags and serialized tracestate. These declarations introduce no SDK or upstream
|
|
312
|
+
namespace; static types do not prove valid id lengths or sampling policy.
|
|
313
|
+
|
|
314
|
+
### Opt-in framework compatibility
|
|
315
|
+
|
|
316
|
+
Rails inheritance and Falcon's configuration DSL need declarations for upstream
|
|
317
|
+
classes that currently ship no RBS. Each integration packages a finite bridge
|
|
318
|
+
outside its automatically loaded `sig/`:
|
|
319
|
+
|
|
320
|
+
| Package | Explicit signature directory | Tested upstream versions |
|
|
321
|
+
| --- | --- | --- |
|
|
322
|
+
| `connectrpc-on-rails` | `rbs/action_controller_8` | actionpack 8.0.5.1 and 8.1.4 |
|
|
323
|
+
| `connectrpc-falcon` | `rbs/async_service_0_25` | Falcon 0.57.0, async-service 0.25.0 |
|
|
324
|
+
|
|
325
|
+
Add only the selected bridge paths to an application's Steep target, using the
|
|
326
|
+
same gem-relative `Pathname` pattern as the Google bridge above. Omit these
|
|
327
|
+
bridges when the application already supplies declarations for those upstream
|
|
328
|
+
classes. Normal library discovery introduces neither `ActionController` nor
|
|
329
|
+
`Async::Service` declarations.
|
|
330
|
+
|
|
331
|
+
The Rails bridge covers nominal `ActionController::API` and `Base` inheritance
|
|
332
|
+
and `before_action` with named Symbol callbacks. It does not type the rest of
|
|
333
|
+
Rails or its callback option/block forms. The Falcon bridge covers
|
|
334
|
+
`Loader#service(name)` with a builder block, `include`, String `url`, Integer
|
|
335
|
+
`count`, block `prepare!`, and value/block forms of `connectrpc_server`,
|
|
336
|
+
`rack_app`, `tls`, `tls_provider` and `server_options`. Deferred option blocks
|
|
337
|
+
have the ConnectRPC Environment capabilities. No general `method_missing`
|
|
338
|
+
acceptance or complete upstream inheritance is declared. The repository checks
|
|
339
|
+
actual Rails subclasses and a real Falcon-loaded service configuration with
|
|
340
|
+
these declarations and runtime counterparts. The Falcon fixture accepts the real loader as a typed method argument, letting
|
|
341
|
+
Steep infer the builder block's self type without a file-level self override.
|
|
342
|
+
|
|
343
|
+
## Repository checks
|
|
344
|
+
|
|
345
|
+
```sh
|
|
346
|
+
mise run rbs:setup
|
|
347
|
+
mise run rbs:check
|
|
348
|
+
mise run rbs:source # Focused strict implementation leaf.
|
|
349
|
+
mise run rbs:api # Focused supported API callers.
|
|
350
|
+
mise run rbs:inventory # Source/signature drift.
|
|
351
|
+
mise run rbs:proof # Independent capture red/green probes.
|
|
352
|
+
mise run rbs:package
|
|
353
|
+
MISE_RUBY_VERSION=4.0.9 mise run rbs:check
|
|
354
|
+
MISE_RUBY_VERSION=4.0.9 mise run rbs:package
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
The independent checksummed `typecheck/Gemfile.lock` pins only development tools.
|
|
358
|
+
Bundles, Bundler state, compiler caches and local evidence live under
|
|
359
|
+
`vendor/rbs/`. The package check installs into a fresh GEM_HOME and exercises
|
|
360
|
+
normal installed signature/executable discovery outside the checkout. It clears
|
|
361
|
+
checkout Ruby and Bundler load paths. Both Ruby lanes run these feature gates in
|
|
362
|
+
CI. `rbs:check` includes strict source, inventory and all API consumers as well as
|
|
363
|
+
the generated positive/negative and nominal/bridge cases. The generated and
|
|
364
|
+
API negative inventories each use one fresh Steep invocation with a single
|
|
365
|
+
worker. Files remain separate, with independent inference contexts
|
|
366
|
+
and unchanged strict signature inputs. The harness verifies the fixture inventory,
|
|
367
|
+
normal exit 1, complete checker progress/summary and exactly one expected error
|
|
368
|
+
per known path. Missing, extra, duplicate, malformed and wrong-severity records
|
|
369
|
+
fail. Parsing uses the pinned formatter's raw record boundaries; escaped message
|
|
370
|
+
newlines cannot introduce diagnostics. Controlled fixture paths cannot contain
|
|
371
|
+
ambiguous annotation properties. Positives, strict implementation, RBS validation
|
|
372
|
+
and Falcon-only checks remain separate.
|
|
373
|
+
`rbs:package` uses the existing frozen optional bundle setups for offline runtime
|
|
374
|
+
archives, builds every owned signature package and checks each library through
|
|
375
|
+
normal installed discovery. It checks composed environments in both load orders,
|
|
376
|
+
real Rails subclass inclusion, Rack/Testing calls, native session/TLS operations,
|
|
377
|
+
Falcon endpoint integration and API-only OTel without loading an SDK. The original
|
|
378
|
+
package guards and generated installed callers remain. Complete negative batch
|
|
379
|
+
logs are retained under `vendor/rbs/`, including nested installed API logs on
|
|
380
|
+
failure. Core, optional and tool bundles stay independent; gem dependencies and
|
|
381
|
+
pins remain unchanged. CI caches dependency installations, always reruns frozen
|
|
382
|
+
setup and every check, and never caches the fresh external consumer. See
|
|
383
|
+
[CI cache ownership and invalidation](ci.md#optional-rbs-lanes).
|
|
384
|
+
|
|
385
|
+
`rbs:proof` captures independent source inodes without Git metadata, proves wrong
|
|
386
|
+
return/data/callback diagnostics and source-addition/signature-omission drift,
|
|
387
|
+
restores every captured byte, and reruns green. It never mutates delivery source.
|
|
388
|
+
The captured executable alone uses 0755 for existing archive guards; source modes
|
|
389
|
+
remain unchanged. Logs and capture bindings live under ignored `vendor/rbs/`.
|
|
390
|
+
|
|
391
|
+
## Cancellation types
|
|
392
|
+
|
|
393
|
+
Client and generated unary methods accept `cancellation: CancellationToken?`.
|
|
394
|
+
Pass `CancellationSource.new.token`; the source itself is rejected. Tokens expose
|
|
395
|
+
only observation and listener registration. `CancellationRegistration#unregister`
|
|
396
|
+
returns bool. Token reasons are `:canceled | nil`; Context's combined
|
|
397
|
+
`cancellation_reason` also admits `:deadline_exceeded`.
|
|
398
|
+
|
|
399
|
+
`TransportRequest` appends `cancellation: _Cancellation?` after `lifecycle`;
|
|
400
|
+
negative indices shift accordingly (`-1` is cancellation, `-2` is lifecycle).
|
|
401
|
+
Complete and partial Structs retain their precise field contracts and aggregate
|
|
402
|
+
unions. `_Cancellation` is the read-only transport/host extension SPI, with
|
|
403
|
+
`cancelled?`, `reason`, `check!` and `on_cancel`. Server/Context accept that SPI
|
|
404
|
+
and own separate processing arbitration. Deadline remains an actual Deadline or
|
|
405
|
+
nil. Runtime cancellation, reactor and blocking-I/O limits still apply.
|
|
406
|
+
|
|
407
|
+
## Streaming types
|
|
408
|
+
|
|
409
|
+
The invariant streaming declarations are siblings of unary Method. Generated
|
|
410
|
+
mixed-service handlers carry concrete request/reply and StreamingContext types;
|
|
411
|
+
readers, writers and duplex endpoints preserve those associations. Block-only
|
|
412
|
+
`each` and required operation blocks are checked. StreamRequest/StreamHead fields,
|
|
413
|
+
partial Structs and literal indices use the same precise record policy as unary.
|
|
414
|
+
The records are named `StreamRequest` and `StreamHead` in Ruby/RBS.
|
|
415
|
+
|
|
416
|
+
The typed `_StreamingTransport` explicitly declares finite cardinalities and
|
|
417
|
+
provides a writable exchange before waiting for headers. `_StreamExchange`
|
|
418
|
+
includes bounded response-head/read/finish waits. Existing unary `_Transport`
|
|
419
|
+
consumers need no new method. New core streaming files participate in the strict
|
|
420
|
+
implementation target, with private declarations outside gem archives. Installed
|
|
421
|
+
checks generate real mixed services and run native Async/Falcon streaming over
|
|
422
|
+
localhost with all seven normally installed packages, both composition orders,
|
|
423
|
+
codecs and codings. These remain separate from independent Go/official evidence.
|
|
424
|
+
Custom server hosts may pass `capabilities: Array[:server_stream | :client_stream |
|
|
425
|
+
:bidi_stream]?` to `Server#call_stream`. Nil preserves the legacy `http2:` behavior;
|
|
426
|
+
a non-nil list must be nonempty, unique and cannot accompany `http2: true`.
|
|
427
|
+
Runtime validation enforces those array constraints. Strict source and installed
|
|
428
|
+
positive/negative consumers cover the capability SPI. Private native routing
|
|
429
|
+
and retirement helpers are internal implementation, not supported host APIs.
|
|
430
|
+
See the [streaming guide](streaming.md) for state, ownership and timing policies.
|
|
431
|
+
|
|
432
|
+
## Native gRPC types
|
|
433
|
+
|
|
434
|
+
Client accepts `protocol: :connect | :grpc`; Server additionally accepts `:auto`.
|
|
435
|
+
`GRPCHead` is deeply immutable and separate from the existing Struct records.
|
|
436
|
+
The independent `_GRPCTransport` advertises all four finite RPC shapes and yields
|
|
437
|
+
`_GRPCStreamExchange`; it needs no unary `call`. Existing `_Transport`,
|
|
438
|
+
`_StreamingTransport`, `_StreamExchange` and `_Binding` requirements are unchanged.
|
|
439
|
+
|
|
440
|
+
A separate `_GRPCStatusCodec` supports composed custom binding tokens. Its
|
|
441
|
+
`decode_status(String, code: Integer)` compares the raw numeric code before
|
|
442
|
+
normalizing unknown codes. Native `Server#call_grpc` requires explicit HTTP/2,
|
|
443
|
+
`_GRPCOutput.finish(headers:)` and a `_PublishGRPCHead` callback. See the
|
|
444
|
+
[gRPC guide](grpc.md) for publication, EOF and transport completion semantics.
|
|
445
|
+
|
|
446
|
+
## gRPC-Web server types
|
|
447
|
+
|
|
448
|
+
Server protocol selection accepts `:grpc_web` and explicit distinct protocol
|
|
449
|
+
arrays; `:auto` remains Connect plus native gRPC. Client protocol types remain
|
|
450
|
+
`:connect | :grpc`. `_GRPCWebOutput` separates prepared writes from staged
|
|
451
|
+
`finish(terminal:)`; `call_grpc_web` grants only unary by default.
|
|
452
|
+
`GRPCWebCORS` is an immutable public configuration value, and `cors_response` is
|
|
453
|
+
the pure host evaluation/decorating SPI. Rails declares its three private Web
|
|
454
|
+
hooks and two status limits. Call.protocol includes `:grpc_web` before observer
|
|
455
|
+
start. All new core files enter the strict source set and internal signatures;
|
|
456
|
+
API callers include exact client-mode, output, capability and CORS negatives.
|
|
457
|
+
The installed consumer runs manual encoded Testing requests and real mixed
|
|
458
|
+
Web/Connect H2 calls in both package load orders, without loading an OTel SDK.
|
|
459
|
+
|
|
460
|
+
## HTTP/1 client types
|
|
461
|
+
|
|
462
|
+
The Async package owns the independent `HTTP1Transport` constructor, unary
|
|
463
|
+
transport and existing SS/CS exchange signatures. Its finite capabilities omit
|
|
464
|
+
bidi and its public surface has no gRPC entry point. Strict callers cover valid
|
|
465
|
+
constructor/exchange use and reject invalid option types, missing blocks and
|
|
466
|
+
gRPC methods. The source inventory classifies lease, parser and exchange
|
|
467
|
+
implementation helpers as internal. Installed generated callers use the normal
|
|
468
|
+
Async package with Falcon H1 for safe GET and SS/CS in both codecs/codings,
|
|
469
|
+
without adding another package or changing the existing streaming SPI.
|