tigrbl-runtime 0.4.2.dev3__tar.gz → 0.4.3.dev4__tar.gz

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.
Files changed (108) hide show
  1. tigrbl_runtime-0.4.3.dev4/NOTICE +7 -0
  2. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/PKG-INFO +121 -28
  3. tigrbl_runtime-0.4.3.dev4/README.md +166 -0
  4. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/pyproject.toml +1 -1
  5. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/__init__.py +25 -0
  6. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/webhooks.py → tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/callbacks.py +12 -12
  7. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_completion.py +33 -0
  8. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_context.py +96 -0
  9. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_jsonrpc.py +38 -0
  10. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_receive.py +63 -0
  11. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_scope.py +75 -0
  12. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_send.py +242 -0
  13. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/_asgi_webtransport.py +335 -0
  14. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/channel/asgi.py +77 -0
  15. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/__init__.py +2 -0
  16. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/_invoke_support.py +193 -0
  17. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/ctx/__init__.py +15 -0
  18. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/ctx/context.py +392 -0
  19. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/ctx/hot.py +35 -0
  20. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/ctx/hot_namespaces.py +421 -0
  21. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/ctx/hot_state.py +226 -0
  22. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/invoke.py +70 -174
  23. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/kernel_executor.py +1 -1
  24. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/packed.py +154 -603
  25. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/executors/types.py +39 -0
  26. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/handle.py +19 -0
  27. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/__init__.py +0 -7
  28. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/runtime/exceptions.py +8 -0
  29. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/runtime/runtime.py +155 -0
  30. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/system.py +2 -2
  31. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/rust/__init__.py +5 -12
  32. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/_fallback.py +73 -0
  33. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/rust/_load_rust.py +3 -9
  34. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/rust/backend.py +25 -1
  35. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/callbacks.py +43 -0
  36. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/codec.py +27 -0
  37. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/compile.py +15 -0
  38. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/errors.py +27 -0
  39. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/rust/request.py +8 -0
  40. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/rust/response.py +8 -0
  41. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/runtime.py +62 -0
  42. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/rust/trace.py +29 -0
  43. tigrbl_runtime-0.4.3.dev4/tigrbl_runtime/semantics.py +319 -0
  44. tigrbl_runtime-0.4.2.dev3/README.md +0 -74
  45. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/__init__.py +0 -52
  46. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/callbacks.py +0 -15
  47. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/channel/asgi.py +0 -865
  48. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/channel/state.py +0 -11
  49. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/executors/helpers.py +0 -3
  50. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/executors/loop_regions.py +0 -46
  51. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/executors/types.py +0 -975
  52. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/handle.py +0 -11
  53. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/__init__.py +0 -19
  54. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/_iterators.py +0 -3
  55. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/anchors.py +0 -38
  56. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/app_frame_codec.py +0 -111
  57. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/completion_fence.py +0 -41
  58. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/dispatch_atoms.py +0 -46
  59. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/framing_atoms.py +0 -50
  60. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/http_stream.py +0 -3
  61. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/http_unary.py +0 -8
  62. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/lifespan_chain.py +0 -3
  63. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/loop_modes.py +0 -24
  64. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/scope_schemas.py +0 -63
  65. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/sse.py +0 -3
  66. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/static_files.py +0 -3
  67. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/subevent_handlers.py +0 -3
  68. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/transport_atoms.py +0 -3
  69. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/websocket.py +0 -3
  70. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/webtransport.py +0 -9
  71. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/protocol/webtransport_session.py +0 -129
  72. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/events.py +0 -97
  73. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/exceptions.py +0 -18
  74. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/executor/__init__.py +0 -6
  75. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/executor/invoke.py +0 -72
  76. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/kernel.py +0 -35
  77. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/labels.py +0 -3
  78. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/runtime.py +0 -229
  79. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/status/__init__.py +0 -1
  80. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/status/converters.py +0 -1
  81. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/status/exceptions.py +0 -1
  82. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/status/mappings.py +0 -1
  83. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/runtime/status/utils.py +0 -1
  84. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/_fallback.py +0 -320
  85. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/_parity_contract.py +0 -161
  86. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/callbacks.py +0 -60
  87. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/codec.py +0 -14
  88. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/compile.py +0 -35
  89. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/errors.py +0 -2
  90. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/parity.py +0 -72
  91. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/runtime.py +0 -127
  92. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/rust/trace.py +0 -64
  93. tigrbl_runtime-0.4.2.dev3/tigrbl_runtime/transactions.py +0 -3
  94. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/LICENSE +0 -0
  95. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/channel/__init__.py +0 -0
  96. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/channel/capabilities.py +0 -0
  97. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/channel/websocket.py +0 -0
  98. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/config/__init__.py +0 -0
  99. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/config/constants.py +0 -0
  100. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/base.py +0 -0
  101. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/numba_packed.py +0 -0
  102. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/executors/phase.py +0 -0
  103. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/_typing_aliases.py +0 -0
  104. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/base.py +0 -0
  105. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/channel.py +0 -0
  106. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/hook_types.py +0 -0
  107. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/runtime/response.py +0 -0
  108. {tigrbl_runtime-0.4.2.dev3 → tigrbl_runtime-0.4.3.dev4}/tigrbl_runtime/rust/availability.py +0 -0
