@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bhooai/nexus-core",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -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 SubscriptionServer({ httpServer: server.httpServer, gateway: graphqlGateway, path: subPath });
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);