Skip to main content
Glama

mcp-google-sheets

db-piece-metadata-service.ts11.1 kB
import { PieceMetadataModel, PieceMetadataModelSummary, pieceTranslation } from '@activepieces/pieces-framework' import { ActivepiecesError, apId, assertNotNullOrUndefined, ErrorCode, EXACT_VERSION_REGEX, isNil, ListVersionsResponse, PieceType } from '@activepieces/shared' import dayjs from 'dayjs' import { FastifyBaseLogger } from 'fastify' import semVer from 'semver' import { IsNull } from 'typeorm' import { repoFactory } from '../../core/db/repo-factory' import { enterpriseFilteringUtils } from '../../ee/pieces/filters/piece-filtering-utils' import { PieceMetadataEntity, PieceMetadataSchema, } from '../piece-metadata-entity' import { pieceTagService } from '../tags/pieces/piece-tag.service' import { localPieceCache } from './helper/local-piece-cache' import { PieceMetadataService } from './piece-metadata-service' import { pieceListUtils } from './utils' import { toPieceMetadataModelSummary } from '.' const repo = repoFactory(PieceMetadataEntity) export const FastDbPieceMetadataService = (log: FastifyBaseLogger): PieceMetadataService => { return { async list(params): Promise<PieceMetadataModelSummary[]> { const originalPieces = await findAllPiecesVersionsSortedByNameAscVersionDesc({ ...params, log, }) const uniquePieces = new Set<string>(originalPieces.map((piece) => piece.name)) const latestVersionOfEachPiece = Array.from(uniquePieces).map((name) => { const result = originalPieces.find((piece) => piece.name === name) const usageCount = originalPieces.filter((piece) => piece.name === name).reduce((acc, piece) => { return acc + piece.projectUsage }, 0) assertNotNullOrUndefined(result, 'piece_metadata_not_found') return { ...result, projectUsage: usageCount, } }) const piecesWithTags = await enrichTags(params.platformId, latestVersionOfEachPiece, params.includeTags) const translatedPieces = piecesWithTags.map((piece) => pieceTranslation.translatePiece<PieceMetadataSchema>(piece, params.locale)) const filteredPieces = await pieceListUtils.filterPieces({ ...params, pieces: translatedPieces, suggestionType: params.suggestionType, }) return toPieceMetadataModelSummary(filteredPieces, piecesWithTags, params.suggestionType) }, async get({ projectId, platformId, version, name }): Promise<PieceMetadataModel | undefined> { const versionToSearch = findNextExcludedVersion(version) const originalPieces = await findAllPiecesVersionsSortedByNameAscVersionDesc({ projectId, platformId, release: undefined, log, }) const piece = originalPieces.find((piece) => { const strictlyLessThan = (isNil(versionToSearch) || ( semVer.compare(piece.version, versionToSearch.nextExcludedVersion) < 0 && semVer.compare(piece.version, versionToSearch.baseVersion) >= 0 )) return piece.name === name && strictlyLessThan }) const isFiltered = !isNil(piece) && await enterpriseFilteringUtils.isFiltered({ piece, projectId, platformId, }) if (isFiltered) { return undefined } return piece }, async getOrThrow({ projectId, version, name, platformId, locale }): Promise<PieceMetadataModel> { const piece = await this.get({ projectId, version, name, platformId }) if (isNil(piece)) { throw new ActivepiecesError({ code: ErrorCode.ENTITY_NOT_FOUND, params: { message: `piece_metadata_not_found projectId=${projectId} pieceName=${name}`, }, }) } return pieceTranslation.translatePiece<PieceMetadataModel>(piece, locale) }, async getVersions({ name, projectId, release, platformId }): Promise<ListVersionsResponse> { const pieces = await findAllPiecesVersionsSortedByNameAscVersionDesc({ projectId, platformId, release, log, }) return pieces.filter(p => p.name === name).reverse() .reduce((record, pieceMetadata) => { record[pieceMetadata.version] = {} return record }, {} as ListVersionsResponse) }, async updateUsage({ id, usage }): Promise<void> { const existingMetadata = await repo().findOneByOrFail({ id, }) await repo().update(id, { projectUsage: usage, updated: existingMetadata.updated, created: existingMetadata.created, }) }, async resolveExactVersion({ name, version, projectId, platformId }): Promise<string> { const isExactVersion = EXACT_VERSION_REGEX.test(version) if (isExactVersion) { return version } const pieceMetadata = await this.getOrThrow({ projectId, name, version, platformId, }) return pieceMetadata.version }, async create({ pieceMetadata, projectId, platformId, packageType, pieceType, archiveId, }): Promise<PieceMetadataSchema> { const existingMetadata = await repo().findOneBy({ name: pieceMetadata.name, version: pieceMetadata.version, projectId: projectId ?? IsNull(), platformId: platformId ?? IsNull(), }) if (!isNil(existingMetadata)) { throw new ActivepiecesError({ code: ErrorCode.VALIDATION, params: { message: `piece_metadata_already_exists name=${pieceMetadata.name} version=${pieceMetadata.version} projectId=${projectId}`, }, }) } const createdDate = await findOldestCreataDate({ name: pieceMetadata.name, projectId, platformId, }) return repo().save({ id: apId(), projectId, packageType, pieceType, archiveId, platformId, created: createdDate, ...pieceMetadata, }) }, } } const findOldestCreataDate = async ({ name, projectId, platformId }: { name: string, projectId: string | undefined, platformId: string | undefined }): Promise<string> => { const piece = await repo().findOne({ where: { name, projectId: projectId ?? IsNull(), platformId: platformId ?? IsNull(), }, order: { created: 'ASC', }, }) return piece?.created ?? dayjs().toISOString() } const enrichTags = async (platformId: string | undefined, pieces: PieceMetadataSchema[], includeTags: boolean | undefined): Promise<PieceMetadataSchema[]> => { if (!includeTags || isNil(platformId)) { return pieces } const tags = await pieceTagService.findByPlatform(platformId) return pieces.map((piece) => { return { ...piece, tags: tags[piece.name] ?? [], } }) } const findNextExcludedVersion = (version: string | undefined): { baseVersion: string, nextExcludedVersion: string } | undefined => { if (version?.startsWith('^')) { const baseVersion = version.substring(1) return { baseVersion, nextExcludedVersion: increaseMajorVersion(baseVersion), } } if (version?.startsWith('~')) { const baseVersion = version.substring(1) return { baseVersion, nextExcludedVersion: increaseMinorVersion(baseVersion), } } if (isNil(version)) { return undefined } return { baseVersion: version, nextExcludedVersion: increasePatchVersion(version), } } const increasePatchVersion = (version: string): string => { const incrementedVersion = semVer.inc(version, 'patch') if (isNil(incrementedVersion)) { throw new Error(`Failed to increase patch version ${version}`) } return incrementedVersion } const increaseMinorVersion = (version: string): string => { const incrementedVersion = semVer.inc(version, 'minor') if (isNil(incrementedVersion)) { throw new Error(`Failed to increase minor version ${version}`) } return incrementedVersion } const increaseMajorVersion = (version: string): string => { const incrementedVersion = semVer.inc(version, 'major') if (isNil(incrementedVersion)) { throw new Error(`Failed to increase major version ${version}`) } return incrementedVersion } async function findAllPiecesVersionsSortedByNameAscVersionDesc({ projectId, platformId, release, log }: { projectId?: string, platformId?: string, release: string | undefined, log: FastifyBaseLogger }): Promise<PieceMetadataSchema[]> { const piece = (await localPieceCache(log).getSortedbyNameAscThenVersionDesc()).filter((piece) => { return isOfficialPiece(piece) || isProjectPiece(projectId, piece) || isPlatformPiece(platformId, piece) }).filter((piece) => isSupportedRelease(release, piece)) return piece } function isSupportedRelease(release: string | undefined, piece: PieceMetadataSchema): boolean { if (isNil(release)) { return true } if (!isNil(piece.maximumSupportedRelease) && semVer.compare(release, piece.maximumSupportedRelease) == 1) { return false } if (!isNil(piece.minimumSupportedRelease) && semVer.compare(release, piece.minimumSupportedRelease) == -1) { return false } return true } function isOfficialPiece(piece: PieceMetadataSchema): boolean { return piece.pieceType === PieceType.OFFICIAL && isNil(piece.projectId) && isNil(piece.platformId) } function isProjectPiece(projectId: string | undefined, piece: PieceMetadataSchema): boolean { if (isNil(projectId)) { return false } return piece.projectId === projectId && piece.pieceType === PieceType.CUSTOM } function isPlatformPiece(platformId: string | undefined, piece: PieceMetadataSchema): boolean { if (isNil(platformId)) { return false } return piece.platformId === platformId && isNil(piece.projectId) && piece.pieceType === PieceType.CUSTOM }

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/activepieces/activepieces'

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