@beignet/core
Version:
Core framework primitives for Beignet
65 lines (58 loc) • 1.98 kB
text/typescript
/**
* Unbound port placeholders for deferred `definePorts(...)` keys.
*
* Ports declared as deferred boot as marked placeholders. Any method call on
* a placeholder throws a descriptive error, and `createServer(...)` scans
* final ports after provider startup so a missing provider fails boot instead
* of failing on first use.
*/
const UNBOUND_PORT_MARKER = Symbol.for("beignet.unboundPort");
function unboundPortMessage(portName: string): string {
return (
`Port "${portName}" is not bound. "${portName}" is declared as deferred ` +
"in definePorts(...). Register a provider that contributes it " +
"(server/providers.ts) or bind it in infra/port-wiring.ts."
);
}
/**
* Create a marked placeholder for a deferred port.
*
* Property access returns a function that throws, so calling any method on an
* unbound port produces a descriptive error naming the port.
*/
export function createUnboundPort(portName: string): unknown {
return new Proxy(
{},
{
get(_target, property) {
if (property === UNBOUND_PORT_MARKER) return true;
if (property === Symbol.toStringTag) {
return `UnboundPort(${portName})`;
}
// Keep unbound ports safe to `await` and JSON-serialize.
if (property === "then" || property === "toJSON") return undefined;
if (typeof property === "symbol") return undefined;
if (property === "toString") {
return () => `[unbound port "${portName}"]`;
}
return () => {
throw new Error(unboundPortMessage(portName));
};
},
},
);
}
/**
* Check whether a value is an unbound port placeholder created for a deferred
* `definePorts(...)` key.
*/
export function isUnboundPort(value: unknown): boolean {
if (value === null || typeof value !== "object") return false;
try {
return (
(value as Record<PropertyKey, unknown>)[UNBOUND_PORT_MARKER] === true
);
} catch {
return false;
}
}