UNPKG

studiocms

Version:

Astro Native CMS for AstroDB. Built from the ground up by the Astro community.

143 lines (131 loc) 4.95 kB
import { and, eq } from 'astro:db'; import { Effect, genLogger } from '../../../effect.js'; import { AstroDB, SDKCore_Generators } from '../effect/index.js'; import { tsAPIKeys, tsPermissions } from '../tables.js'; import { _clearLibSQLError } from '../utils.js'; /** * Provides REST API token management functionality for the StudioCMS SDK. * * This service exposes methods for creating, retrieving, deleting, and verifying API tokens * associated with users. It integrates with the database and token generator services. * * @remarks * - Handles database errors gracefully using custom error handlers. * - Uses Drizzle ORM for database operations. * - Token verification also retrieves user rank from permissions table. * * @example * ```typescript * const api = yield* Effect.service(SDKCore_REST_API); * const tokens = yield* api.tokens.get(userId); * ``` * * @dependencies * - AstroDB.Default: Database service for executing queries. * - SDKCore_Generators.Default: Token generation utilities. * * @effect * - All methods return Effect-wrapped results for composability and error handling. * * @module studiocms/sdk/SDKCore/modules/rest_api */ export class SDKCore_REST_API extends Effect.Service<SDKCore_REST_API>()( 'studiocms/sdk/SDKCore/modules/rest_api', { dependencies: [AstroDB.Default, SDKCore_Generators.Default], effect: genLogger('studiocms/sdk/SDKCore/modules/rest_api/effect')(function* () { const [dbService, { generateToken }] = yield* Effect.all([AstroDB, SDKCore_Generators]); const REST_API = { tokens: { /** * Retrieves all API tokens for a specific user. * @param userId - The ID of the user whose tokens are to be retrieved. * @returns An Effect that resolves to an array of API keys for the user. * @throws {LibSQLDatabaseError} If a database error occurs during the operation. */ get: dbService.makeQuery((ex, userId: string) => ex((db) => db.select().from(tsAPIKeys).where(eq(tsAPIKeys.userId, userId))).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError('REST_API.tokens.get', cause), }) ) ), /** * Creates a new API token for a user with the specified description. * @param userId - The ID of the user for whom to create the token. * @param description - A description for the API key. * @returns An Effect that resolves to the created API key record. * @throws {LibSQLDatabaseError} If a database error occurs during the operation. */ new: (userId: string, description: string) => Effect.gen(function* () { const key = yield* generateToken(userId, true); return yield* dbService.execute((db) => db .insert(tsAPIKeys) .values({ id: crypto.randomUUID(), creationDate: new Date(), userId, key, description, }) .returning() .get() ); }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError('REST_API.tokens.new', cause), }) ), /** * Deletes an API token for a user by its ID. * @param userId - The ID of the user whose token is to be deleted. * @param tokenId - The ID of the API token to delete. * @returns An Effect that resolves when the token is successfully deleted. * @throws {LibSQLDatabaseError} If a database error occurs during the operation. */ delete: (userId: string, tokenId: string) => dbService .execute((db) => db .delete(tsAPIKeys) .where(and(eq(tsAPIKeys.userId, userId), eq(tsAPIKeys.id, tokenId))) ) .pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError('REST_API.tokens.delete', cause), }) ), /** * Verifies an API key and retrieves the associated user ID and rank. * @param key - The API key to verify. * @returns An Effect that resolves to an object containing userId, key, and rank if valid, or false if invalid. * @throws {LibSQLDatabaseError} If a database error occurs during the verification. */ verify: (key: string) => Effect.gen(function* () { const apiKey = yield* dbService.execute((db) => db.select().from(tsAPIKeys).where(eq(tsAPIKeys.key, key)).get() ); if (!apiKey) return false; const keyRank = yield* dbService.execute((db) => db.select().from(tsPermissions).where(eq(tsPermissions.user, apiKey.userId)).get() ); if (!keyRank) return false; return { userId: apiKey.userId, key: apiKey.key, rank: keyRank.rank, }; }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError('REST_API.tokens.verify', cause), }) ), }, }; return REST_API; }), } ) {}