Skip to main content
Glama
Apache 2.0
845
2,105
  • Apple
util.ts3.61 kB
import { z } from 'zod'; import type { SupabasePlatform } from './platform/types.js'; import { PLATFORM_INDEPENDENT_FEATURES } from './server.js'; import { currentFeatureGroupSchema, featureGroupSchema, type FeatureGroup, } from './types.js'; export type ValueOf<T> = T[keyof T]; // UnionToIntersection<A | B> = A & B export type UnionToIntersection<U> = ( U extends unknown ? (arg: U) => 0 : never ) extends (arg: infer I) => 0 ? I : never; // LastInUnion<A | B> = B export type LastInUnion<U> = UnionToIntersection<U extends unknown ? (x: U) => 0 : never> extends ( x: infer L ) => 0 ? L : never; // UnionToTuple<A, B> = [A, B] export type UnionToTuple<T, Last = LastInUnion<T>> = [T] extends [never] ? [] : [Last, ...UnionToTuple<Exclude<T, Last>>]; /** * Parses a key-value string into an object. * * @returns An object representing the key-value pairs * * @example * const result = parseKeyValueList("key1=value1\nkey2=value2"); * console.log(result); // { key1: "value1", key2: "value2" } */ export function parseKeyValueList(data: string): { [key: string]: string } { return Object.fromEntries( data .split('\n') .map((item) => item.split(/=(.*)/)) // split only on the first '=' .filter(([key]) => key) // filter out empty keys .map(([key, value]) => [key, value ?? '']) // ensure value is not undefined ); } /** * Creates a unique hash from a JavaScript object. * @param obj - The object to hash * @param length - Optional length to truncate the hash (default: full length) */ export async function hashObject( obj: Record<string, any>, length?: number ): Promise<string> { // Sort object keys to ensure consistent output regardless of original key order const str = JSON.stringify(obj, (_, value) => { if (value && typeof value === 'object' && !Array.isArray(value)) { return Object.keys(value) .sort() .reduce<Record<string, any>>((result, key) => { result[key] = value[key]; return result; }, {}); } return value; }); const buffer = await crypto.subtle.digest( 'SHA-256', new TextEncoder().encode(str) ); // Convert to base64 const base64Hash = btoa(String.fromCharCode(...new Uint8Array(buffer))); return base64Hash.slice(0, length); } /** * Parses and validates feature groups based on the platform's available features. */ export function parseFeatureGroups( platform: SupabasePlatform, features: string[] ) { // First pass: validate that all features are valid const desiredFeatures = z.set(featureGroupSchema).parse(new Set(features)); // The platform implementation can define a subset of features const availableFeatures: FeatureGroup[] = [ ...PLATFORM_INDEPENDENT_FEATURES, ...currentFeatureGroupSchema.options.filter((key) => Object.keys(platform).includes(key) ), ]; const availableFeaturesSchema = z.enum( availableFeatures as [string, ...string[]], { description: 'Available features based on platform implementation', errorMap: (issue, ctx) => { switch (issue.code) { case 'invalid_enum_value': return { message: `This platform does not support the '${issue.received}' feature group. Supported groups are: ${availableFeatures.join(', ')}`, }; default: return { message: ctx.defaultError }; } }, } ); // Second pass: validate the desired features against this platform's available features return z.set(availableFeaturesSchema).parse(desiredFeatures); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/supabase-community/mcp-supabase'

If you have feedback or need assistance with the MCP directory API, please join our Discord server