All files / src/oauth token-context.ts

100% Statements 28/28
100% Branches 2/2
100% Functions 9/9
100% Lines 28/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                    82x                 82x                                             82x       20x                     82x 9x                       82x 2x 2x 1x       1x               82x 2x 2x               82x 2x 2x               82x 7x 7x               82x 7x 7x               82x 3x 3x               82x 5x    
/**
 * Token Context for OAuth
 *
 * Uses AsyncLocalStorage to provide per-request access to the authenticated
 * user's GitLab token without passing it through function parameters.
 *
 * This pattern allows existing code (like enhancedFetch) to automatically
 * use the correct token for the current request context.
 */
 
import { AsyncLocalStorage } from "async_hooks";
import { TokenContext } from "./types";
 
/**
 * AsyncLocalStorage instance for token context
 *
 * Stores the current request's token context, making it accessible
 * from any code running within the request without explicit passing.
 */
const asyncLocalStorage = new AsyncLocalStorage<TokenContext>();
 
/**
 * Run a function with a specific token context
 *
 * All code executed within the callback (including async operations)
 * will have access to the provided token context via getTokenContext().
 *
 * @param context - Token context for this request
 * @param fn - Function to execute with the context
 * @returns The return value of the function
 *
 * @example
 * ```typescript
 * await runWithTokenContext(
 *   { gitlabToken: 'xxx', gitlabUserId: 123, gitlabUsername: 'user', sessionId: 'abc' },
 *   async () => {
 *     // All code here can call getTokenContext() or getGitLabTokenFromContext()
 *     const projects = await listProjects();
 *   }
 * );
 * ```
 */
export function runWithTokenContext<T>(
  context: TokenContext,
  fn: () => T | Promise<T>
): T | Promise<T> {
  return asyncLocalStorage.run(context, fn);
}
 
/**
 * Get the current token context
 *
 * Returns undefined if called outside of a runWithTokenContext() callback.
 * Use this when you need to optionally use the token context.
 *
 * @returns The current token context, or undefined if not in OAuth mode
 */
export function getTokenContext(): TokenContext | undefined {
  return asyncLocalStorage.getStore();
}
 
/**
 * Get the GitLab token from the current context
 *
 * Throws an error if called outside of a runWithTokenContext() callback.
 * Use this in OAuth mode when a token is required.
 *
 * @returns The GitLab access token for the current request
 * @throws Error if no token context is available
 */
export function getGitLabTokenFromContext(): string {
  const context = asyncLocalStorage.getStore();
  if (!context) {
    throw new Error(
      "No OAuth token context available - this code must be called within an authenticated request"
    );
  }
  return context.gitlabToken;
}
 
/**
 * Get the GitLab user ID from the current context
 *
 * @returns The GitLab user ID, or undefined if not in OAuth context
 */
export function getGitLabUserIdFromContext(): number | undefined {
  const context = asyncLocalStorage.getStore();
  return context?.gitlabUserId;
}
 
/**
 * Get the GitLab username from the current context
 *
 * @returns The GitLab username, or undefined if not in OAuth context
 */
export function getGitLabUsernameFromContext(): string | undefined {
  const context = asyncLocalStorage.getStore();
  return context?.gitlabUsername;
}
 
/**
 * Get the session ID from the current context
 *
 * @returns The session ID, or undefined if not in OAuth context
 */
export function getSessionIdFromContext(): string | undefined {
  const context = asyncLocalStorage.getStore();
  return context?.sessionId;
}
 
/**
 * Get the GitLab API URL from the current context
 *
 * @returns The GitLab API URL, or undefined if not in OAuth context
 */
export function getGitLabApiUrlFromContext(): string | undefined {
  const context = asyncLocalStorage.getStore();
  return context?.apiUrl;
}
 
/**
 * Get the GitLab instance label from the current context
 *
 * @returns The instance label, or undefined if not in OAuth context or not set
 */
export function getInstanceLabelFromContext(): string | undefined {
  const context = asyncLocalStorage.getStore();
  return context?.instanceLabel;
}
 
/**
 * Check if we're currently in an OAuth context
 *
 * @returns true if a token context is available
 */
export function isInOAuthContext(): boolean {
  return asyncLocalStorage.getStore() !== undefined;
}