@@ -0,0 +1,7 @@
1
+ Tigrbl
2
+ Copyright 2026 Swarmauri
3
+
4
+ This product includes software developed by Swarmauri.
5
+
6
+ Tigrbl is licensed under the Apache License, Version 2.0.
7
+ See the LICENSE file distributed with this work for the full license text.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrbl-runtime
3
- Version: 0.4.2.dev3
3
+ Version: 0.4.3.dev4
4
4
  Summary: Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -204,6 +204,7 @@ License: Apache License
204
204
  See the License for the specific language governing permissions and
205
205
  limitations under the License.
206
206
  License-File: LICENSE
207
+ License-File: NOTICE
207
208
  Keywords: tigrbl,asgi,api,json-rpc,rest,sqlalchemy,pydantic,runtime,pipeline,bridge,openapi,openrpc,schema-first
208
209
  Author: Jacob Stewart
209
210
  Author-email: jacob@swarmauri.com
@@ -243,12 +244,45 @@ Description-Content-Type: text/markdown
243
244
  <p><strong>Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch.</strong></p>
244
245
  <a href="https://pypi.org/project/tigrbl-runtime/"><img src="https://img.shields.io/pypi/v/tigrbl-runtime?label=PyPI" alt="PyPI version for tigrbl-runtime"/></a>
245
246
  <a href="https://pypi.org/project/tigrbl-runtime/"><img src="https://static.pepy.tech/badge/tigrbl-runtime" alt="Downloads for tigrbl-runtime"/></a>
247
+ <a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-runtime"/></a>
246
248
  <a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_runtime/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_runtime/README.md.svg?label=hits" alt="Repository hits for tigrbl-runtime README"/></a>
247
249
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
248
- <a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%20to%203.15-3776ab" alt="Python requirement for tigrbl-runtime"/></a>
250
+ <a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-runtime"/></a>
249
251
  <a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-runtime"/></a>
250
252
  </div>
251
253
 
254
+ ## What is tigrbl-runtime?
255
+
256
+ Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch.
257
+
258
+ ## Why use tigrbl-runtime?
259
+
260
+ Use it when you need this foundational Tigrbl layer directly as a small, focused dependency.
261
+
262
+ ## When should I install tigrbl-runtime?
263
+
264
+ Install it for extension packages, package-local tests, or internals that need this boundary without the whole facade.
265
+
266
+ ## Who is tigrbl-runtime for?
267
+
268
+ Framework maintainers, extension authors, and advanced users composing Tigrbl from split packages.
269
+
270
+ ## Where does tigrbl-runtime fit?
271
+
272
+ `tigrbl-runtime` lives at `pkgs/core/tigrbl_runtime` and serves a focused layer in the split Tigrbl framework.
273
+
274
+ ## How does tigrbl-runtime work?
275
+
276
+ It owns a narrow layer in the split workspace and is consumed by higher-level packages through explicit dependencies.
277
+
278
+ ## Certification Status
279
+
280
+ - Package status: governed package in the `tigrbl/tigrbl` workspace.
281
+ - Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
282
+ - Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
283
+ - Local certification guard: `pkgs/core/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
284
+ - Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
285
+
252
286
  ## Install
253
287
 
254
288
  ```bash
@@ -259,56 +293,115 @@ uv add tigrbl-runtime
259
293
  pip install tigrbl-runtime
