mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 16:03:02 +00:00
e40bc71e9f
Every domain's *.rpc.ts was written against rpc-kit, rpc-params, rpc-errors and PluginGuards, and every domain module imported PluginGuardsModule, all of it inside src/nest/plugins, while PluginsRuntimeModule imports those same domains so their handlers exist at boot. That made the plugins domain part of every cycle. The kit imports no domain but the protocol tables and permissions/addons for the guards, so it moves to src/nest-rpc beside src/nest-mcp, with its tests, its README and its extraction rule; the runtime module keeps its domain imports, which the boot-time coverage check of the wire surface needs in any subset app.
95 lines
3.4 KiB
TypeScript
95 lines
3.4 KiB
TypeScript
/**
|
|
* The metadata store under the plugin RPC decorators. It is a WeakMap/WeakSet keyed
|
|
* by constructor rather than reflect-metadata, so these tests run without a Nest app
|
|
* and without any polyfill import order to get right.
|
|
*/
|
|
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
addEntry,
|
|
getEntry,
|
|
isPluginController,
|
|
markController,
|
|
type ClassRef,
|
|
} from '../../../../src/nest-rpc/rpc-kit/metadata';
|
|
import type { PluginRpcEntry } from '../../../../src/nest-rpc/rpc-kit/types';
|
|
|
|
const methodEntry = (methodName: string, method: 'tags.list' | 'tags.create' = 'tags.list'): PluginRpcEntry => ({
|
|
kind: 'method',
|
|
methodName,
|
|
method,
|
|
permission: method === 'tags.list' ? 'db:read:tags' : 'db:write:tags',
|
|
});
|
|
|
|
describe('rpc-kit metadata store', () => {
|
|
it('RPCKIT-META-001 an unmarked class is not a plugin controller', () => {
|
|
class Plain {}
|
|
expect(isPluginController(Plain)).toBe(false);
|
|
});
|
|
|
|
it('RPCKIT-META-002 markController makes the class recognisable', () => {
|
|
class Marked {}
|
|
markController(Marked as unknown as ClassRef);
|
|
expect(isPluginController(Marked)).toBe(true);
|
|
});
|
|
|
|
it('RPCKIT-META-003 a non-function is never a controller', () => {
|
|
expect(isPluginController({})).toBe(false);
|
|
expect(isPluginController(undefined)).toBe(false);
|
|
expect(isPluginController('Marked')).toBe(false);
|
|
});
|
|
|
|
it('RPCKIT-META-004 an entry is retrievable by its method name', () => {
|
|
class Holder {}
|
|
const entry = methodEntry('list');
|
|
addEntry(Holder as unknown as ClassRef, entry);
|
|
expect(getEntry(Holder as unknown as ClassRef, 'list')).toBe(entry);
|
|
});
|
|
|
|
it('RPCKIT-META-005 an unknown method name resolves to undefined', () => {
|
|
class Holder {}
|
|
addEntry(Holder as unknown as ClassRef, methodEntry('list'));
|
|
expect(getEntry(Holder as unknown as ClassRef, 'missing')).toBeUndefined();
|
|
});
|
|
|
|
it('RPCKIT-META-006 a second entry for the same name replaces the first', () => {
|
|
class Holder {}
|
|
addEntry(Holder as unknown as ClassRef, methodEntry('list'));
|
|
const second = methodEntry('list', 'tags.create');
|
|
addEntry(Holder as unknown as ClassRef, second);
|
|
expect(getEntry(Holder as unknown as ClassRef, 'list')).toBe(second);
|
|
});
|
|
|
|
it('RPCKIT-META-007 entries are found on a subclass through the prototype chain', () => {
|
|
class Base {}
|
|
class Child extends Base {}
|
|
const entry = methodEntry('list');
|
|
addEntry(Base as unknown as ClassRef, entry);
|
|
expect(getEntry(Child as unknown as ClassRef, 'list')).toBe(entry);
|
|
});
|
|
|
|
it('RPCKIT-META-008 a subclass entry wins over the inherited one', () => {
|
|
class Base {}
|
|
class Child extends Base {}
|
|
addEntry(Base as unknown as ClassRef, methodEntry('list'));
|
|
const own = methodEntry('list', 'tags.create');
|
|
addEntry(Child as unknown as ClassRef, own);
|
|
expect(getEntry(Child as unknown as ClassRef, 'list')).toBe(own);
|
|
});
|
|
|
|
it('RPCKIT-META-009 walking the chain stops cleanly at the root', () => {
|
|
class Lonely {}
|
|
expect(getEntry(Lonely as unknown as ClassRef, 'anything')).toBeUndefined();
|
|
});
|
|
|
|
it('RPCKIT-META-010 two classes keep separate entry maps', () => {
|
|
class A {}
|
|
class B {}
|
|
const a = methodEntry('list');
|
|
const b = methodEntry('list', 'tags.create');
|
|
addEntry(A as unknown as ClassRef, a);
|
|
addEntry(B as unknown as ClassRef, b);
|
|
expect(getEntry(A as unknown as ClassRef, 'list')).toBe(a);
|
|
expect(getEntry(B as unknown as ClassRef, 'list')).toBe(b);
|
|
});
|
|
});
|