### Environment Variables Setup (Bash) Source: https://context7.com/hackclub/ai/llms.txt Provides an example of setting up environment variables for service configuration. These variables control database connections, authentication providers, model access, and deployment. All variables are validated at startup using arktype schemas. ```bash # Example placeholder for environment variable setup # Actual variables would be defined here based on specific needs. # export DATABASE_URL="postgresql://user:password@host:port/database" # export ALLOWED_LANGUAGE_MODELS="openai/gpt-5-mini,qwen/qwen3-32b" # export ALLOWED_EMBEDDING_MODELS="openai/text-embedding-3-large" # export ENFORCE_IDV="true" ``` -------------------------------- ### GET /proxy/v1/models Source: https://context7.com/hackclub/ai/llms.txt Lists available AI models from the upstream provider. Models are filtered based on environment variables and cached for 5 minutes. ```APIDOC ## GET /proxy/v1/models ### Description Returns a filtered list of available AI models from the upstream provider. Models are cached for 5 minutes to reduce latency. Only models specified in `ALLOWED_LANGUAGE_MODELS` and `ALLOWED_EMBEDDING_MODELS` environment variables are returned. ### Method GET ### Endpoint /proxy/v1/models ### Parameters No path or query parameters. ### Request Example ```bash curl -X GET https://ai.hackclub.com/proxy/v1/models ``` ### Response #### Success Response (200) - **object** (string) - Type of the response, typically "list". - **data** (array) - An array of model objects. - **id** (string) - The unique identifier of the model. - **object** (string) - Type of the object, typically "model". - **created** (integer) - Timestamp of model creation. - **owned_by** (string) - The owner of the model (e.g., "openai", "qwen"). #### Response Example ```json { "object": "list", "data": [ { "id": "openai/gpt-5-mini", "object": "model", "created": 1704067200, "owned_by": "openai" }, { "id": "qwen/qwen3-32b", "object": "model", "created": 1704067200, "owned_by": "qwen" }, { "id": "openai/text-embedding-3-large", "object": "model", "created": 1704067200, "owned_by": "openai" } ] } ``` ``` -------------------------------- ### Get User Statistics - cURL Source: https://context7.com/hackclub/ai/llms.txt Retrieves comprehensive usage statistics for authenticated user including total requests, token usage breakdown, and recent request logs. Returns aggregated metrics and 50 most recent API calls with model, duration, and IP information. ```bash # Get usage stats curl -X GET https://ai.hackclub.com/api/stats \ -b "session_token=" # Response: { "stats": { "totalRequests": 1234, "totalTokens": 567890, "totalPromptTokens": 234567, "totalCompletionTokens": 333323 }, "recentLogs": [ { "id": "770e8400-e29b-41d4-a716-446655440002", "model": "openai/gpt-5-mini", "totalTokens": 450, "timestamp": "2025-01-15T14:30:00.000Z", "duration": 1250, "ip": "192.0.2.1" }, { "id": "880e8400-e29b-41d4-a716-446655440003", "model": "qwen/qwen3-32b", "totalTokens": 890, "timestamp": "2025-01-15T14:25:00.000Z", "duration": 2100, "ip": "192.0.2.1" } ] } ``` -------------------------------- ### Database Migration Commands Source: https://context7.com/hackclub/ai/llms.txt Provides essential commands for managing database schema migrations using Bun. Includes instructions for generating new migration files based on schema changes and applying these migrations to the database. ```bash # Generate migrations: bun run db:generate # Apply migrations: bun run db:migrate # View database in Drizzle Studio: bun run db:studio ``` -------------------------------- ### Docker Compose Configuration for AI Project Production Deployment Source: https://context7.com/hackclub/ai/llms.txt Sets up a production environment for the AI project using Docker Compose. It defines services for the application and a PostgreSQL database, including port mappings, environment variable injection, database health checks, data persistence, and restart policies. This configuration ensures a robust and scalable deployment. ```yaml # docker-compose.yml version: '3.8' services: app: build: . ports: - "51735:51735" environment: DATABASE_URL: postgresql://postgres:postgres@db:5432/ai_proxy PORT: 51735 SLACK_CLIENT_ID: ${SLACK_CLIENT_ID} SLACK_CLIENT_SECRET: ${SLACK_CLIENT_SECRET} SLACK_TEAM_ID: T0266FRGM OPENAI_API_URL: ${OPENAI_API_URL:-https://openrouter.ai/api} OPENAI_API_KEY: ${OPENAI_API_KEY} NODE_ENV: production ALLOWED_LANGUAGE_MODELS: ${ALLOWED_LANGUAGE_MODELS} ALLOWED_EMBEDDING_MODELS: ${ALLOWED_EMBEDDING_MODELS} ENFORCE_IDV: ${ENFORCE_IDV:-true} depends_on: db: condition: service_healthy restart: unless-stopped db: image: postgres:18-alpine environment: POSTGRES_DB: ai_proxy POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 restart: unless-stopped volumes: postgres_data: # Deploy: # docker-compose up -d # View logs: # docker-compose logs -f app # Run migrations: # docker-compose exec app bun run db:migrate ``` -------------------------------- ### Environment Variables for AI Project Configuration Source: https://context7.com/hackclub/ai/llms.txt Defines essential environment variables for the AI project, including database connection details, Slack OAuth credentials, API keys for services like OpenRouter or OpenAI, and lists of allowed language and embedding models. These variables are crucial for setting up the application's environment. ```env # .env configuration DATABASE_URL=postgresql://user:password@localhost:5432/ai_proxy BASE_URL=https://ai.hackclub.com PORT=54321 NODE_ENV=production # Slack OAuth credentials from https://api.slack.com/apps SLACK_CLIENT_ID=1234567890.1234567890123 SLACK_CLIENT_SECRET=abcdef1234567890abcdef1234567890 SLACK_TEAM_ID=T0266FRGM # OpenRouter or OpenAI API configuration OPENAI_API_URL=https://openrouter.ai/api OPENAI_API_KEY=sk-or-v1-abc123... # Comma-separated model lists ALLOWED_LANGUAGE_MODELS=qwen/qwen3-32b,openai/gpt-5-mini,google/gemini-2.5-flash,deepseek/deepseek-v3.2-exp ALLOWED_EMBEDDING_MODELS=openai/text-embedding-3-large,qwen/qwen3-embedding-8b,mistralai/codestral-embed-2505 # Optional identity verification enforcement ENFORCE_IDV=true ``` -------------------------------- ### Environment Variables for Hack Club AI Proxy Configuration Source: https://github.com/hackclub/ai/blob/main/README.md This snippet details the necessary environment variables for configuring the Hack Club AI proxy. It covers settings for allowed models, API keys, Slack integration, user verification, database connection, base URL, and runtime environment. Ensure sensitive keys are not committed to version control. ```shell # what model? ALLOWED_EMBEDDING_MODELS=qwen/qwen3-embedding-8b,mistralai/codestral-embed-2505,openai/text-embedding-3-large ALLOWED_LANGUAGE_MODELS=qwen/qwen3-32b,moonshotai/kimi-k2-thinking,openai/gpt-oss-120b,moonshotai/kimi-k2-0905,qwen/qwen3-vl-235b-a22b-instruct, nvidia/nemotron-nano-12b-v2-vl,google/gemini-2.5-flash,openai/gpt-5-mini,deepseek/deepseek-v3.2-exp,deepseek/deepseek-r1-0528,z-ai/glm-4.6,google/gemini-2.5-flash-image # you should not commit these - although i hope you know that already! OPENAI_API_KEY= OPENAI_API_URL=https://openrouter.ai/api # get these from https://api.slack.com/apps SLACK_CLIENT_ID= SLACK_CLIENT_SECRET= SLACK_TEAM_ID=T0266FRGM # check that users are ID verified? ENFORCE_IDV=true # postgres 18 database # not needed for docker compose DATABASE_URL= BASE_URL=https://ai.hackclub.com NODE_ENV=production # not needed for docker compose PORT=54321 # not needed for docker compose ``` -------------------------------- ### Create API Key - cURL Source: https://context7.com/hackclub/ai/llms.txt Creates a new API key for authenticated users with a 50 key limit per user. Keys are prefixed with `sk-hc-v1-` and generated from two concatenated UUIDs without hyphens. Returns the full key, name, and unique identifier upon successful creation. ```bash # Create new API key curl -X POST https://ai.hackclub.com/api/keys \ -H "Content-Type: application/json" \ -b "session_token=" \ -d '{ "name": "My Development Key" }' # Response: { "key": "sk-hc-v1-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "name": "My Development Key", "id": "550e8400-e29b-41d4-a716-446655440000" } # If user has 50 keys: # 400 { "message": "Maximum API key limit reached" } ``` -------------------------------- ### Authentication Endpoints Source: https://context7.com/hackclub/ai/llms.txt Endpoints for initiating the Slack OAuth authentication flow and logging out. ```APIDOC ## Slack OAuth Login Flow ### Description Initiates the Slack OAuth authentication flow for Hack Club workspace members. Users are redirected to Slack's authorization page to grant necessary permissions. After successful authorization, the callback endpoint exchanges the authorization code for user information and establishes a session. ### Method GET ### Endpoint /auth/login ### Parameters None ### Request Example ```bash curl -L https://ai.hackclub.com/auth/login ``` ### Response Redirects to Slack OAuth authorization URL. Upon successful callback, sets `session_token` cookie and redirects to `/dashboard`. ## Session Logout ### Description Revokes the current user's session, clears authentication cookies, and removes the session data from the database. ### Method GET ### Endpoint /auth/logout ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET https://ai.hackclub.com/auth/logout \ -b "session_token=" ``` ### Response 302 Redirect to `/`. The `session_token` cookie is cleared with `maxAge=0`. ``` -------------------------------- ### List Available AI Models (Bash) Source: https://context7.com/hackclub/ai/llms.txt Retrieves a filtered list of available AI models from the upstream provider. Models are cached for 5 minutes and are restricted by ALLOWED_LANGUAGE_MODELS and ALLOWED_EMBEDDING_MODELS environment variables. No authentication is required for this endpoint. ```bash # Get available models (no authentication required) curl -X GET https://ai.hackclub.com/proxy/v1/models # Response (filtered by allowed models): { "object": "list", "data": [ { "id": "openai/gpt-5-mini", "object": "model", "created": 1704067200, "owned_by": "openai" }, { "id": "qwen/qwen3-32b", "object": "model", "created": 1704067200, "owned_by": "qwen" }, { "id": "openai/text-embedding-3-large", "object": "model", "created": 1704067200, "owned_by": "openai" } ] } ``` -------------------------------- ### API Key Management API Source: https://context7.com/hackclub/ai/llms.txt Endpoints for creating, listing, and deleting API keys for authenticated users. ```APIDOC ## Create API Key ### Description Creates a new API key for the authenticated user. Each user is limited to a maximum of 50 active API keys. Keys are generated with a specific prefix and format. ### Method POST ### Endpoint /api/keys ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **name** (string) - Required - A descriptive name for the API key. ### Request Example ```bash curl -X POST https://ai.hackclub.com/api/keys \ -H "Content-Type: application/json" \ -b "session_token=" \ -d '{ "name": "My Development Key" }' ``` ### Response #### Success Response (200) - **key** (string) - The newly generated API key. - **name** (string) - The name provided for the API key. - **id** (string) - The unique identifier for the API key. #### Response Example ```json { "key": "sk-hc-v1-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "name": "My Development Key", "id": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Error Response (400) - **message** (string) - "Maximum API key limit reached" if the user has reached their key limit. ## List API Keys ### Description Retrieves all API keys associated with the authenticated user, including those that have been revoked. The response includes a preview of each key, its creation timestamp, and revocation status. ### Method GET ### Endpoint /api/keys ### Parameters None ### Request Example ```bash curl -X GET https://ai.hackclub.com/api/keys \ -b "session_token=" ``` ### Response #### Success Response (200) - **Array of API Key Objects** - **id** (string) - The unique identifier for the API key. - **name** (string) - The name of the API key. - **createdAt** (string) - The timestamp when the API key was created. - **revokedAt** (string | null) - The timestamp when the API key was revoked, or null if not revoked. - **keyPreview** (string) - A preview of the API key (first 10 characters). #### Response Example ```json [ { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "My Development Key", "createdAt": "2025-01-15T10:30:00.000Z", "revokedAt": null, "keyPreview": "sk-hc-v1-a..." }, { "id": "660e8400-e29b-41d4-a716-446655440001", "name": "Production Key", "createdAt": "2025-01-14T09:00:00.000Z", "revokedAt": "2025-01-15T12:00:00.000Z", "keyPreview": "sk-hc-v1-b..." } ] ``` ## Delete API Key ### Description Revokes an existing API key, making it unusable for future requests. The key's revocation timestamp is updated, but the key remains in the database for auditing purposes. ### Method DELETE ### Endpoint /api/keys/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of the API key to revoke. ### Request Example ```bash curl -X DELETE https://ai.hackclub.com/api/keys/550e8400-e29b-41d4-a716-446655440000 \ -b "session_token=" ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates whether the operation was successful. #### Response Example ```json { "success": true } ``` #### Error Response (404) - **message** (string) - "Operation failed" if the key is not found or does not belong to the user. ``` -------------------------------- ### List API Keys - cURL Source: https://context7.com/hackclub/ai/llms.txt Retrieves all API keys for the authenticated user including revoked keys. Returns key preview showing first 10 characters, creation timestamp, revocation status, and unique identifier for each key. ```bash # Get all user API keys curl -X GET https://ai.hackclub.com/api/keys \ -b "session_token=" # Response: [ { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "My Development Key", "createdAt": "2025-01-15T10:30:00.000Z", "revokedAt": null, "keyPreview": "sk-hc-v1-a..." }, { "id": "660e8400-e29b-41d4-a716-446655440001", "name": "Production Key", "createdAt": "2025-01-14T09:00:00.000Z", "revokedAt": "2025-01-15T12:00:00.000Z", "keyPreview": "sk-hc-v1-b..." } ] ``` -------------------------------- ### Chat Completions (Bash) Source: https://context7.com/hackclub/ai/llms.txt Proxies chat completion requests to an OpenAI-compatible API. It validates model selection, enforces identity verification if enabled, and logs requests. Supports both streaming and non-streaming responses. Authentication is required using a Bearer token. ```bash # Non-streaming chat completion curl -X POST https://ai.hackclub.com/proxy/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "openai/gpt-5-mini", \ "messages": [ \ { \ "role": "system", \ "content": "You are a helpful assistant." }, \ { \ "role": "user", \ "content": "What is the capital of France?" } ], "temperature": 0.7, "max_tokens": 150 }' # Response: { "id": "chatcmpl-abc123", "object": "chat.completion", "created": 1704067200, "model": "openai/gpt-5-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The capital of France is Paris." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 25, "completion_tokens": 8, "total_tokens": 33 } } # Streaming chat completion curl -X POST https://ai.hackclub.com/proxy/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "qwen/qwen3-32b", \ "messages": [ \ { "role": "user", \ "content": "Write a haiku about coding" } ], "stream": true }' # Response (Server-Sent Events): data: {"id":"chatcmpl-xyz789","object":"chat.completion.chunk","created":1704067200,"model":"qwen/qwen3-32b","choices":[{"index":0,"delta":{"role":"assistant","content":"Code"},"finish_reason":null}]} data: {"id":"chatcmpl-xyz789","object":"chat.completion.chunk","created":1704067200,"model":"qwen/qwen3-32b","choices":[{"index":0,"delta":{"content":" flows"},"finish_reason":null}]} data: {"id":"chatcmpl-xyz789","object":"chat.completion.chunk","created":1704067200,"model":"qwen/qwen3-32b","choices":[{"index":0,"delta":{"content":" like"},"finish_reason":null}]} data: [DONE] # Invalid model automatically replaced with default: # Request with "invalid-model" -> Uses first allowed model # Identity verification error (if ENFORCE_IDV=true): # 403 { "message": "Identity verification required. Please verify at https://identity.hackclub.com" } ``` -------------------------------- ### POST /proxy/v1/chat/completions Source: https://context7.com/hackclub/ai/llms.txt Proxies chat completion requests to the upstream OpenAI-compatible API. Supports both streaming and non-streaming responses. ```APIDOC ## POST /proxy/v1/chat/completions ### Description Proxies chat completion requests to the upstream OpenAI-compatible API. Validates model selection, enforces identity verification if enabled, and logs all requests with token usage. Supports both streaming and non-streaming responses. ### Method POST ### Endpoint /proxy/v1/chat/completions ### Parameters #### Headers - **Content-Type** (string) - Required - `application/json` - **Authorization** (string) - Required - Bearer token (e.g., `Bearer sk-hc-v1-a1b2c3d4...`) #### Request Body - **model** (string) - Required - The ID of the model to use for chat completions (e.g., `openai/gpt-5-mini`). If an invalid model is provided, it will be automatically replaced with the first allowed model. - **messages** (array) - Required - A list of message objects representing the conversation history. - **role** (string) - Required - The role of the message sender (`system`, `user`, or `assistant`). - **content** (string) - Required - The content of the message. - **temperature** (number) - Optional - Controls randomness. Lower values make the output more deterministic. - **max_tokens** (integer) - Optional - The maximum number of tokens to generate in the completion. - **stream** (boolean) - Optional - If `true`, the response will be streamed using Server-Sent Events. ### Request Example (Non-streaming) ```bash curl -X POST https://ai.hackclub.com/proxy/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "openai/gpt-5-mini", \ "messages": [ \ { \ "role": "system", \ "content": "You are a helpful assistant." }, \ { \ "role": "user", \ "content": "What is the capital of France?" } ], "temperature": 0.7, "max_tokens": 150 }' ``` ### Response (Non-streaming) #### Success Response (200) - **id** (string) - Unique identifier for the chat completion. - **object** (string) - Type of the object, "chat.completion". - **created** (integer) - Timestamp of creation. - **model** (string) - The model used for the completion. - **choices** (array) - A list of completion choices. - **index** (integer) - Index of the choice. - **message** (object) - The message from the assistant. - **role** (string) - Role of the message sender, "assistant". - **content** (string) - The generated content. - **finish_reason** (string) - The reason the model stopped generating tokens (e.g., "stop", "length"). - **usage** (object) - Token usage statistics. - **prompt_tokens** (integer) - Number of tokens in the prompt. - **completion_tokens** (integer) - Number of tokens in the completion. - **total_tokens** (integer) - Total tokens used. #### Response Example (Non-streaming) ```json { "id": "chatcmpl-abc123", "object": "chat.completion", "created": 1704067200, "model": "openai/gpt-5-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The capital of France is Paris." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 25, "completion_tokens": 8, "total_tokens": 33 } } ``` ### Request Example (Streaming) ```bash curl -X POST https://ai.hackclub.com/proxy/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "qwen/qwen3-32b", \ "messages": [ \ { \ "role": "user", \ "content": "Write a haiku about coding" } ], "stream": true }' ``` ### Response (Streaming) Responses are streamed as Server-Sent Events (SSE). Example SSE chunks: ``` data: {"id":"chatcmpl-xyz789","object":"chat.completion.chunk","created":1704067200,"model":"qwen/qwen3-32b","choices":[{"index":0,"delta":{"role":"assistant","content":"Code"},"finish_reason":null}]} data: {"id":"chatcmpl-xyz789","object":"chat.completion.chunk","created":1704067200,"model":"qwen/qwen3-32b","choices":[{"index":0,"delta":{"content":" flows"},"finish_reason":null}]} data: {"id":"chatcmpl-xyz789","object":"chat.completion.chunk","created":1704067200,"model":"qwen/qwen3-32b","choices":[{"index":0,"delta":{"content":" like"},"finish_reason":null}]} data: [DONE] ``` ### Error Handling - **Invalid model**: Automatically replaced with the first allowed model. - **Identity verification error** (if `ENFORCE_IDV=true`): - Status: `403 Forbidden` - Body: `{ "message": "Identity verification required. Please verify at https://identity.hackclub.com" }` ``` -------------------------------- ### Application Blocking Middleware for AI Coding Agents Source: https://context7.com/hackclub/ai/llms.txt Blocks requests from unauthorized AI coding applications by checking Referer and X-Title headers against a blocklist including Cursor, Windsurf, SillyTavern, Continue, and Cline. Performs case-insensitive substring matching and returns 403 HTTP exception with guidance to join Slack channel for updates. ```typescript async function blockAICodingAgents(c, next) { const referer = c.req.header("Referer") || c.req.header("HTTP-Referer"); const xTitle = c.req.header("X-Title"); const blockedApps = ["cursor", "windsurf", "sillytavern", "continue", "cline"]; const refererLower = (referer || "").toLowerCase(); const xTitleLower = (xTitle || "").toLowerCase(); for (const app of blockedApps) { if (refererLower.includes(app) || xTitleLower.includes(app)) { throw new HTTPException(403, { message: "AI coding agents aren't allowed. Join #hackclub-ai on Slack for updates." }); } } await next(); } ``` -------------------------------- ### API Key Authentication with Identity Verification Enforcement Source: https://context7.com/hackclub/ai/llms.txt Authenticates requests using Bearer tokens from Authorization headers and validates API key status. Enforces identity verification (IDV) when ENFORCE_IDV environment variable is enabled, unless the user has skipIdv flag set. Throws 401 HTTP exceptions for missing/invalid keys and 403 for unverified identities. ```typescript async function requireApiKey(c, next) { const authHeader = c.req.header("Authorization"); if (!authHeader || !authHeader.startsWith("Bearer ")) { throw new HTTPException(401, { message: "Authentication required" }); } const key = authHeader.substring(7); const [apiKey] = await db .select({ apiKey: apiKeys, user: users }) .from(apiKeys) .innerJoin(users, eq(apiKeys.userId, users.id)) .where(and(eq(apiKeys.key, key), isNull(apiKeys.revokedAt))) .limit(1); if (!apiKey) { throw new HTTPException(401, { message: "Authentication failed" }); } c.set("apiKey", apiKey.apiKey); c.set("user", apiKey.user); // Enforce identity verification if (env.ENFORCE_IDV && !apiKey.user.skipIdv && !apiKey.user.isIdvVerified) { throw new HTTPException(403, { message: "Identity verification required. Please verify at https://identity.hackclub.com" }); } await next(); } ``` -------------------------------- ### Define Database Schema with Drizzle ORM Source: https://context7.com/hackclub/ai/llms.txt Defines PostgreSQL tables for users, API keys, and request logs using Drizzle ORM in TypeScript. Includes table structures, column types, primary keys, foreign key constraints with cascade deletion, and various indexes for optimized query performance. Supports Slack integration and IDV verification for users. ```typescript import { pgTable, text, timestamp, integer, uuid, index, jsonb, boolean } from "drizzle-orm/pg-core"; // Users table with Slack integration and IDV tracking const users = pgTable("users", { id: uuid("id").primaryKey().defaultRandom(), slackId: text("slack_id").notNull().unique(), slackTeamId: text("slack_team_id").notNull(), email: text("email"), name: text("name"), avatar: text("avatar"), isIdvVerified: boolean("is_idv_verified").notNull().default(false), skipIdv: boolean("skip_idv").notNull().default(false), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull() }, (table) => [ index("users_slack_id_idx").on(table.slackId), index("users_email_idx").on(table.email), index("users_idv_verified_idx").on(table.isIdvVerified) ]); // API keys with cascade deletion const apiKeys = pgTable("api_keys", { id: uuid("id").primaryKey().defaultRandom(), userId: uuid("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), key: text("key").notNull().unique(), name: text("name").notNull(), createdAt: timestamp("created_at").defaultNow().notNull(), revokedAt: timestamp("revoked_at") }, (table) => [ index("api_keys_user_id_idx").on(table.userId), index("api_keys_key_revoked_idx").on(table.key, table.revokedAt) ]); // Request logs for analytics const requestLogs = pgTable("request_logs", { id: uuid("id").primaryKey().defaultRandom(), apiKeyId: uuid("api_key_id").notNull().references(() => apiKeys.id, { onDelete: "cascade" }), userId: uuid("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), slackId: text("slack_id").notNull(), model: text("model").notNull(), promptTokens: integer("prompt_tokens").notNull().default(0), completionTokens: integer("completion_tokens").notNull().default(0), totalTokens: integer("total_tokens").notNull().default(0), request: jsonb("request").notNull(), response: jsonb("response").notNull(), ip: text("ip").notNull(), timestamp: timestamp("timestamp").defaultNow().notNull(), duration: integer("duration").notNull() }, (table) => [ index("request_logs_user_timestamp_idx").on(table.userId, table.timestamp.desc()), index("request_logs_apikey_timestamp_idx").on(table.apiKeyId, table.timestamp.desc()), index("request_logs_slack_timestamp_idx").on(table.slackId, table.timestamp.desc()), index("request_logs_model_idx").on(table.model) ]); ``` -------------------------------- ### POST /proxy/v1/embeddings Source: https://context7.com/hackclub/ai/llms.txt Generates vector embeddings for text input using specified embedding models. ```APIDOC ## POST /proxy/v1/embeddings ### Description Generates vector embeddings for text input. Validates embedding model selection and logs usage. Automatically substitutes invalid models with the first allowed embedding model. ### Method POST ### Endpoint /proxy/v1/embeddings ### Parameters #### Headers - **Content-Type** (string) - Required - `application/json` - **Authorization** (string) - Required - Bearer token (e.g., `Bearer sk-hc-v1-a1b2c3d4...`) #### Request Body - **model** (string) - Required - The ID of the embedding model to use (e.g., `openai/text-embedding-3-large`). If an invalid model is provided, it will be automatically replaced with the first allowed embedding model. - **input** (string | array) - Required - The input text or an array of texts to generate embeddings for. ### Request Example (Single Input) ```bash curl -X POST https://ai.hackclub.com/proxy/v1/embeddings \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "openai/text-embedding-3-large", \ "input": "The quick brown fox jumps over the lazy dog" }' ``` ### Response (Single Input) #### Success Response (200) - **object** (string) - Type of the response, "list". - **data** (array) - An array of embedding objects. - **object** (string) - Type of the object, "embedding". - **embedding** (array) - The generated vector embedding. - **index** (integer) - The index of the input text this embedding corresponds to. - **model** (string) - The model used for generating embeddings. - **usage** (object) - Token usage statistics. - **prompt_tokens** (integer) - Number of tokens in the prompt. - **total_tokens** (integer) - Total tokens used. #### Response Example (Single Input) ```json { "object": "list", "data": [ { "object": "embedding", "embedding": [ 0.0023064255, -0.009327292, -0.0028842222, ... 0.012345678 ], "index": 0 } ], "model": "openai/text-embedding-3-large", "usage": { "prompt_tokens": 9, "total_tokens": 9 } } ``` ### Request Example (Batch Input) ```bash curl -X POST https://ai.hackclub.com/proxy/v1/embeddings \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "qwen/qwen3-embedding-8b", \ "input": [ "First document to embed", "Second document to embed", "Third document to embed" ] }' ``` ### Response (Batch Input) #### Success Response (200) Response includes multiple embedding vectors, one for each input text. ### Model Validation Invalid embedding models are automatically replaced with the first allowed embedding model. ``` -------------------------------- ### Usage Statistics API Source: https://context7.com/hackclub/ai/llms.txt Endpoint for retrieving comprehensive usage statistics for the authenticated user. ```APIDOC ## Get User Statistics ### Description Retrieves detailed usage statistics for the authenticated user. This includes aggregated metrics such as total requests and token usage, along with a list of the 50 most recent API calls. ### Method GET ### Endpoint /api/stats ### Parameters None ### Request Example ```bash curl -X GET https://ai.hackclub.com/api/stats \ -b "session_token=" ``` ### Response #### Success Response (200) - **stats** (object) - An object containing aggregated usage statistics. - **totalRequests** (integer) - The total number of API requests made. - **totalTokens** (integer) - The total number of tokens used across all requests. - **totalPromptTokens** (integer) - The total number of prompt tokens used. - **totalCompletionTokens** (integer) - The total number of completion tokens used. - **recentLogs** (array) - An array of the 50 most recent API call logs. - **id** (string) - The unique identifier for the API call. - **model** (string) - The AI model used for the request. - **totalTokens** (integer) - The number of tokens used in this specific request. - **timestamp** (string) - The timestamp when the request was made. - **duration** (integer) - The duration of the API call in milliseconds. - **ip** (string) - The IP address from which the request originated. #### Response Example ```json { "stats": { "totalRequests": 1234, "totalTokens": 567890, "totalPromptTokens": 234567, "totalCompletionTokens": 333323 }, "recentLogs": [ { "id": "770e8400-e29b-41d4-a716-446655440002", "model": "openai/gpt-5-mini", "totalTokens": 450, "timestamp": "2025-01-15T14:30:00.000Z", "duration": 1250, "ip": "192.0.2.1" }, { "id": "880e8400-e29b-41d4-a716-446655440003", "model": "qwen/qwen3-32b", "totalTokens": 890, "timestamp": "2025-01-15T14:25:00.000Z", "duration": 2100, "ip": "192.0.2.1" } ] } ``` ``` -------------------------------- ### Session Authentication Middleware for Dashboard Routes Source: https://context7.com/hackclub/ai/llms.txt Validates session tokens from cookies and retrieves associated user information from the database. Redirects unauthenticated requests to the home page. Requires valid, non-expired session tokens and integrates with Hono framework and Drizzle ORM for database operations. ```typescript import { getCookie } from "hono/cookie"; import { db } from "./db"; import { users, sessions } from "./db/schema"; async function requireAuth(c, next) { const sessionToken = getCookie(c, "session_token"); if (!sessionToken) { return c.redirect("/"); } const [result] = await db .select({ user: users }) .from(sessions) .innerJoin(users, eq(sessions.userId, users.id)) .where(and( eq(sessions.token, sessionToken), gt(sessions.expiresAt, new Date()) )) .limit(1); if (!result) { return c.redirect("/"); } c.set("user", result.user); await next(); } ``` -------------------------------- ### Generate Text Embeddings (Bash) Source: https://context7.com/hackclub/ai/llms.txt Generates vector embeddings for text input using specified models. It validates model selection and logs usage, automatically substituting invalid models with the first allowed embedding model. Authentication is required via a Bearer token. ```bash # Create text embeddings curl -X POST https://ai.hackclub.com/proxy/v1/embeddings \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "openai/text-embedding-3-large", \ "input": "The quick brown fox jumps over the lazy dog" }' # Response: { "object": "list", "data": [ { "object": "embedding", "embedding": [ 0.0023064255, -0.009327292, -0.0028842222, ... 0.012345678 ], "index": 0 } ], "model": "openai/text-embedding-3-large", "usage": { "prompt_tokens": 9, "total_tokens": 9 } } # Batch embeddings curl -X POST https://ai.hackclub.com/proxy/v1/embeddings \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-hc-v1-a1b2c3d4..." \ -d '{ \ "model": "qwen/qwen3-embedding-8b", \ "input": [ \ "First document to embed", \ "Second document to embed", \ "Third document to embed" ] }' # Response includes multiple embedding vectors # Model validation: invalid models replaced with first allowed embedding model ``` -------------------------------- ### Slack OAuth Login Flow - cURL Source: https://context7.com/hackclub/ai/llms.txt Initiates Slack OAuth authentication for Hack Club workspace members. Redirects users to Slack authorization page requesting openid, profile, and email scopes. After authorization, the callback endpoint exchanges the OAuth code for user information and creates a session with httpOnly cookie. ```bash # Redirect user to login endpoint curl -L https://ai.hackclub.com/auth/login # This redirects to Slack OAuth page: # https://hackclub.slack.com/oauth/v2/authorize?client_id=&user_scope=openid,profile,email&redirect_uri=https://ai.hackclub.com/auth/callback # After user authorizes, Slack redirects to callback with code: # GET /auth/callback?code= # Server exchanges code for tokens and creates session # Sets session_token cookie (httpOnly, 30 day expiration) # Redirects to /dashboard ``` -------------------------------- ### Delete API Key - cURL Source: https://context7.com/hackclub/ai/llms.txt Revokes an API key by setting its revokedAt timestamp, making it immediately unusable for API requests. The key remains in database for audit purposes. Returns success response or 404 error if key not found or doesn't belong to user. ```bash # Revoke API key curl -X DELETE https://ai.hackclub.com/api/keys/550e8400-e29b-41d4-a716-446655440000 \ -b "session_token=" # Response: { "success": true } # If key not found or doesn't belong to user: # 404 { "message": "Operation failed" } ``` -------------------------------- ### Session Logout - cURL Source: https://context7.com/hackclub/ai/llms.txt Revokes the user's session and clears authentication cookies by deleting the session from database and removing the session_token cookie with maxAge=0. Returns 302 redirect to home page upon successful logout. ```bash # Logout current user curl -X GET https://ai.hackclub.com/auth/logout \ -b "session_token=" # Response: 302 redirect to / # Cookie cleared with maxAge=0 ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.