260
294
  ```
261
295
 
296
+ ## Surface Coverage
297
+
298
+ | Surface | Value |
299
+ |---|---|
300
+ | PyPI package | [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/) |
301
+ | Repository path | [`pkgs/core/tigrbl_runtime`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_runtime) |
302
+ | Python import root | `tigrbl_runtime` |
303
+ | Console scripts | none declared |
304
+ | Entry points | none declared |
305
+ | Optional extras | none declared |
306
+ | Legal files | `LICENSE`, `NOTICE` |
307
+ | Supported Python | `3.10 | 3.11 | 3.12 | 3.13 | 3.14` |
308
+
262
309
  ## What It Owns
263
310
 
264
- `tigrbl-runtime` owns the runtime boundary inside the split Python workspace.
265
- Rust crates and optional Python extension bindings have moved to the private `tigrbl/tigrbl_rs` repository.
311
+ `tigrbl-runtime` owns the `foundational framework package` boundary. It should be installed when you need this package's focused responsibility without assuming every other Tigrbl workspace package is present.
266
312
 
267
- ## Use It When
313
+ Implementation orientation:
314
+ - `tigrbl_runtime`: callbacks, channel/, config/, executors/, handle, protocol/, runtime/, transactions, webhooks
315
+ - `tigrbl_runtime/rust/`: deprecated compatibility shims only; Rust execution is unavailable.
268
316
 
269
- Use `tigrbl-runtime` when you want this subsystem directly as a package boundary instead of consuming it only through the top-level `tigrbl` facade.
317
+ Runtime authoring BCP:
318
+ - Do use this package for runtime-owned routing, request execution, transport-unit execution, framing atoms, transport channels, transaction helpers, and kernel integration.
319
+ - Do keep handler invocation, transaction progression, error handling, and transport emission aligned with compiled plans.
320
+ - Do not make application route handlers, FastAPI/Starlette objects, direct SQLAlchemy session calls, or ad-hoc engine construction the runtime contract.
321
+ - Do not bypass kernel plans or lifecycle phases when adding REST, JSON-RPC, stream, SSE, WebSocket, or WebTransport behavior.
322
+ - Avoid hiding behavior in transport wrappers that diagnostics and compiled plans cannot inspect.
270
323
 
271
- ## Public Surface
324
+ ## Public API and Import Surface
272
325
 
273
- - Package-local implementation lives under `pkgs/core/tigrbl_runtime` and is consumed as a distribution boundary rather than a single broad root re-export.
326
+ - Import roots: `tigrbl_runtime`.
327
+ - Public symbols: `Runtime`, `RuntimeBase`.
328
+ - Rust-named symbols live only under `tigrbl_runtime.rust` as deprecated compatibility shims and must not be used for execution.
329
+ - Workspace dependencies: [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/), [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/), [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/), [`tigrbl-base`](https://pypi.org/project/tigrbl-base/), [`tigrbl-core`](https://pypi.org/project/tigrbl-core/).
330
+ - External runtime dependencies: `numba>=0.61.2`.
274
331
 
275
- ## Internal Layout
332
+ ## Usage Examples
276
333
 
277
- - Workspace path: `pkgs/core/tigrbl_runtime`.
278
- - Package class: `core framework package`.
279
- - Python requirement: `>=3.10,<3.15`.
334
+ ### Verify the installed package
280
335
 
281
- ## Dependency Surface
336
+ ```bash
337
+ python -m pip show tigrbl-runtime
338
+ python - <<'PY'
339
+ from importlib.metadata import version
340
+ print(version("tigrbl-runtime"))
341
+ PY
342
+ ```
282
343
 
283
- - Workspace package dependencies: [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/), [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/), [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/), [`tigrbl-base`](https://pypi.org/project/tigrbl-base/), [`tigrbl-core`](https://pypi.org/project/tigrbl-core/).
284
- - External runtime dependencies: `numba>=0.61.2`.
285
- - Optional extras: none in this Python workspace.
344
+ ### Import the package boundary
345
+
346
+ ```python
347
+ import importlib
348
+
349
+ module = importlib.import_module("tigrbl_runtime")
350
+ print(module.__name__)
351
+ ```
352
+
353
+ ### Import a public symbol
354
+
355
+ ```python
356
+ from tigrbl_runtime import Runtime
357
+
358
+ print(Runtime)
359
+ ```
360
+
361
+ ### Use with the facade when building applications
362
+
363
+ ```bash
364
+ uv add tigrbl tigrbl-runtime
365
+ python - <<'PY'
366
+ import tigrbl
367
+ print(tigrbl.__name__)
368
+ PY
369
+ ```
370
+
371
+ ## How To Choose This Package
372
+
373
+ Choose `tigrbl-runtime` when the quick-answer table matches your use case. Choose [`tigrbl`](https://pypi.org/project/tigrbl/) instead when you want the full public facade. Choose a lower-level package such as [`tigrbl-core`](https://pypi.org/project/tigrbl-core/), [`tigrbl-base`](https://pypi.org/project/tigrbl-base/), or [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/) when you are building framework extensions or testing a specific internal boundary.
286
374
 
287
375
  ## Related Packages
288
376
 
289
- - [`tigrbl`](https://pypi.org/project/tigrbl/)
290
377
  - [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/)
291
378
  - [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/)
292
379
  - [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/)
293
380
  - [`tigrbl-base`](https://pypi.org/project/tigrbl-base/)
294
381
  - [`tigrbl-core`](https://pypi.org/project/tigrbl-core/)
382
+ - [`tigrbl`](https://pypi.org/project/tigrbl/)
383
+
384
+ ## Documentation Links
385
+
386
+ - [Workspace docs](https://github.com/tigrbl/tigrbl/blob/master/docs/README.md)
387
+ - [Package catalog](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_CATALOG.md)
388
+ - [Package layout](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_LAYOUT.md)
389
+ - [Current target](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_TARGET.md)
390
+ - [Current state](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_STATE.md)
391
+ - [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json)
392
+ - [Release workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml)
295
393
 
296
- ## Canonical Repository Docs
394
+ ## Support
297
395
 
298
- - `docs/README.md`
299
- - `docs/conformance/CURRENT_TARGET.md`
300
- - `docs/conformance/CURRENT_STATE.md`
301
- - `docs/conformance/NEXT_STEPS.md`
302
- - `docs/governance/DOC_POINTERS.md`
303
- - `docs/developer/PACKAGE_CATALOG.md`
304
- - `docs/developer/PACKAGE_LAYOUT.md`
396
+ - Community: [Discord](https://discord.gg/K4YTAPapjR).
397
+ - Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
398
+ - Repository: [pkgs/core/tigrbl_runtime](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_runtime).
305
399
 
306
400
  ## Package-local Boundary
307
401
 
308
- This file is a package-local distribution entry point.
309
- Use this page for package installation and boundary orientation. Repository governance, conformance state, target status, and release evidence remain governed from `docs/` and `.ssot/`.
402
+ This README is the package-local distribution entry point for `tigrbl-runtime`. It answers install, usage, API, ownership, and certification-orientation questions for this package. Broader architectural decisions, release status, and cross-package proof chains remain in the repository-level docs and SSOT registry.
310
403
 
311
404
  ## License
312
405
 
313
- Licensed under the Apache License, Version 2.0. See `LICENSE` and the official [Apache 2.0 license text](https://www.apache.org/licenses/LICENSE-2.0).
406
+ Licensed under the Apache License, Version 2.0. See `LICENSE`, `NOTICE`, and the official [Apache 2.0 license text](https://www.apache.org/licenses/LICENSE-2.0).
314
407
 
@@ -0,0 +1,166 @@
1
+ <div align="center">
2
+ <h1>tigrbl-runtime</h1>
3
+ <img src="https://raw.githubusercontent.com/swarmauri/swarmauri-sdk/master/assets/tigrbl_full_logo.png" alt="Tigrbl logo" width="140"/>
4
+ <p><strong>Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch.</strong></p>
5
+ <a href="https://pypi.org/project/tigrbl-runtime/"><img src="https://img.shields.io/pypi/v/tigrbl-runtime?label=PyPI" alt="PyPI version for tigrbl-runtime"/></a>
6
+ <a href="https://pypi.org/project/tigrbl-runtime/"><img src="https://static.pepy.tech/badge/tigrbl-runtime" alt="Downloads for tigrbl-runtime"/></a>
7
+ <a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-runtime"/></a>
8
+ <a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_runtime/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_runtime/README.md.svg?label=hits" alt="Repository hits for tigrbl-runtime README"/></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
10
+ <a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-runtime"/></a>
11
+ <a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-runtime"/></a>
12
+ </div>
13
+
14
+ ## What is tigrbl-runtime?
15
+
16
+ Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch.
17
+
18
+ ## Why use tigrbl-runtime?
19
+
20
+ Use it when you need this foundational Tigrbl layer directly as a small, focused dependency.
21
+
22
+ ## When should I install tigrbl-runtime?
23
+
24
+ Install it for extension packages, package-local tests, or internals that need this boundary without the whole facade.
25
+
26
+ ## Who is tigrbl-runtime for?
27
+
28
+ Framework maintainers, extension authors, and advanced users composing Tigrbl from split packages.
29
+
30
+ ## Where does tigrbl-runtime fit?
31
+
32
+ `tigrbl-runtime` lives at `pkgs/core/tigrbl_runtime` and serves a focused layer in the split Tigrbl framework.
33
+
34
+ ## How does tigrbl-runtime work?
35
+
36
+ It owns a narrow layer in the split workspace and is consumed by higher-level packages through explicit dependencies.
37
+
38
+ ## Certification Status
39
+
40
+ - Package status: governed package in the `tigrbl/tigrbl` workspace.
41
+ - Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
42
+ - Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
43
+ - Local certification guard: `pkgs/core/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
44
+ - Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ uv add tigrbl-runtime
50
+ ```
51
+
52
+ ```bash
53
+ pip install tigrbl-runtime
54
+ ```
55
+
56
+ ## Surface Coverage
57
+
58
+ | Surface | Value |
59
+ |---|---|
60
+ | PyPI package | [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/) |
61
+ | Repository path | [`pkgs/core/tigrbl_runtime`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_runtime) |
62
+ | Python import root | `tigrbl_runtime` |
63
+ | Console scripts | none declared |
64
+ | Entry points | none declared |
65
+ | Optional extras | none declared |
66
+ | Legal files | `LICENSE`, `NOTICE` |
67
+ | Supported Python | `3.10 | 3.11 | 3.12 | 3.13 | 3.14` |
68
+
69
+ ## What It Owns
70
+
71
+ `tigrbl-runtime` owns the `foundational framework package` boundary. It should be installed when you need this package's focused responsibility without assuming every other Tigrbl workspace package is present.
72
+
73
+ Implementation orientation:
74
+ - `tigrbl_runtime`: callbacks, channel/, config/, executors/, handle, protocol/, runtime/, transactions, webhooks
75
+ - `tigrbl_runtime/rust/`: deprecated compatibility shims only; Rust execution is unavailable.
76
+
77
+ Runtime authoring BCP:
78
+ - Do use this package for runtime-owned routing, request execution, transport-unit execution, framing atoms, transport channels, transaction helpers, and kernel integration.
79
+ - Do keep handler invocation, transaction progression, error handling, and transport emission aligned with compiled plans.
80
+ - Do not make application route handlers, FastAPI/Starlette objects, direct SQLAlchemy session calls, or ad-hoc engine construction the runtime contract.
81
+ - Do not bypass kernel plans or lifecycle phases when adding REST, JSON-RPC, stream, SSE, WebSocket, or WebTransport behavior.
82
+ - Avoid hiding behavior in transport wrappers that diagnostics and compiled plans cannot inspect.
83
+
84
+ ## Public API and Import Surface
85
+
86
+ - Import roots: `tigrbl_runtime`.
87
+ - Public symbols: `Runtime`, `RuntimeBase`.
88
+ - Rust-named symbols live only under `tigrbl_runtime.rust` as deprecated compatibility shims and must not be used for execution.
89
+ - Workspace dependencies: [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/), [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/), [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/), [`tigrbl-base`](https://pypi.org/project/tigrbl-base/), [`tigrbl-core`](https://pypi.org/project/tigrbl-core/).
90
+ - External runtime dependencies: `numba>=0.61.2`.
91
+
92
+ ## Usage Examples
93
+
94
+ ### Verify the installed package
95
+
96
+ ```bash
97
+ python -m pip show tigrbl-runtime
98
+ python - <<'PY'
99
+ from importlib.metadata import version
100
+ print(version("tigrbl-runtime"))
101
+ PY
102
+ ```
103
+
104
+ ### Import the package boundary
105
+
106
+ ```python
107
+ import importlib
108
+
109
+ module = importlib.import_module("tigrbl_runtime")
110
+ print(module.__name__)
111
+ ```
112
+
113
+ ### Import a public symbol
114
+
115
+ ```python
116
+ from tigrbl_runtime import Runtime
117
+
118
+ print(Runtime)
119
+ ```
120
+
121
+ ### Use with the facade when building applications
122
+
123
+ ```bash
124
+ uv add tigrbl tigrbl-runtime
125
+ python - <<'PY'
126
+ import tigrbl
127
+ print(tigrbl.__name__)
128
+ PY
129
+ ```
130
+
131
+ ## How To Choose This Package
132
+
133
+ Choose `tigrbl-runtime` when the quick-answer table matches your use case. Choose [`tigrbl`](https://pypi.org/project/tigrbl/) instead when you want the full public facade. Choose a lower-level package such as [`tigrbl-core`](https://pypi.org/project/tigrbl-core/), [`tigrbl-base`](https://pypi.org/project/tigrbl-base/), or [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/) when you are building framework extensions or testing a specific internal boundary.
134
+
135
+ ## Related Packages
136
+
137
+ - [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/)
138
+ - [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/)
139
+ - [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/)
140
+ - [`tigrbl-base`](https://pypi.org/project/tigrbl-base/)
141
+ - [`tigrbl-core`](https://pypi.org/project/tigrbl-core/)
142
+ - [`tigrbl`](https://pypi.org/project/tigrbl/)
143
+
144
+ ## Documentation Links
145
+
146
+ - [Workspace docs](https://github.com/tigrbl/tigrbl/blob/master/docs/README.md)
147
+ - [Package catalog](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_CATALOG.md)
148
+ - [Package layout](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_LAYOUT.md)
149
+ - [Current target](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_TARGET.md)
150
+ - [Current state](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_STATE.md)
151
+ - [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json)
152
+ - [Release workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml)
153
+
154
+ ## Support
155
+
156
+ - Community: [Discord](https://discord.gg/K4YTAPapjR).
157
+ - Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
158
+ - Repository: [pkgs/core/tigrbl_runtime](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_runtime).
159
+
160
+ ## Package-local Boundary
161
+
162
+ This README is the package-local distribution entry point for `tigrbl-runtime`. It answers install, usage, API, ownership, and certification-orientation questions for this package. Broader architectural decisions, release status, and cross-package proof chains remain in the repository-level docs and SSOT registry.
163
+
164
+ ## License
165
+
166
+ Licensed under the Apache License, Version 2.0. See `LICENSE`, `NOTICE`, and the official [Apache 2.0 license text](https://www.apache.org/licenses/LICENSE-2.0).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tigrbl-runtime"
3
- version = "0.4.2.dev3"
3
+ version = "0.4.3.dev4"
4
4
  description = "Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -0,0 +1,25 @@
1
+ """Public exports for ``tigrbl_runtime`` with lazy loading."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import import_module
6
+ from typing import Any
7
+
8
+ _LAZY_EXPORTS = {
9
+ "Runtime": "runtime",
10
+ "RuntimeBase": "runtime",
11
+ }
12
+
13
+ __all__ = [
14
+ *_LAZY_EXPORTS,
15
+ ]
16
+
17
+
18
+ def __getattr__(name: str) -> Any:
19
+ module_name = _LAZY_EXPORTS.get(name)
20
+ if module_name is None:
21
+ raise AttributeError(name)
22
+ module = import_module(f"{__name__}.{module_name}")
23
+ value = getattr(module, name)
24
+ globals()[name] = value
25
+ return value
@@ -7,7 +7,7 @@ from collections.abc import Callable, Mapping
7
7
  from typing import Any
8
8
 
9
9
 
10
- def compile_webhook_delivery_plan(
10
+ def compile_callback_delivery_plan(
11
11
  *,
12
12
  event: str,
13
13
  endpoint: str,
@@ -19,11 +19,11 @@ def compile_webhook_delivery_plan(
19
19
  "endpoint": endpoint,
20
20
  "signing": {"algorithm": "hmac-sha256", "secret_ref": signing_secret_ref},
21
21
  "retry": dict(retry or {"max_attempts": 1}),
22
- "completion_subevent": "webhook.delivery.emit_complete",
22
+ "completion_subevent": "callback.delivery.emit_complete",
23
23
  }
24
24
 
25
25
 
26
- def build_webhook_payload(
26
+ def build_callback_payload(
27
27
  *, event: str, data: Mapping[str, Any], idempotency_key: str
28
28
  ) -> dict[str, object]:
29
29
  return {
@@ -33,13 +33,13 @@ def build_webhook_payload(
33
33
  }
34
34
 
35
35
 
36
- def sign_webhook_payload(payload: Mapping[str, Any], *, secret: str) -> dict[str, object]:
36
+ def sign_callback_payload(payload: Mapping[str, Any], *, secret: str) -> dict[str, object]:
37
37
  canonical = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
38
38
  digest = hmac.new(secret.encode("utf-8"), canonical, hashlib.sha256).hexdigest()
39
39
  return {"payload": dict(payload), "signature": f"sha256={digest}"}
40
40
 
41
41
 
42
- def deliver_webhook(
42
+ def deliver_callback(
43
43
  payload: Mapping[str, Any],
44
44
  *,
45
45
  send: Callable[[Mapping[str, Any]], Mapping[str, Any]],
@@ -54,7 +54,7 @@ def deliver_webhook(
54
54
  for attempt in range(1, max_attempts + 1):
55
55
  attempts = attempt
56
56
  if trace and attempt == 1:
57
- trace("webhook.delivery.emit")
57
+ trace("callback.delivery.emit")
58
58
  try:
59
59
  response = send(payload)
60
60
  except Exception as exc:
@@ -65,7 +65,7 @@ def deliver_webhook(
65
65
  "attempts": attempts,
66
66
  "completed": False,
67
67
  "error_ctx": {
68
- "subevent": "webhook.delivery.emit",
68
+ "subevent": "callback.delivery.emit",
69
69
  "message": str(exc),
70
70
  },
71
71
  }
@@ -73,7 +73,7 @@ def deliver_webhook(
73
73
  status_code = int(response.get("status_code", 0))
74
74
  if 200 <= status_code < 300:
75
75
  if trace:
76
- trace("webhook.delivery.emit_complete")
76
+ trace("callback.delivery.emit_complete")
77
77
  return {
78
78
  "status": "delivered",
79
79
  "attempts": attempts,
@@ -109,8 +109,8 @@ def _is_transient(status_code: int) -> bool:
109
109
 
110
110
 
111
111
  __all__ = [
112
- "build_webhook_payload",
113
- "compile_webhook_delivery_plan",
114
- "deliver_webhook",
115
- "sign_webhook_payload",
112
+ "build_callback_payload",
113
+ "compile_callback_delivery_plan",
114
+ "deliver_callback",
115
+ "sign_callback_payload",
116
116
  ]
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from tigrbl_atoms.atoms.transport.asgi_channel import (
6
+ complete_channel_state as _complete_channel_state,
7
+ )
8
+ from tigrbl_typing.channel import OpChannel
9
+
10
+ from ._asgi_scope import build_asgi_channel
11
+ from ._asgi_send import send_transport_via_channel
12
+ from .websocket import RuntimeWebSocket
13
+
14
+
15
+ def channel_senders():
16
+ from tigrbl_atoms.atoms.egress.asgi_send import _send_json
17
+
18
+ return _send_json, send_transport_via_channel
19
+
20
+
21
+ async def complete_channel(env: Any, ctx: Any) -> None:
22
+ channel = ctx.get("channel")
23
+ if channel is None:
24
+ channel = build_asgi_channel(env)
25
+ ctx["channel"] = channel
26
+ if isinstance(getattr(channel, "state", None), dict):
27
+ _complete_channel_state(channel.state)
28
+ ctx["transport_completed"] = True
29
+ ctx["current_phase"] = "POST_EMIT"
30
+
31
+
32
+ def websocket_adapter(channel: OpChannel) -> RuntimeWebSocket:
33
+ return RuntimeWebSocket(channel)
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any, Mapping
5
+
6
+ from tigrbl_kernel.channel_taxonomy import normalize_exchange
7
+ from tigrbl_typing.channel import OpChannel
8
+
9
+ from ._asgi_jsonrpc import _resolve_jsonrpc_endpoint
10
+ from ._asgi_receive import _receive_session_message
11
+ from ._asgi_scope import _scheme, build_asgi_channel
12
+ from ._asgi_webtransport import (
13
+ _receive_webtransport_session_messages,
14
+ _webtransport_scope_state,
15
+ )
16
+
17
+
18
+ async def prepare_channel_context(env: Any, ctx: Any) -> OpChannel:
19
+ temp = ctx.get("temp")
20
+ if not isinstance(temp, dict):
21
+ ctx["temp"] = {}
22
+ temp = ctx["temp"]
23
+
24
+ route = temp.setdefault("route", {})
25
+ exchange = str(
26
+ route.get("exchange")
27
+ or getattr(ctx, "tigrbl_exchange", None)
28
+ or "request_response"
29
+ )
30
+ exchange = normalize_exchange(exchange)
31
+ protocol = str(route.get("protocol") or _scheme(getattr(env, "scope", {}) or {}))
32
+ framing = route.get("framing")
33
+ channel = build_asgi_channel(
34
+ env,
35
+ exchange=exchange,
36
+ protocol=protocol or None,
37
+ framing=str(framing) if isinstance(framing, str) else None,
38
+ )
39
+ ctx["channel"] = channel
40
+ ctx["path"] = channel.path
41
+ ctx["method"] = channel.method or channel.protocol.upper()
42
+
43
+ dispatch = temp.setdefault("dispatch", {})
44
+ if isinstance(dispatch, dict):
45
+ dispatch.setdefault("channel_protocol", channel.protocol)
46
+ dispatch.setdefault("channel_selector", channel.selector)
47
+ dispatch.setdefault("path_params", dict(channel.path_params))
48
+ endpoint = _resolve_jsonrpc_endpoint(ctx, channel)
49
+ if endpoint:
50
+ dispatch.setdefault("endpoint", endpoint)
51
+
52
+ scope = getattr(env, "scope", {}) or {}
53
+ scope_type = str(scope.get("type") or "http")
54
+ if scope_type == "webtransport":
55
+ await _receive_webtransport_session_messages(env, channel, ctx)
56
+ wt_state = _webtransport_scope_state(env)
57
+ trace = wt_state.get("trace")
58
+ if isinstance(trace, list):
59
+ ctx["webtransport_trace"] = trace
60
+ channel.state["webtransport_trace"] = trace
61
+ hook_trace = wt_state.get("hook_trace")
62
+ if isinstance(hook_trace, list):
63
+ ctx["webtransport_hook_trace"] = hook_trace
64
+ channel.state["webtransport_hook_trace"] = hook_trace
65
+ route.setdefault("protocol", dispatch.get("binding_protocol"))
66
+ route.setdefault("selector", channel.path)
67
+ route.setdefault("path_params", dict(channel.path_params))
68
+ route.setdefault("endpoint", dispatch.get("endpoint"))
69
+ elif scope_type == "websocket":
70
+ await _receive_session_message(
71
+ env,
72
+ channel,
73
+ ctx,
74
+ connect_type="websocket.connect",
75
+ receive_type="websocket.receive",
76
+ disconnect_type="websocket.disconnect",
77
+ eager_payload_after_connect=False,
78
+ )
79
+ message = ctx.get("channel_message")
80
+ if isinstance(message, Mapping) and message.get("text") is not None:
81
+ try:
82
+ parsed = json.loads(str(message.get("text")))
83
+ except Exception:
84
+ parsed = None
85
+ if isinstance(parsed, Mapping) and parsed.get("jsonrpc") == "2.0":
86
+ dispatch["binding_protocol"] = (
87
+ "wss.jsonrpc" if channel.protocol == "wss" else "ws.jsonrpc"
88
+ )
89
+ dispatch["rpc"] = dict(parsed)
90
+ dispatch["rpc_method"] = parsed.get("method")
91
+ route.setdefault("protocol", dispatch.get("binding_protocol"))
92
+ route.setdefault("selector", channel.path)
93
+ route.setdefault("path_params", dict(channel.path_params))
94
+ route.setdefault("endpoint", dispatch.get("endpoint"))
95
+
96
+ return channel
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Mapping
4
+
5
+ from tigrbl_core.config.constants import __JSONRPC_DEFAULT_ENDPOINT_MAPPINGS__
6
+ from tigrbl_typing.channel import OpChannel
7
+
8
+
9
+ def _normalize_path(path: str) -> str:
10
+ return path.rstrip("/") or "/"
11
+
12
+
13
+ def _resolve_jsonrpc_endpoint(ctx: Any, channel: OpChannel) -> str | None:
14
+ if channel.kind != "http" or str(channel.method or "").upper() != "POST":
15
+ return None
16
+
17
+ path = _normalize_path(channel.path)
18
+ route = {}
19
+ temp = ctx.get("temp")
20
+ if isinstance(temp, dict):
21
+ route = temp.setdefault("route", {})
22
+ if isinstance(route, Mapping):
23
+ endpoint = route.get("endpoint")
24
+ if isinstance(endpoint, str) and endpoint:
25
+ return endpoint
26
+
27
+ for owner_key in ("router", "app"):
28
+ owner = ctx.get(owner_key)
29
+ mounts = getattr(owner, "_jsonrpc_endpoint_mounts", None)
30
+ if isinstance(mounts, Mapping):
31
+ endpoint = mounts.get(path) or mounts.get(channel.path)
32
+ if isinstance(endpoint, str) and endpoint:
33
+ return endpoint
34
+
35
+ for endpoint, mapped_path in __JSONRPC_DEFAULT_ENDPOINT_MAPPINGS__.items():
36
+ if path == _normalize_path(mapped_path):
37
+ return endpoint
38
+ return None