@jeffjassky/oauth-host 0.1.0 → 0.2.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
@@ -493,6 +493,7 @@ function resolveConfig(config) {
493
493
  }
494
494
  const store = rateLimits.store ?? memoryStore();
495
495
  const normalizedMount = `/${String(mountPath).replace(/^\/+|\/+$/g, "")}`;
496
+ const indexes = { ready: false };
496
497
  const ctx = {
497
498
  models,
498
499
  issuer,
@@ -524,6 +525,11 @@ function resolveConfig(config) {
524
525
  cors: { tokenEndpoint: cors.tokenEndpoint ?? false, origins: cors.origins ?? [] },
525
526
  clockSkewMs,
526
527
  cimd: resolveCimd(clientIdMetadata, scopeIndex),
528
+ indexes,
529
+ async syncIndexes() {
530
+ await syncModelIndexes(models);
531
+ indexes.ready = true;
532
+ },
527
533
  logger,
528
534
  track,
529
535
  async audit(entry) {
@@ -2473,8 +2479,17 @@ function createOAuthRouter(ctx) {
2473
2479
  const ipKey = (req) => req.ip ?? "unknown";
2474
2480
  const clientKey = (req) => clientIdFromRequest(req) ?? ipKey(req);
2475
2481
  const cors = corsMiddleware(ctx);
2482
+ const requireIndexes = w((_req, _res, next) => {
2483
+ if (ctx.indexes.ready) return next();
2484
+ throw new OAuthError(
2485
+ 503,
2486
+ "server_error",
2487
+ "This authorization server is not ready: `syncIndexes()` has not resolved yet. Await `oauth.syncIndexes()` at boot, before mounting the routers."
2488
+ );
2489
+ });
2476
2490
  router.get(
2477
2491
  "/authorize",
2492
+ requireIndexes,
2478
2493
  rateLimit(ctx, "authorize", ipKey),
2479
2494
  w(async (req, res) => {
2480
2495
  let validated;
@@ -2533,6 +2548,7 @@ function createOAuthRouter(ctx) {
2533
2548
  router.post(
2534
2549
  "/token",
2535
2550
  cors,
2551
+ requireIndexes,
2536
2552
  form,
2537
2553
  rateLimit(ctx, "token", clientKey),
2538
2554
  w(async (req, res) => {
@@ -2637,6 +2653,7 @@ function createOAuthRouter(ctx) {
2637
2653
  );
2638
2654
  router.post(
2639
2655
  "/consent/:requestId",
2656
+ requireIndexes,
2640
2657
  rateLimit(ctx, "consent", ipKey),
2641
2658
  w(async (req, res) => {
2642
2659
  const user = await requireUser(ctx, req);
@@ -2738,6 +2755,16 @@ function corsMiddleware(ctx) {
2738
2755
  };
2739
2756
  }
2740
2757
 
2758
+ // src/server/vendors.ts
2759
+ var CLAUDE_CONNECTOR_REDIRECT_URI = "https://claude.ai/api/mcp/auth_callback";
2760
+ var CLAUDE_CODE_REDIRECT_URIS = [
2761
+ "http://localhost/callback",
2762
+ "http://127.0.0.1/callback"
2763
+ ];
2764
+ var CHATGPT_LEGACY_REDIRECT_URI = "https://chatgpt.com/connector_platform_oauth_redirect";
2765
+ var CHATGPT_CONNECTOR_REDIRECT_URI_PATTERN = "https://chatgpt.com/connector/oauth/{callback_id}";
2766
+ var CIMD_ALLOWED_HOSTS = ["claude.ai", "chatgpt.com"];
2767
+
2741
2768
  // src/server/index.ts
2742
2769
  function createOAuthHost(config) {
2743
2770
  const ctx = resolveConfig(config);
@@ -2761,13 +2788,30 @@ function createOAuthHost(config) {
2761
2788
  * stops one user holding two live grants for the same client, and mongoose
2762
2789
  * builds indexes in the background — a cold database will happily serve
2763
2790
  * the write that violates it first. See standards/traps.md #3.
2791
+ *
2792
+ * Resolving this is also what flips `ready` and un-gates `/authorize`,
2793
+ * `POST /consent/:requestId` and `POST /token`.
2764
2794
  */
2765
- syncIndexes: () => syncModelIndexes(ctx.models),
2795
+ syncIndexes: () => ctx.syncIndexes(),
2796
+ /**
2797
+ * Has `syncIndexes()` resolved?
2798
+ *
2799
+ * A boolean, not a promise, and the difference is the failure mode. A
2800
+ * promise would have to exist from construction, so a host that never calls
2801
+ * `syncIndexes()` would await it forever — a boot-order mistake turning into
2802
+ * an unexplained hang with no message. A boolean is plainly `false`, cannot
2803
+ * be awaited by accident, and is backed by three routes that say what is
2804
+ * wrong by name. Gate a mount on it, or simply
2805
+ * `await oauth.syncIndexes()` first, which is the same thing said directly.
2806
+ */
2807
+ get ready() {
2808
+ return ctx.indexes.ready;
2809
+ },
2766
2810
  /** Escape hatch. Prefer the APIs above; these carry no invariants. */
2767
2811
  models: ctx.models
2768
2812
  };
2769
2813
  }
2770
2814
 
2771
- export { OAuthError, RedirectableAuthError, UnredirectableError, createModels, createOAuthHost, createUserAdapter, defaultResolveUser, syncModelIndexes };
2815
+ export { CHATGPT_CONNECTOR_REDIRECT_URI_PATTERN, CHATGPT_LEGACY_REDIRECT_URI, CIMD_ALLOWED_HOSTS, CLAUDE_CODE_REDIRECT_URIS, CLAUDE_CONNECTOR_REDIRECT_URI, OAuthError, RedirectableAuthError, UnredirectableError, createModels, createOAuthHost, createUserAdapter, defaultResolveUser, syncModelIndexes };
2772
2816
  //# sourceMappingURL=index.js.map
2773
2817
  //# sourceMappingURL=index.js.map