feat: initial Signage 0.1.0
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import {
|
||||
ANONYMOUS_PRINCIPAL,
|
||||
type CapabilityId,
|
||||
EMPTY_MODULE_CONFIGURATION,
|
||||
EMPTY_MODULE_STORAGE,
|
||||
type ModuleConfiguration,
|
||||
type ModuleRouteDefinitionInput,
|
||||
type ModuleRouteHandlerContext,
|
||||
type ModuleRuntimeServices,
|
||||
type RegisteredCapability,
|
||||
} from "@ekklesia/module-sdk";
|
||||
import moduleRuntime from "../../src/server/index.js";
|
||||
|
||||
/**
|
||||
* The module-layer test harness: everything a Signage unit test needs to exercise the real runtime
|
||||
* definition without a platform.
|
||||
*
|
||||
* Every object here is a `@ekklesia/contracts` interface constructed by hand, which is exactly what
|
||||
* a module-layer test may legitimately do — a module may never import Core. It also demonstrates the
|
||||
* portability claim directly: the host producing these objects could be Ekklesia, or a future
|
||||
* standalone host reading YAML from disk, and Signage cannot tell the difference.
|
||||
*/
|
||||
export interface CapturedRegistration {
|
||||
readonly channels: { channel: string; permission: string }[];
|
||||
readonly provided: Map<CapabilityId, unknown>;
|
||||
readonly routes: ModuleRouteDefinitionInput[];
|
||||
}
|
||||
|
||||
export async function registerModule(
|
||||
config: ModuleConfiguration = EMPTY_MODULE_CONFIGURATION,
|
||||
): Promise<CapturedRegistration> {
|
||||
const channels: { channel: string; permission: string }[] = [];
|
||||
const provided = new Map<CapabilityId, unknown>();
|
||||
const routes: ModuleRouteDefinitionInput[] = [];
|
||||
await moduleRuntime.register?.({
|
||||
capabilities: {
|
||||
provide(capabilityId, implementation) {
|
||||
provided.set(capabilityId, implementation);
|
||||
},
|
||||
resolve(_capabilityId: CapabilityId): RegisteredCapability | undefined {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
config,
|
||||
http: {
|
||||
route(definition) {
|
||||
routes.push(definition);
|
||||
},
|
||||
},
|
||||
moduleId: "signage",
|
||||
realtime: {
|
||||
channel(definition) {
|
||||
channels.push({ channel: definition.channel, permission: definition.permission });
|
||||
},
|
||||
},
|
||||
});
|
||||
return { channels, provided, routes };
|
||||
}
|
||||
|
||||
export function findRoute(
|
||||
registration: CapturedRegistration,
|
||||
method: string,
|
||||
path: string,
|
||||
): ModuleRouteDefinitionInput {
|
||||
const route = registration.routes.find(
|
||||
(candidate) => candidate.method === method && candidate.path === path,
|
||||
);
|
||||
if (!route) {
|
||||
throw new Error(`Signage did not register ${method} ${path}.`);
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
export function fakeConfiguration(values: Readonly<Record<string, unknown>>): ModuleConfiguration {
|
||||
const read = <Value>(key: string, kind: string): Value | undefined => {
|
||||
const value = values[key];
|
||||
return typeof value === kind ? (value as Value) : undefined;
|
||||
};
|
||||
return Object.freeze({
|
||||
get: (key: string) => values[key] as never,
|
||||
getBoolean: (key: string) => read<boolean>(key, "boolean"),
|
||||
getEnum: (key: string) => read<string>(key, "string"),
|
||||
getInteger: (key: string) => read<number>(key, "number"),
|
||||
getSecret: (key: string) => read<string>(key, "string"),
|
||||
getString: (key: string) => read<string>(key, "string"),
|
||||
getUrl: (key: string) => read<string>(key, "string"),
|
||||
has: (key: string) => Object.hasOwn(values, key),
|
||||
keys: () => Object.freeze(Object.keys(values)),
|
||||
});
|
||||
}
|
||||
|
||||
export function fakeHandlerContext(
|
||||
overrides: Partial<ModuleRouteHandlerContext> = {},
|
||||
): ModuleRouteHandlerContext {
|
||||
const services = { database: undefined } as unknown as ModuleRuntimeServices;
|
||||
return Object.freeze({
|
||||
config: EMPTY_MODULE_CONFIGURATION,
|
||||
moduleId: "signage",
|
||||
params: Object.freeze({}),
|
||||
principal: ANONYMOUS_PRINCIPAL,
|
||||
realtime: { publish: () => undefined },
|
||||
services,
|
||||
storage: EMPTY_MODULE_STORAGE,
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user