Full SDK workspace: core, contracts, sdk, cli, browser-host, browser-kit, federation, omega-core, oracle, self-healing, strategies, tools, emacs. Clean extraction from the development monorepo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
67 lines
2.6 KiB
TypeScript
67 lines
2.6 KiB
TypeScript
import { mxesc1Decode, mxesc1Encode } from './mxesc1';
|
|
|
|
export type WireProfileName = 'matrix3' | 'mxenv1';
|
|
|
|
export interface IngressAddress {
|
|
profile: WireProfileName;
|
|
root: string;
|
|
/** @deprecated Use root instead */
|
|
realm?: string;
|
|
shard?: string; // mxenv1
|
|
}
|
|
|
|
function assertRootSegment(root: string): void {
|
|
if (!root || typeof root !== 'string') throw new Error('root must be a non-empty string');
|
|
if (root.includes('/')) throw new Error(`root must not contain slashes: ${root}`);
|
|
if (root.includes('+') || root.includes('#')) throw new Error('root must not contain wildcards');
|
|
// DNS roots may contain dots (e.g., 'com.nimbletec.richard.santomauro')
|
|
}
|
|
|
|
/** Legacy Matrix-3 mailbox: public.ingress.<mxesc1(root)> */
|
|
export function getLegacyIngressTopic(root: string): string {
|
|
// legacy format uses mxesc1 because the root may include characters unsafe in a dot-segment.
|
|
return `public.ingress.${mxesc1Encode(root)}`;
|
|
}
|
|
|
|
export function extractLegacyRootFromIngressTopic(topic: string): string | null {
|
|
const prefix = 'public.ingress.';
|
|
if (!topic.startsWith(prefix)) return null;
|
|
try {
|
|
return mxesc1Decode(topic.slice(prefix.length));
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/** @deprecated Use extractLegacyRootFromIngressTopic instead */
|
|
export const extractLegacyRealmFromIngressTopic = extractLegacyRootFromIngressTopic;
|
|
|
|
/** DNS-hierarchical ingress topic: {root}.$ingress.{shard} */
|
|
export function getMxIngressTopic(root: string, shard: string = '00'): string {
|
|
assertRootSegment(root);
|
|
if (!/^[0-9]{2}$/.test(shard)) throw new Error(`invalid shard '${shard}' (expected two digits like '00')`);
|
|
return `${root}.$ingress.${shard}`;
|
|
}
|
|
|
|
export function extractMxIngressFromTopic(topic: string): { root: string; shard: string } | null {
|
|
// Format: {root}.$ingress.{shard} — find the .$ingress. separator
|
|
const ingressIdx = topic.indexOf('.$ingress.');
|
|
if (ingressIdx < 0) return null;
|
|
const root = topic.slice(0, ingressIdx);
|
|
const shard = topic.slice(ingressIdx + '.$ingress.'.length);
|
|
if (!/^[0-9]{2}$/.test(shard)) return null;
|
|
if (!root) return null;
|
|
return { root, shard };
|
|
}
|
|
|
|
/**
|
|
* Internal semantic topic — returns the semantic path directly.
|
|
* With DNS hierarchical addressing, the transport (NatsTransport) handles
|
|
* root prefix encoding. The federation layer just passes semantic topics.
|
|
*/
|
|
export function getInternalTopic(_root: string, toPath: string): string {
|
|
if (!toPath || typeof toPath !== 'string') throw new Error('toPath must be a non-empty string');
|
|
if (toPath.startsWith('/')) throw new Error('toPath must not start with /');
|
|
return toPath;
|
|
}
|