feat: add native module realtime transport
CI / verify (pull_request) Successful in 37s
CI / infrastructure-smoke (pull_request) Successful in 13s
CI / migration-smoke (pull_request) Successful in 1m7s

This commit is contained in:
ekklesia
2026-08-23 18:47:18 -05:00
parent fcc531a39c
commit fc6c8045c4
53 changed files with 3959 additions and 108 deletions
+12 -4
View File
@@ -6,7 +6,11 @@ import {
type ModuleRuntimeServices,
type RegisteredModuleHttpRoute,
} from "@ekklesia/contracts";
import type { ModuleConfigurationLookup, ModuleStorageLookup } from "@ekklesia/core/modules";
import type {
ModuleConfigurationLookup,
ModuleRealtimeRegistry,
ModuleStorageLookup,
} from "@ekklesia/core/modules";
import type { Context, Hono } from "hono";
import {
type AuthorizationMiddlewareOptions,
@@ -53,6 +57,8 @@ export interface ModuleHttpRoutesOptions extends AuthorizationMiddlewareOptions
* its own module's storage, because that is the only entry looked up for it.
*/
readonly storages: ModuleStorageLookup;
/** The same started registry whose scoped publishers lifecycle hooks receive. */
readonly realtime: ModuleRealtimeRegistry;
}
/** Never carries the offending permission id, route path, module id, or any other configuration
@@ -195,9 +201,10 @@ function sanitizeModuleResponse(response: Response): Response {
* implicit `HEAD` handling, which re-enters this exact same middleware chain and strips the
* response body afterward — there is no separate `HEAD` registration or permission path.
* `route.handler` is invoked only after authorization succeeds, with the raw Fetch `Request` and a
* frozen context carrying exactly `moduleId`, `principal`, `params`, and `services` — never a Hono
* `Context`, authorization store, or configuration; `services.database` is the module's only
* reachable database surface, and is unreachable to anything short of a successfully authorized
* frozen context carrying exactly `config`, `moduleId`, `params`, `principal`, `realtime`,
* `services`, and `storage` — never a Hono `Context`, authorization store, raw provider, or
* deployment-wide configuration. `services.database` is the module's only reachable database
* surface, and the whole context is unreachable to anything short of a successfully authorized
* handler invocation (a denied request, a rejected trusted-origin check, and `OPTIONS` never reach
* this handler at all).
*
@@ -239,6 +246,7 @@ export function mountModuleHttpRoutes(
storage: options.storages.get(route.moduleId) ?? EMPTY_MODULE_STORAGE,
params: Object.freeze({ ...c.req.param() }),
principal: getAuthorizedPrincipal(c),
realtime: options.realtime.publisherFor(route.moduleId),
services: options.services,
});