@bhooai/nexus-core 2.0.19 → 2.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/app/createNexusApp.ts +43 -7
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ import { Container } from '../di/Container.js';
|
|
|
20
20
|
import { Router } from '../http/Router.js';
|
|
21
21
|
import { NexusServer } from '../http/Server.js';
|
|
22
22
|
import { bodyParser } from '../http/bodyParser.js';
|
|
23
|
-
import type { Handler, Middleware } from '../http/context.js';
|
|
23
|
+
import type { Handler, Middleware, RequestContext } from '../http/context.js';
|
|
24
24
|
import { discoverBackend, importDefault, type DiscoveryResult } from './discover.js';
|
|
25
25
|
import type { RoutesFile, RouteDef } from './defineRoutes.js';
|
|
26
26
|
import { DefaultErrorHandler, ErrorHandler } from './ErrorHandler.js';
|
|
@@ -42,9 +42,36 @@ import { registerAuthRoutes } from './authModule.js';
|
|
|
42
42
|
import { issueCsrfToken, getCsrfToken, csrf, authToken, requireRole } from '@bhooai/nexus-auth';
|
|
43
43
|
import { connect } from '@bhooai/nexus-data';
|
|
44
44
|
import { ensureLicense } from '@bhooai/nexus-crypto';
|
|
45
|
-
import { createGateway, createFederatedGateway, graphqlHttpHandler, getExplorerHtml, helloSubgraph, SubscriptionServer } from '@bhooai/nexus-graphql';
|
|
46
45
|
import type { Subgraph, GraphQLContext } from '@bhooai/nexus-graphql';
|
|
47
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Lazily loaded `@bhooai/nexus-graphql` — an optional peer, not a hard
|
|
49
|
+
* dependency. Static-importing it here would make merely *loading*
|
|
50
|
+
* `@bhooai/nexus-core` (e.g. `nexus init`, which never serves GraphQL)
|
|
51
|
+
* crash when the peer isn't installed. Call sites `await graphqlApi()`
|
|
52
|
+
* instead; null means "not installed" and the gateway mount is skipped
|
|
53
|
+
* with a warning.
|
|
54
|
+
*
|
|
55
|
+
* Typed as `any` (not `typeof import(...)`) so the emitted declarations
|
|
56
|
+
* don't require the peer's types to be present for consumers.
|
|
57
|
+
*/
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
let _graphqlApi: any = undefined;
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
+
async function graphqlApi(): Promise<any> {
|
|
62
|
+
if (_graphqlApi !== undefined) return _graphqlApi;
|
|
63
|
+
try {
|
|
64
|
+
_graphqlApi = await import('@bhooai/nexus-graphql');
|
|
65
|
+
} catch (e) {
|
|
66
|
+
if ((e as { code?: string })?.code === 'ERR_MODULE_NOT_FOUND') {
|
|
67
|
+
_graphqlApi = null;
|
|
68
|
+
} else {
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return _graphqlApi;
|
|
73
|
+
}
|
|
74
|
+
|
|
48
75
|
export interface CreateNexusAppOptions {
|
|
49
76
|
/** Identifier for this backend, used in admin, telemetry, logs. */
|
|
50
77
|
name?: string;
|
|
@@ -368,8 +395,16 @@ export async function createNexusApp(opts: CreateNexusAppOptions = {}): Promise<
|
|
|
368
395
|
let graphqlMounted = false;
|
|
369
396
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
370
397
|
let graphqlGateway: any = null;
|
|
398
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
399
|
+
let GraphqlSubscriptionServer: any = null;
|
|
371
400
|
if (tech === 'react') {
|
|
372
401
|
{
|
|
402
|
+
const gql = await graphqlApi();
|
|
403
|
+
if (!gql) {
|
|
404
|
+
console.warn(`[${name}] @bhooai/nexus-graphql is not installed — GraphQL gateway skipped (npm i @bhooai/nexus-graphql to enable).`);
|
|
405
|
+
} else {
|
|
406
|
+
const { createGateway, createFederatedGateway, graphqlHttpHandler, getExplorerHtml, helloSubgraph, SubscriptionServer } = gql;
|
|
407
|
+
GraphqlSubscriptionServer = SubscriptionServer;
|
|
373
408
|
const explorerEnabled = (config.graphql as unknown as { explorer?: boolean })?.explorer ?? true;
|
|
374
409
|
const helloEnabled = (config.graphql as unknown as { hello?: boolean })?.hello !== false;
|
|
375
410
|
try {
|
|
@@ -415,7 +450,7 @@ export async function createNexusApp(opts: CreateNexusAppOptions = {}): Promise<
|
|
|
415
450
|
gateway,
|
|
416
451
|
introspection: config.graphql?.introspection ?? true,
|
|
417
452
|
requireMutationCsrf: config.graphql?.requireMutationCsrf ?? true,
|
|
418
|
-
context: (ctx) => ({ request: ctx, user: (ctx.state.user as GraphQLContext['user']), config: ctx.config ?? config, ...opts.graphqlContext }),
|
|
453
|
+
context: (ctx: RequestContext) => ({ request: ctx, user: (ctx.state.user as GraphQLContext['user']), config: ctx.config ?? config, ...opts.graphqlContext }),
|
|
419
454
|
});
|
|
420
455
|
if (explorerEnabled) {
|
|
421
456
|
const explorerHtml = getExplorerHtml({
|
|
@@ -462,7 +497,7 @@ export async function createNexusApp(opts: CreateNexusAppOptions = {}): Promise<
|
|
|
462
497
|
if (helloEnabled) {
|
|
463
498
|
// hello is available even in fallback — route through its gateway
|
|
464
499
|
const gw = createGateway({ subgraph: helloSubgraph });
|
|
465
|
-
const h = graphqlHttpHandler({ gateway: gw, introspection: config.graphql?.introspection ?? true, requireMutationCsrf: config.graphql?.requireMutationCsrf ?? true, context: (ctx) => ({ request: ctx, user: (ctx.state.user as GraphQLContext['user']), config: ctx.config ?? config, ...opts.graphqlContext }) });
|
|
500
|
+
const h = graphqlHttpHandler({ gateway: gw, introspection: config.graphql?.introspection ?? true, requireMutationCsrf: config.graphql?.requireMutationCsrf ?? true, context: (ctx: RequestContext) => ({ request: ctx, user: (ctx.state.user as GraphQLContext['user']), config: ctx.config ?? config, ...opts.graphqlContext }) });
|
|
466
501
|
return h(ctx);
|
|
467
502
|
}
|
|
468
503
|
ctx.json({ errors: [{ message: 'No GraphQL subgraph found. Add one with: npx nexus make:subgraph <name> (then restart)' }] }, 404);
|
|
@@ -472,7 +507,7 @@ export async function createNexusApp(opts: CreateNexusAppOptions = {}): Promise<
|
|
|
472
507
|
try {
|
|
473
508
|
if (helloEnabled) {
|
|
474
509
|
const gw = createGateway({ subgraph: helloSubgraph });
|
|
475
|
-
router.add('POST', graphqlPath, graphqlHttpHandler({ gateway: gw, introspection: config.graphql?.introspection ?? true, requireMutationCsrf: config.graphql?.requireMutationCsrf ?? true, context: (ctx) => ({ request: ctx, user: (ctx.state.user as GraphQLContext['user']), config: ctx.config ?? config, ...opts.graphqlContext }) }));
|
|
510
|
+
router.add('POST', graphqlPath, graphqlHttpHandler({ gateway: gw, introspection: config.graphql?.introspection ?? true, requireMutationCsrf: config.graphql?.requireMutationCsrf ?? true, context: (ctx: RequestContext) => ({ request: ctx, user: (ctx.state.user as GraphQLContext['user']), config: ctx.config ?? config, ...opts.graphqlContext }) }));
|
|
476
511
|
} else {
|
|
477
512
|
router.add('POST', graphqlPath, async (ctx) => ctx.json({ errors: [{ message: 'No GraphQL subgraph found. Add one with: npx nexus make:subgraph <name>' }] }, 404));
|
|
478
513
|
}
|
|
@@ -482,6 +517,7 @@ export async function createNexusApp(opts: CreateNexusAppOptions = {}): Promise<
|
|
|
482
517
|
}
|
|
483
518
|
}
|
|
484
519
|
}
|
|
520
|
+
}
|
|
485
521
|
|
|
486
522
|
// ------------------------------------------------------------------
|
|
487
523
|
// Admin module — request log buffer, lazy DB, admin + AI proxy routes
|
|
@@ -737,10 +773,10 @@ export async function createNexusApp(opts: CreateNexusAppOptions = {}): Promise<
|
|
|
737
773
|
// and config.graphql.subscriptions is enabled.
|
|
738
774
|
// ------------------------------------------------------------------
|
|
739
775
|
const graphqlSubscriptions = (config.graphql as unknown as { subscriptions?: boolean })?.subscriptions ?? true;
|
|
740
|
-
if (graphqlGateway && graphqlSubscriptions && typeof graphqlGateway.subscribe === 'function') {
|
|
776
|
+
if (graphqlGateway && GraphqlSubscriptionServer && graphqlSubscriptions && typeof graphqlGateway.subscribe === 'function') {
|
|
741
777
|
try {
|
|
742
778
|
const subPath = `${config.graphql?.path ?? '/graphql'}/ws`;
|
|
743
|
-
new
|
|
779
|
+
new GraphqlSubscriptionServer({ httpServer: server.httpServer, gateway: graphqlGateway, path: subPath });
|
|
744
780
|
console.log(`[${name}] GraphQL subscriptions mounted at ${subPath}`);
|
|
745
781
|
} catch (err) {
|
|
746
782
|
console.warn(`[${name}] failed to mount GraphQL subscriptions:`, err);
|