This page documents the 0.4 release candidates of @nexusdi/core. The newest on npm is 0.4.0-rc.1. The documentation for 0.3.2, the current release, is at nexus.js.org. Try the release candidate.
NEXUS_INTERCEPTOR_MISSING
@nexusdi/interceptors reports NEXUS_INTERCEPTOR_MISSING when a global entry, a binding, a static interceptors declaration or a @UseInterceptors call names an interceptor token that interceptors({ register }) does not list. The plugin’s check finds it while the graph compiles, before any constructor runs. Nexus.create and ship.load() reject with NEXUS_BLUEPRINT_INVALID holding one error for each unregistered use, and Nexus.check throws that error. A token is compared by identity, so a second new Token('Audit') is another token, and the message prints the same name for both.
Reproduce NEXUS_INTERCEPTOR_MISSING
interceptors() reports NEXUS_INTERCEPTOR_MISSING when global names AUDIT and register lists only TRACE. Without a text pack, the message is one line that starts with the code and ends with the address of this page.
import { Nexus, Token, defineModule, provide } from '@nexusdi/core';
import { isNexusError } from '@nexusdi/core';
import { interceptor, interceptors } from '@nexusdi/interceptors';
import type { CallContext, Interceptor, Next } from '@nexusdi/interceptors';
interface IReactorCore {
output(): number;
}
const REACTOR = new Token<IReactorCore>('ReactorCore');
const TRACE = new Token<Interceptor>('Trace');
const AUDIT = new Token<Interceptor>('Audit');
class TraceInterceptor implements Interceptor {
intercept(_call: CallContext, next: Next) {
return next();
}
}
class FusionReactor implements IReactorCore {
output() {
return 1.21;
}
}
const Engineering = defineModule({
name: 'Engineering',
providers: [provide(REACTOR, { useClass: FusionReactor })],
exports: [REACTOR],
});
// The global entry names AUDIT, and register lists TRACE alone.
const error = await Nexus.create(Engineering, {
plugins: [
interceptors({
register: [interceptor(TRACE, { useClass: TraceInterceptor })],
global: [AUDIT],
}),
],
}).catch((caught: unknown) => caught);
const inner = isNexusError(error, 'NEXUS_BLUEPRINT_INVALID')
? error.errors[0]
: undefined;
const message = inner?.message; // -> '[NEXUS_INTERCEPTOR_MISSING] token=Audit. https://nexus.js.org/errors/NEXUS_INTERCEPTOR_MISSING'
console.log(message);Try it: run npm install @nexusdi/core@next @nexusdi/interceptors@next, save the region as missing.ts and run npx tsx missing.ts. It prints the one-line message: [NEXUS_INTERCEPTOR_MISSING] token=Audit. and the address of this page. Change global: [AUDIT] to global: [TRACE], delete the AUDIT declaration and run it again. The container builds, and the region prints undefined because there is no error to read. Put the declaration back and the message returns.
Full text of NEXUS_INTERCEPTOR_MISSING with errors()
NEXUS_INTERCEPTOR_MISSING carries its full text and fix line when interceptorsText from @nexusdi/interceptors/text is passed to errors() from @nexusdi/errors, as errors({ text: [interceptorsText] }) in the plugins of Nexus.create. devtools({ text: [interceptorsText] }) words the error the same way. The text names the place that uses the token: a class, a method of a class, a binding’s method, or a global entry or binding.
import { Nexus, Token, defineModule, provide } from '@nexusdi/core';
import { isNexusError } from '@nexusdi/core';
import { errors } from '@nexusdi/errors';
import { interceptor, interceptors } from '@nexusdi/interceptors';
import type { CallContext, Interceptor, Next } from '@nexusdi/interceptors';
import { interceptorsText } from '@nexusdi/interceptors/text';
interface IReactorCore {
output(): number;
}
const REACTOR = new Token<IReactorCore>('ReactorCore');
const TRACE = new Token<Interceptor>('Trace');
const AUDIT = new Token<Interceptor>('Audit');
class TraceInterceptor implements Interceptor {
intercept(_call: CallContext, next: Next) {
return next();
}
}
class FusionReactor implements IReactorCore {
output() {
return 1.21;
}
}
const Engineering = defineModule({
name: 'Engineering',
providers: [provide(REACTOR, { useClass: FusionReactor })],
exports: [REACTOR],
});
const error = await Nexus.create(Engineering, {
plugins: [
errors({ text: [interceptorsText] }),
interceptors({
register: [interceptor(TRACE, { useClass: TraceInterceptor })],
global: [AUDIT],
}),
],
}).catch((caught: unknown) => caught);
const inner = isNexusError(error, 'NEXUS_BLUEPRINT_INVALID')
? error.errors[0]
: undefined;
const lines = inner?.message.split('\n'); // -> ['[NEXUS_INTERCEPTOR_MISSING] a global entry or binding uses the interceptor Audit, which is not registered.', ' Fix: add Audit to interceptors({ register }).']
console.log(lines?.join('\n'));Try it: run npm install @nexusdi/errors@next, save the region as full.ts and run npx tsx full.ts. It prints the two-line message with its Fix: line: [NEXUS_INTERCEPTOR_MISSING] a global entry or binding uses the interceptor Audit, which is not registered. and Fix: add Audit to interceptors({ register }).
Fix NEXUS_INTERCEPTOR_MISSING
NEXUS_INTERCEPTOR_MISSING goes away when every interceptor token a declaration names is in interceptors({ register }). Register the token with interceptor(TOKEN, { useClass }), or register an interceptor class that is its own token. When the token is a typo, correct the declaration.
import { Nexus, Token, defineModule, provide } from '@nexusdi/core';
import { interceptor, interceptors } from '@nexusdi/interceptors';
import type { CallContext, Interceptor, Next } from '@nexusdi/interceptors';
interface IReactorCore {
output(): number;
}
const REACTOR = new Token<IReactorCore>('ReactorCore');
const TRACE = new Token<Interceptor>('Trace');
const AUDIT = new Token<Interceptor>('Audit');
const calls: string[] = [];
class TraceInterceptor implements Interceptor {
intercept(_call: CallContext, next: Next) {
calls.push('trace');
return next();
}
}
class AuditInterceptor implements Interceptor {
intercept(_call: CallContext, next: Next) {
calls.push('audit');
return next();
}
}
class FusionReactor implements IReactorCore {
output() {
return 1.21;
}
}
const Engineering = defineModule({
name: 'Engineering',
providers: [provide(REACTOR, { useClass: FusionReactor })],
exports: [REACTOR],
});
await using ship = await Nexus.create(Engineering, {
plugins: [
interceptors({
register: [
interceptor(TRACE, { useClass: TraceInterceptor }),
interceptor(AUDIT, { useClass: AuditInterceptor }),
],
global: [TRACE, AUDIT],
}),
],
});
const output = ship.get(REACTOR).output(); // -> 1.21
console.log(output);
const seen = calls; // -> ['trace', 'audit']
console.log(seen);The fix region differs from the reproduce region in two ways. It registers AuditInterceptor, which it declares, and lists both tokens in global. It then calls output() on the container it keeps and prints what the interceptors saw.
Try it: save the region as fixed.ts and run npx tsx fixed.ts. It prints 1.21 and [ 'trace', 'audit' ]. Delete the line interceptor(AUDIT, { useClass: AuditInterceptor }), from the register list and the AuditInterceptor class, and run it again. npx tsc accepts the file, and npx tsx fixed.ts throws an uncaught BlueprintError and prints a stack trace headed BlueprintError: [NEXUS_BLUEPRINT_INVALID] 1 error., whose message goes on with the line [NEXUS_INTERCEPTOR_MISSING] token=Audit. and the address of this page. Put the line and the class back and the program prints its two lines again.
Method Interceptors shows each way to attach an interceptor.
Fields of InterceptorError
code:'NEXUS_INTERCEPTOR_MISSING'.reason:nullfor this code.token: the name of the interceptor token that is not registered.target: the name of the class whose declaration names the token, ornullfor a global entry or a binding.method: the method name when a method list names the token, ornullfor a class list, a global entry or a binding’s class list. A binding’s method list sets it, andtargetstaysnull.state:nullfor this code.detail: an empty list for this code.