@extenshi/mcp
Version:
Extenshi MCP server — bring the extension catalog (search, security, market research) and pre-publish scanning into your AI tools
105 lines • 7.37 kB
JavaScript
/**
* Thin tRPC client for the public catalog BFF (`bff.extenshi.io`).
*
* The BFF tRPC server is configured WITHOUT a data transformer (no superjson),
* so this client must match — plain JSON over the wire. We type the proxy as
* `any` on purpose: catalog-api emits no `.d.ts`, so the BFF↔API type chain
* can't be imported reliably across a published-package boundary. The runtime
* proxy builds the procedure path from property access regardless of types.
*
* Every call carries `Authorization: Bearer <ek_…>`. Today the BFF read
* procedures are anonymous, but they are moving to mandatory key-enforcement
* (no anonymous data access) — sending the key now is forward-compatible and
* needs no client change when enforcement lands.
*/
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { PAY_OPERATIONS, payWireInput } from './pay.js';
/** Build a BFF client from a static `ek_…` key (stdio path). */
export function makeBff(bffUrl, apiKey) {
return makeBffWithAuth(bffUrl, () => `Bearer ${apiKey}`);
}
/**
* Build a BFF client whose Authorization header is produced per request by
* `authHeader` (may be async). The remote OAuth server uses this to mint a
* fresh, short-lived genkan JWT for each call instead of holding a static key.
* The provider returns the FULL header value (e.g. `Bearer eyJ…`).
*/
export function makeBffWithAuth(bffUrl, authHeader) {
const client = createTRPCClient({
links: [
httpBatchLink({
url: `${bffUrl}/api/trpc`,
headers: async () => ({ authorization: await authHeader() }),
}),
],
});
// NB: the store router is mounted under `catalog` in the BFF appRouter
// (routers/index.ts: `catalog: storeRouter`), NOT `store`. Security is `security`.
const pay = Object.fromEntries(PAY_OPERATIONS.map(([method, , , procedure, mutation]) => [
method,
(input) => {
const [router, action] = procedure.split('.');
return client[router][action][mutation ? 'mutate' : 'query'](payWireInput(method, input));
},
]));
return {
...pay,
createProject: (input) => client.devProject.agentCreateProject.mutate(input),
getDecisions: (input) => client.devProject.agentGetDecisions.query(input),
proposeDecision: (input) => client.devProject.agentProposeDecision.mutate(input),
importManifest: (input) => client.devProject.agentImportManifest.mutate(input),
getProjectWorkspace: (input) => client.devProject.agentGetWorkspace.query(input),
diffProjectWorkspace: (input) => client.devProject.agentDiffWorkspace.mutate(input),
patchProjectWorkspace: (input) => client.devProject.agentPatchWorkspace.mutate(input),
recordProjectEvidence: (input) => client.devProject.agentRecordEvidence.mutate(input),
getReleaseReadiness: (input) => client.devProject.agentReleaseReadiness.query(input),
connectionDiagnostics: () => client.devProject.agentConnectionDiagnostics.query(),
searchExtensions: (input) => client.catalog.searchExtensions.query(input),
getExtensionById: (id) => client.catalog.getExtensionById.query({ id }),
getReviews: (input) => client.catalog.getReviewsForExtension.query(input),
getSecurityData: (extensionId) => client.security.getSecurityData.query({ extensionId }),
getRiskSummary: (extensionId) => client.security.getRiskSummary.query({ extensionId }),
getSearchFacets: (input) => client.catalog.getSearchFacets.query(input),
getStats: () => client.catalog.getStats.query(),
getExtendedFilterFacets: () => client.catalog.getExtendedFilterFacets.query(),
getCategoryTree: () => client.catalog.getCategoryTree.query(),
getApiCallerBalance: () => client.cli.getApiCallerBalance.query(),
resolveExtensionRef: (input) => client.catalog.resolveExtensionRef.query(input),
getSecuritySummaryBatch: (input) => client.security.getSecuritySummaryBatch.query(input),
listMyProjects: () => client.devProject.agentListProjects.query(),
getMyProjectState: (input) => client.devProject.agentGetProjectState.query(input),
getMyProjectScaffold: (input) => client.devProject.agentGetProjectScaffold.query(input),
listPrivacyPolicyVersions: (input) => client.privacyPolicy.agentListVersions.query(input),
getPrivacyPolicyVersion: (input) => client.privacyPolicy.agentGetVersion.query(input),
publishPrivacyPolicy: (input) => client.privacyPolicy.agentPublish.mutate(input),
updatePrivacyPolicyWithAi: (input) => client.privacyPolicy.agentUpdateWithAi.mutate(input),
createCiIngestSecret: (input) => client.devProject.agentCreateCiIngestSecret.mutate(input),
revokeCiIngestSecret: (input) => client.devProject.agentRevokeCiIngestSecret.mutate(input),
upsertHostedPage: (input) => client.devProject.agentUpsertHostedPage.mutate(input),
verifyHostedArtifact: (input) => client.devProject.agentVerifyHostedArtifact.mutate(input),
removeHostedPage: (input) => client.devProject.agentRemoveHostedPage.mutate(input),
listHostedPages: (input) => client.devProject.agentListHostedPages.query(input),
publishLandingPage: (input) => client.devProject.agentPublishLandingPage.mutate(input),
getLandingPage: (input) => client.devProject.agentGetLandingPage.query(input),
unpublishLandingPage: (input) => client.devProject.agentUnpublishLandingPage.mutate(input),
draftLandingPage: (input) => client.devProject.agentDraftLandingPage.query(input),
previewLandingPage: (input) => client.devProject.agentPreviewLandingPage.mutate(input),
listLandingVersions: (input) => client.devProject.agentListLandingVersions.query(input),
rollbackLandingPage: (input) => client.devProject.agentRollbackLandingPage.mutate(input),
getCustomDomain: (input) => client.devProject.agentGetCustomDomain.query(input),
setCustomDomain: (input) => client.devProject.agentSetCustomDomain.mutate(input),
verifyCustomDomain: (input) => client.devProject.agentVerifyCustomDomain.mutate(input),
removeCustomDomain: (input) => client.devProject.agentRemoveCustomDomain.mutate(input),
getInstructionsPage: (input) => client.devProject.agentGetInstructionsPage.query(input),
publishInstructions: (input) => client.devProject.agentPublishInstructions.mutate(input),
setInstructionsEnabled: (input) => client.devProject.agentSetInstructionsEnabled.mutate(input),
getPageTranslations: (input) => client.devProject.agentGetPageTranslations.query(input),
setPageTranslations: (input) => client.devProject.agentSetPageTranslations.mutate(input),
getPrivacyPolicyTranslations: (input) => client.privacyPolicy.agentGetTranslations.query(input),
setPrivacyPolicyTranslations: (input) => client.privacyPolicy.agentSetTranslations.mutate(input),
getLicenseTermsTranslations: (input) => client.payLicenseTerms.getTranslations.query(input),
setLicenseTermsTranslations: (input) => client.payLicenseTerms.setTranslations.mutate(input),
uploadProjectMedia: (input) => client.devProject.agentUploadProjectMedia.mutate(input),
};
}
//# sourceMappingURL=bff.js.map