@kb-labs/gateway-app 2.96.0 → 2.100.0

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/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { createServiceBootstrap, platform, getPlatformRoot, getProjectRoot, getA
4
4
  import { makeAssemblyHook } from '@kb-labs/plugin-runtime';
5
5
  import { createCorrelatedLogger, registerOpenAPI, createServiceReadyResponse, OperationMetricsTracker, createServiceObservabilityDescribe, createServiceObservabilityHealth } from '@kb-labs/shared-http';
6
6
  import { HostStore, globalDispatcher, AdaptiveBuffer } from '@kb-labs/gateway-core';
7
- import { UsersStore, CredentialsStore, MembershipsStore, SessionsStore, InvitesStore, loadIdentityProviders, createPasswordPolicy, createStubPDP, createTenantResolver, createUserAuthService, ensureBootstrapAdmin, createRateLimiter, OAuthStateStore, AuthService, verifyUserAccessToken, AuthError, getClientByHandle, issueCsrfToken, verifyCsrfToken, getClientByHostId } from '@kb-labs/gateway-auth';
7
+ import { UsersStore, CredentialsStore, MembershipsStore, SessionsStore, InvitesStore, loadIdentityProviders, createPasswordPolicy, createStubPDP, createTenantResolver, createUserAuthService, ensureBootstrapAdmin, createRateLimiter, OAuthStateStore, AuthService, ensureBootstrapCliCredentials, verifyUserAccessToken, AuthError, getClientByHandle, issueCsrfToken, verifyCsrfToken, getClientByHostId } from '@kb-labs/gateway-auth';
8
8
  import { createRegistry, mergeOpenAPISpecs } from '@kb-labs/core-registry';
9
9
  import { loadEffectiveConfig } from '@kb-labs/core-config';
10
10
  import { GatewayConfigSchema, HostRegistrationSchema, RegisterRequestSchema, TokenRequestSchema, RefreshRequestSchema, ExecuteRequestSchema, ChatCompletionRequestSchema, TelemetryIngestRequestSchema, PlatformCallRequestSchema, HelloMessageSchema, SUPPORTED_PROTOCOL_VERSIONS, HostCapabilitySchema, AdapterCallMessageSchema, AdapterNameSchema, ClientHelloSchema, ClientCancelSchema, ClientUnsubscribeSchema, ClientSubscribeSchema, CLIENT_PROTOCOL_VERSION } from '@kb-labs/gateway-contracts';
@@ -68,6 +68,14 @@ var PUBLIC_ROUTES = /* @__PURE__ */ new Set([
68
68
  "/health",
69
69
  "/health/adapters",
70
70
  "/ready",
71
+ // Studio SPA shell (index.html) — the login page itself. There is no
72
+ // session yet when a browser first hits this, so it can't be gated.
73
+ // Exact match only (not a prefix) so it doesn't swallow unrelated routes.
74
+ "/",
75
+ // Module Federation manifest — static, non-sensitive metadata describing
76
+ // available Studio remotes. The Studio SPA shell must be able to fetch
77
+ // this before a user has logged in (there is no session yet to gate on).
78
+ "/mf-manifest.json",
71
79
  "/hosts/register",
72
80
  // /hosts/connect and /clients/connect are handled at the HTTP upgrade level
73
81
  // by gateway-ws.ts (raw ws) — they never reach Fastify routing.
@@ -99,6 +107,15 @@ function createAuthMiddleware(cache, jwtConfig, options = {}) {
99
107
  if (routePath.startsWith("/auth/oauth/")) {
100
108
  return;
101
109
  }
110
+ if (routePath.startsWith("/webhooks/")) {
111
+ return;
112
+ }
113
+ if (routePath.startsWith("/plugins/")) {
114
+ return;
115
+ }
116
+ if (routePath.startsWith("/studio/")) {
117
+ return;
118
+ }
102
119
  const queryToken = request.query["access_token"];
103
120
  const token = extractBearerToken(request.headers.authorization) ?? queryToken ?? null;
104
121
  if (!token && request.userAuthContext) {
@@ -493,7 +510,12 @@ function registerUserAuthRoutes(app, deps) {
493
510
  if (!auth) {
494
511
  return reply.code(401).send({ error: "Unauthorized", message: "Not authenticated" });
495
512
  }
496
- return reply.send({ userId: auth.userId, namespaceId: auth.namespaceId });
513
+ return reply.send({
514
+ userId: auth.userId,
515
+ namespaceId: auth.namespaceId,
516
+ email: auth.userId,
517
+ tenantId: auth.namespaceId
518
+ });
497
519
  });
498
520
  app.get("/auth/providers", {
499
521
  schema: { tags: ["Auth"], summary: "List registered identity providers" }
@@ -1292,7 +1314,7 @@ async function resolveLLMForTier(tier) {
1292
1314
  return llm;
1293
1315
  }
1294
1316
  function registerLLMGatewayRoutes(app, logger) {
1295
- app.post("/llm/v1/chat/completions", { schema: { tags: ["LLM"], summary: "OpenAI-compatible chat completions", hide: true } }, async (request, reply) => {
1317
+ app.post("/api/v1/llm/chat/completions", { schema: { tags: ["LLM"], summary: "OpenAI-compatible chat completions", hide: true } }, async (request, reply) => {
1296
1318
  const auth = request.authContext;
1297
1319
  if (!auth) {
1298
1320
  return reply.code(401).send({ error: "Unauthorized" });
@@ -3782,6 +3804,20 @@ async function createServer(config, cache, logger, jwtConfig, registry, serviceT
3782
3804
  statusCode: reply.statusCode
3783
3805
  });
3784
3806
  });
3807
+ if (userAuth) {
3808
+ app.addHook(
3809
+ "onRequest",
3810
+ createUserAuthMiddleware({
3811
+ users: userAuth.users,
3812
+ tenantResolver: userAuth.tenantResolver,
3813
+ jwtConfig
3814
+ })
3815
+ );
3816
+ }
3817
+ app.addHook(
3818
+ "onRequest",
3819
+ createAuthMiddleware(cache, jwtConfig, { authEnabled: config.auth?.enabled !== false })
3820
+ );
3785
3821
  const socketWsUpstreams = [];
3786
3822
  for (const [name, upstream] of Object.entries(config.upstreams)) {
3787
3823
  const conn = serviceTransport.connectionInfo(upstream.serviceId);
@@ -3817,20 +3853,6 @@ async function createServer(config, cache, logger, jwtConfig, registry, serviceT
3817
3853
  gatewayLogger.info(`Upstream registered: ${name} \u2192 ${connDesc} (${upstream.prefix}${wsDesc})`);
3818
3854
  }
3819
3855
  await app.register(async function gatewayRoutes(scope) {
3820
- if (userAuth) {
3821
- scope.addHook(
3822
- "onRequest",
3823
- createUserAuthMiddleware({
3824
- users: userAuth.users,
3825
- tenantResolver: userAuth.tenantResolver,
3826
- jwtConfig
3827
- })
3828
- );
3829
- }
3830
- scope.addHook(
3831
- "onRequest",
3832
- createAuthMiddleware(cache, jwtConfig, { authEnabled: config.auth?.enabled !== false })
3833
- );
3834
3856
  if (config.pressure?.perTenant?.enabled === true && platform.hasResourceBroker) {
3835
3857
  scope.addHook(
3836
3858
  "preHandler",
@@ -4295,6 +4317,19 @@ async function bootstrap(repoRoot = process.cwd()) {
4295
4317
  logger.warn("GATEWAY_JWT_SECRET not set \u2014 using insecure default (dev only, never use in production!)");
4296
4318
  }
4297
4319
  const jwtConfig = { secret: jwtSecret ?? DEV_JWT_SECRET };
4320
+ if (config.auth?.bootstrap?.provisionCliCredentials === true) {
4321
+ const bootstrapAuthService = new AuthService(cache, jwtConfig);
4322
+ await ensureBootstrapCliCredentials({
4323
+ enabled: true,
4324
+ authService: bootstrapAuthService,
4325
+ gatewayUrl: `http://127.0.0.1:${config.port}`,
4326
+ logger
4327
+ }).catch((err) => {
4328
+ logger.warn("Bootstrap CLI credentials provisioning failed (non-fatal)", {
4329
+ error: err instanceof Error ? err.message : String(err)
4330
+ });
4331
+ });
4332
+ }
4298
4333
  if (platform.hasResourceBroker) {
4299
4334
  registerPressureLimits(platform.resourceBroker, config.pressure, platform.logger);
4300
4335
  } else {