Remove mcp-server
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
Docker Emulator Test / docker (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Test / docker (push) Has been cancelled
Runs E2E API Tests / build (22.x) (push) Has been cancelled
Runs E2E API Tests with external source of truth / build (22.x) (push) Has been cancelled
Lint & build / lint_and_build (latest) (push) Has been cancelled
Dev Environment Test / restart-dev-and-test (push) Has been cancelled
Run setup tests / setup-tests (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled

This commit is contained in:
Konstantin Wohlwend 2025-07-28 22:38:28 -07:00
parent ddf1cfd01a
commit 5ee342af7c
14 changed files with 5 additions and 703 deletions

View File

@ -17,7 +17,7 @@
"codegen-prisma:watch": "pnpm run prisma generate --watch",
"codegen-route-info": "pnpm run with-env tsx scripts/generate-route-info.ts",
"codegen-route-info:watch": "pnpm run with-env tsx watch --clear-screen=false scripts/generate-route-info.ts",
"codegen": "pnpm run with-env pnpm run generate-migration-imports && pnpm run with-env bash -c 'if [ \"$STACK_ACCELERATE_ENABLED\" = \"true\" ]; then pnpm run prisma generate --no-engine && pnpm run generate-openapi; else pnpm run codegen-prisma && pnpm run generate-openapi; fi' && pnpm run codegen-route-info",
"codegen": "pnpm run with-env pnpm run generate-migration-imports && pnpm run with-env bash -c 'if [ \"$STACK_ACCELERATE_ENABLED\" = \"true\" ]; then pnpm run prisma generate --no-engine; else pnpm run codegen-prisma; fi' && pnpm run codegen-route-info",
"codegen:watch": "concurrently -n \"prisma,docs,route-info\" -k \"pnpm run codegen-prisma:watch\" \"pnpm run watch-docs\" \"pnpm run codegen-route-info:watch\"",
"psql-inner": "psql $STACK_DATABASE_CONNECTION_STRING",
"psql": "pnpm run with-env pnpm run psql-inner",
@ -32,7 +32,6 @@
"generate-migration-imports:watch": "chokidar 'prisma/migrations/**/*.sql' -c 'pnpm run generate-migration-imports'",
"lint": "next lint",
"watch-docs": "pnpm run with-env bash -c 'tsx watch --clear-screen=false scripts/generate-openapi-fumadocs.ts && pnpm run --filter=@stackframe/stack-docs generate-openapi-docs'",
"generate-openapi": "pnpm run with-env tsx scripts/generate-openapi.ts",
"generate-openapi-fumadocs": "pnpm run with-env tsx scripts/generate-openapi-fumadocs.ts",
"generate-keys": "pnpm run with-env tsx scripts/generate-keys.ts",
"db-seed-script": "pnpm run with-env tsx prisma/seed.ts",

View File

@ -1,42 +0,0 @@
import { parseOpenAPI } from '@/lib/openapi';
import { isSmartRouteHandler } from '@/route-handlers/smart-route-handler';
import { writeFileSyncIfChanged } from '@stackframe/stack-shared/dist/utils/fs';
import { HTTP_METHODS } from '@stackframe/stack-shared/dist/utils/http';
import { typedKeys } from '@stackframe/stack-shared/dist/utils/objects';
import { glob } from 'glob';
import path from 'path';
async function main() {
console.log("Started docs schema generator");
for (const audience of ['client', 'server', 'admin'] as const) {
const filePathPrefix = path.resolve(process.platform === "win32" ? "apps/src/app/api/latest" : "src/app/api/latest");
const importPathPrefix = "@/app/api/latest";
const filePaths = [...await glob(filePathPrefix + "/**/route.{js,jsx,ts,tsx}")];
const openApiSchemaObject = parseOpenAPI({
endpoints: new Map(await Promise.all(filePaths.map(async (filePath) => {
if (!filePath.startsWith(filePathPrefix)) {
throw new Error(`Invalid file path: ${filePath}`);
}
const suffix = filePath.slice(filePathPrefix.length);
const midfix = suffix.slice(0, suffix.lastIndexOf("/route."));
const importPath = `${importPathPrefix}${suffix}`;
const urlPath = midfix.replaceAll("[", "{").replaceAll("]", "}").replaceAll(/\/\(.*\)/g, "");
const myModule = require(importPath);
const handlersByMethod = new Map(
typedKeys(HTTP_METHODS).map(method => [method, myModule[method]] as const)
.filter(([_, handler]) => isSmartRouteHandler(handler))
);
return [urlPath, handlersByMethod] as const;
}))),
audience,
});
writeFileSyncIfChanged(`../mcp-server/openapi/${audience}.json`, JSON.stringify(openApiSchemaObject, null, 2));
}
console.log("Successfully updated docs schemas");
}
main().catch((...args) => {
console.error(`ERROR! Could not update OpenAPI schema`, ...args);
process.exit(1);
});

View File

@ -13,7 +13,7 @@ import { ProjectsCrud } from "@stackframe/stack-shared/dist/interface/crud/proje
import { UsersCrud } from "@stackframe/stack-shared/dist/interface/crud/users";
import { StackAdaptSentinel, yupValidate } from "@stackframe/stack-shared/dist/schema-fields";
import { groupBy, typedIncludes } from "@stackframe/stack-shared/dist/utils/arrays";
import { getNodeEnvironment } from "@stackframe/stack-shared/dist/utils/env";
import { getEnvVariable, getNodeEnvironment } from "@stackframe/stack-shared/dist/utils/env";
import { StackAssertionError, StatusError, captureError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
import { deindent } from "@stackframe/stack-shared/dist/utils/strings";
import { NextRequest } from "next/server";
@ -259,7 +259,7 @@ const parseAuth = withTraceSpan('smart request parseAuth', async (req: NextReque
const tenancy = req.method === "GET" && req.url.endsWith("/users/me") ? "tenancy not available in /users/me as a performance hack" as never : await getSoleTenancyFromProjectBranch(projectId, branchId, true);
if (developmentKeyOverride) {
if (getNodeEnvironment() !== "development" && getNodeEnvironment() !== "test") {
if (!["development", "test"].includes(getNodeEnvironment()) && getEnvVariable("STACK_ALLOW_DEVELOPMENT_KEY_OVERRIDE_DESPITE_PRODUCTION", "") === "this-is-dangerous") { // it's not actually that dangerous, but it changes the security model
throw new StatusError(401, "Development key override is only allowed in development or test environments");
}
const result = await checkApiKeySet("internal", { superSecretAdminKey: developmentKeyOverride });

View File

@ -1,4 +0,0 @@
STACK_AUTH_URL=http://localhost:8102
STACK_PROJECT_ID=internal
STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only

View File

@ -1,7 +0,0 @@
module.exports = {
"extends": [
"../../configs/eslint/defaults.js",
"../../configs/eslint/next.js",
],
"ignorePatterns": ['/*', '!/src']
};

View File

@ -1,183 +0,0 @@
# @stackframe/mcp-server
## 2.8.26
### Patch Changes
- @stackframe/js@2.8.26
## 2.8.25
### Patch Changes
- @stackframe/js@2.8.25
## 2.8.24
### Patch Changes
- @stackframe/js@2.8.24
## 2.8.23
### Patch Changes
- @stackframe/js@2.8.23
## 2.8.22
### Patch Changes
- @stackframe/js@2.8.22
## 2.8.21
### Patch Changes
- @stackframe/js@2.8.21
## 2.8.20
### Patch Changes
- @stackframe/js@2.8.20
## 2.8.19
### Patch Changes
- @stackframe/js@2.8.19
## 2.8.18
### Patch Changes
- @stackframe/js@2.8.18
## 2.8.17
### Patch Changes
- @stackframe/js@2.8.17
## 2.8.16
### Patch Changes
- @stackframe/js@2.8.16
## 2.8.15
### Patch Changes
- @stackframe/js@2.8.15
## 2.8.14
### Patch Changes
- @stackframe/js@2.8.14
## 2.8.13
### Patch Changes
- @stackframe/js@2.8.13
## 2.8.12
### Patch Changes
- Various changes
- @stackframe/js@2.8.12
## 2.8.11
### Patch Changes
- @stackframe/js@2.8.11
## 2.8.10
### Patch Changes
- @stackframe/js@2.8.10
## 2.8.9
### Patch Changes
- Various changes
- @stackframe/js@2.8.9
## 2.8.8
### Patch Changes
- @stackframe/js@2.8.8
## 2.8.7
### Patch Changes
- @stackframe/js@2.8.7
## 2.8.6
### Patch Changes
- @stackframe/js@2.8.6
## 2.8.5
### Patch Changes
- @stackframe/js@2.8.5
## 2.8.4
### Patch Changes
- @stackframe/js@2.8.4
## 2.8.3
### Patch Changes
- Updated dependencies
- @stackframe/js@2.8.3
## 2.8.2
### Patch Changes
- @stackframe/js@2.8.2
## 2.8.1
### Patch Changes
- @stackframe/js@2.8.1
## 2.8.0
### Patch Changes
- Updated dependencies
- @stackframe/js@2.8.0
## 2.7.30
### Patch Changes
- @stackframe/js@2.7.30
## 2.7.29
### Patch Changes
- @stackframe/js@2.7.29
## 2.7.27
initial release

View File

@ -1 +0,0 @@
*.json

View File

@ -1,30 +0,0 @@
{
"name": "@stackframe/mcp-server",
"version": "2.8.26",
"private": true,
"type": "module",
"bin": {
"mcp-server": "./build/index.js"
},
"scripts": {
"start": "dotenv -c local -- tsx src/index.ts",
"dev-mcp-server": "dotenv -c development -- tsx watch --clear-screen=false src/index.ts",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"clean": "rimraf build && rimraf node_modules && rimraf openapi/*.json",
"build": "tsc"
},
"files": [
"build"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.7.0",
"@stackframe/js": "workspace:*",
"dotenv-cli": "^7.3.0",
"openapi-types": "^12.1.3"
},
"devDependencies": {
"@types/node": "20.17.6",
"typescript": "5.3.3"
}
}

View File

@ -1,229 +0,0 @@
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListToolsResult
} from "@modelcontextprotocol/sdk/types.js";
import { StackServerApp, stackAppInternalsSymbol } from "@stackframe/js";
import { readFileSync } from "fs";
import type { OpenAPIV3_1 } from 'openapi-types';
import { convertParameterArrayToJsonSchema } from "./utils/openapi-to-jsonschema";
const STACK_AUTH_URL = process.env.STACK_AUTH_URL ?? "https://api.stack-auth.com/";
const STACK_SECRET_SERVER_KEY = process.env.STACK_SECRET_SERVER_KEY;
const STACK_PROJECT_ID = process.env.STACK_PROJECT_ID;
const STACK_PUBLISHABLE_CLIENT_KEY = process.env.STACK_PUBLISHABLE_CLIENT_KEY;
if (!STACK_SECRET_SERVER_KEY || !STACK_PROJECT_ID || !STACK_PUBLISHABLE_CLIENT_KEY) {
throw new Error("STACK_SECRET_SERVER_KEY, STACK_PROJECT_ID, and STACK_PUBLISHABLE_CLIENT_KEY must be set");
}
export const stackServerApp = new StackServerApp({
baseUrl: STACK_AUTH_URL,
projectId: STACK_PROJECT_ID,
publishableClientKey: STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: STACK_SECRET_SERVER_KEY,
tokenStore: "memory",
});
// Cursor only supports 40 endpoints, so we only expose the most useful tools
const operationIDs = {
"getUserById": ["/users/{user_id}", "get"],
"updateUser": ["/users/{user_id}", "patch"],
"deleteUser": ["/users/{user_id}", "delete"],
"listUsers": ["/users", "get"],
"createUser": ["/users", "post"],
"listTeams": ["/teams", "get"],
"createTeam": ["/teams", "post"],
"listTeamMemberProfiles": ["/team-member-profiles", "get"],
"getTeamById": ["/teams/{team_id}", "get"],
"updateTeam": ["/teams/{team_id}", "patch"],
"deleteTeam": ["/teams/{team_id}", "delete"],
"addUserToTeam": ["/team-memberships/{team_id}/{user_id}", "post"],
"removeUserFromTeam": ["/team-memberships/{team_id}/{user_id}", "delete"],
"getTeamMemberProfile": ["/team-member-profiles/{team_id}/{user_id}", "get"],
"updateTeamMemberProfile": ["/team-member-profiles/{team_id}/{user_id}", "patch"],
"sendTeamInvitationCode": ["/team-invitations/send-code", "post"],
"grantTeamUserPermission": ["/team-permissions/{team_id}/{user_id}/{permission_id}", "post"],
"grantProjectPermission": ["/project-permissions/{user_id}/{permission_id}", "post"],
"revokeTeamUserPermission": ["/team-permissions/{team_id}/{user_id}/{permission_id}", "delete"],
"revokeProjectPermission": ["/project-permissions/{user_id}/{permission_id}", "delete"],
"listTeamPermissions": ["/team-permissions", "get"],
"getContactChannel": ["/contact-channels/{user_id}/{contact_channel_id}", "get"],
"updateContactChannel": ["/contact-channels/{user_id}/{contact_channel_id}", "patch"],
"deleteContactChannel": ["/contact-channels/{user_id}/{contact_channel_id}", "delete"],
"listContactChannels": ["/contact-channels", "get"]
};
function getOpenAPISchema(): OpenAPIV3_1.Document {
return JSON.parse(readFileSync("./openapi/server.json", "utf8"));
}
function isOperationObject(obj: any): obj is OpenAPIV3_1.OperationObject {
return obj !== null && typeof obj === 'object' && 'parameters' in obj;
}
function getOperationObject(openAPISchema: OpenAPIV3_1.Document, path: string, method: string): OpenAPIV3_1.OperationObject {
const pathItem = openAPISchema.paths?.[path];
if (!pathItem) {
throw new Error(`Could not find path item ${path} in openAPI schema`);
}
const operation = pathItem[method as keyof typeof pathItem];
if (!operation) {
throw new Error(`Could not find method ${method} in path item ${path} in openAPI schema`);
}
if (!isOperationObject(operation)) {
throw new Error(`Method ${method} in path ${path} is not an operation object`);
}
return operation;
}
type ToolType = {
path: string,
method: string,
name: string,
description: string | undefined,
inputSchema: {
[x: string]: unknown,
type: "object",
properties?: {
[x: string]: unknown,
} | undefined,
},
}
function getToolsFromOpenAPI(openAPISchema: OpenAPIV3_1.Document): ToolType[] {
const tools: ToolType[] = Object.entries(operationIDs).map(([operationID, [path, method]]) => {
const operation = getOperationObject(openAPISchema, path, method);
const inputSchema = !operation.parameters ? {
type: "object" as const,
properties: {},
required: [],
} : convertParameterArrayToJsonSchema(operation.parameters, operation.requestBody);
return {
name: operationID,
description: operation.description,
inputSchema,
path,
method,
};
});
return tools;
}
async function main() {
const openAPISchema = getOpenAPISchema();
const tools = getToolsFromOpenAPI(openAPISchema);
const transport = new StdioServerTransport();
const version = (await import("../package.json", { assert: { type: "json" } })).default.version;
// Create server instance
const server = new Server({
name: "stackauth",
version,
}, {
capabilities: {
tools: {}
}
});
server.setRequestHandler(ListToolsRequestSchema,
(): ListToolsResult => ({
tools
})
);
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const name = request.params.name;
const args = request.params.arguments ?? {};
const tool = tools.find(tool => tool.name === name);
if (!tool) {
return {
isError: true,
content: [{ type: "text", text: `Tool ${name} not found` }],
};
}
const path = tool.path;
const method = tool.method.toUpperCase();
// Split args into path and query parameters
const queryParams = new URLSearchParams();
const pathParams: Record<string, string> = {};
for (const [key, value] of Object.entries(args)) {
if (key.endsWith("###query")) {
const paramName = key.replace("###query", "");
queryParams.append(paramName, String(value));
} else if (key.endsWith("###path")) {
const paramName = key.replace("###path", "");
pathParams[paramName] = String(value);
}
}
// Replace path parameters
let finalPath = path;
for (const [key, value] of Object.entries(pathParams)) {
finalPath = finalPath.replace(`{${key}}`, value);
}
// Add query string if we have query parameters
const queryString = queryParams.toString();
if (queryString) {
finalPath += `?${queryString}`;
}
let body: string | undefined;
let headers: Record<string, string> | undefined;
// LIMITATION: we only support JSON body for now
if (args["###body###"] && typeof args["###body###"] === "string") {
body = args["###body###"];
headers = {
"Content-Type": "application/json",
};
}
const result = await (stackServerApp as any)[stackAppInternalsSymbol].sendRequest(finalPath, {
method,
headers: {
// Hack to make api call as a server and not client, should probably create a new (internal) function for this
"x-stack-secret-server-key": STACK_SECRET_SERVER_KEY,
...headers,
},
body,
}, "server");
if (!result.ok) {
return {
isError: true,
content: [{ type: "text", text: `Error: ${result.status} ${await result.text()}` }],
};
}
return {
content: [{ type: "text", text: JSON.stringify(await result.json(), null, 2) }],
};
});
await server.connect(transport);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -1,155 +0,0 @@
/**
* Type definitions for OpenAPI Parameter Object
*/
import type { OpenAPIV3_1 } from 'openapi-types';
/**
* Type definition for JSON Schema
*/
type JSONSchema = {
type: 'object',
properties: Record<string, any>,
required?: string[],
}
/**
* Type guard to check if an object is a ReferenceObject
* @param obj - Object to check
* @returns True if object is a ReferenceObject, false otherwise
*/
function isReferenceObject(obj: any): obj is OpenAPIV3_1.ReferenceObject {
return obj !== null && typeof obj === 'object' && '$ref' in obj;
}
/**
* Converts an OpenAPI Parameter Object Array to a JSON Schema
* @param parameterObjectArray - Array of OpenAPI Parameter Objects
* @returns JSON Schema representation of the parameters
*/
function convertParameterArrayToJsonSchema(parameterObjectArray: (OpenAPIV3_1.ParameterObject | OpenAPIV3_1.ReferenceObject)[], requestBody?: OpenAPIV3_1.RequestBodyObject | OpenAPIV3_1.ReferenceObject): {
type: "object",
properties: Record<string, any>,
required: string[],
} {
if (!Array.isArray(parameterObjectArray)) {
throw new Error('Input must be an array of parameter objects');
}
const properties = new Map<string, any>();
const requiredParams: string[] = [];
parameterObjectArray.forEach(param => {
if (isReferenceObject(param)) {
throw new Error('Reference objects are not supported');
}
if (!param.name) {
throw new Error('Parameter object must have a name');
}
const newParamName = param.name + "###" + param.in;
// Extract the schema from the parameter
let schema: Record<string, any> = param.schema ?
(typeof param.schema === 'object' ? { ...param.schema } : {}) :
{};
// If the parameter has its own type/format, use those instead
if ('type' in param && param.type) {
schema.type = param.type;
}
if ('format' in param && param.format) {
schema.format = param.format;
}
// Copy description if available
if (param.description) {
schema.description = param.description;
}
// Copy example if available
if ('example' in param && param.example !== undefined) {
schema.example = param.example;
}
// Handle enum values
if ('enum' in param && param.enum) {
schema.enum = param.enum;
}
// Add default value if specified
if ('default' in param && param.default !== undefined) {
schema.default = param.default;
}
// Add parameter to properties
properties.set(newParamName, schema);
// Add to required array if necessary
if (param.required === true) {
requiredParams.push(newParamName);
}
});
if (requestBody) {
const body = handleRequestBody(requestBody);
if (body) {
properties.set("###body###", body.properties);
requiredParams.push("###body###");
}
}
// Convert Map back to Record for return type
const propertiesRecord: Record<string, any> = {};
properties.forEach((value, key) => {
propertiesRecord[key] = value;
});
const jsonSchema = {
type: 'object' as const,
properties: propertiesRecord,
required: requiredParams
};
return jsonSchema;
}
export { convertParameterArrayToJsonSchema };
export type { JSONSchema };
function handleRequestBody(requestBody: OpenAPIV3_1.RequestBodyObject | OpenAPIV3_1.ReferenceObject) {
if (isReferenceObject(requestBody)) {
throw new Error('Reference objects are not supported');
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!requestBody.content["application/json"]) {
throw new Error('Request body must be of type application/json');
}
const body_schema = requestBody.content["application/json"].schema;
if (!body_schema || isReferenceObject(body_schema)) {
throw new Error('Reference objects are not supported');
}
if (!body_schema.properties) {
return;
}
// We simplify the body into one property, called "body"
return {
type: "string",
properties: {
body: JSON.stringify(body_schema)
},
required: ["body"]
};
}

View File

@ -1,37 +0,0 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"strict": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"noErrorTruncation": true,
"outDir": "./build",
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
]
},
"skipLibCheck": true
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}

View File

@ -26,7 +26,7 @@ COPY . .
RUN tsx ./scripts/generate-sdks.ts
# https://turbo.build/repo/docs/guides/tools/docker
RUN turbo prune --scope=@stackframe/stack-backend --scope=@stackframe/stack-dashboard --scope=@stackframe/mcp-server --docker
RUN turbo prune --scope=@stackframe/stack-backend --scope=@stackframe/stack-dashboard --docker
# Build stage

View File

@ -23,7 +23,7 @@
"restart-dev-environment": "pnpm pre && concurrently \"pnpm run build:packages && pnpm run codegen\" \"pnpm run restart-deps\" && pnpm run restart-dev-in-background",
"stop-dev-environment": "pnpm pre && pnpm run kill-dev:named && pnpm run stop-deps",
"clean": "pnpm pre-no-codegen && turbo run clean && rimraf --glob **/.next && rimraf --glob **/.turbo && rimraf .turbo && rimraf --glob **/node_modules",
"codegen": "pnpm pre && turbo run codegen && pnpm run generate-sdks && pnpm run generate-openapi && pnpm run generate-openapi-fumadocs",
"codegen": "pnpm pre && turbo run codegen && pnpm run generate-sdks && pnpm run generate-openapi-fumadocs",
"deps-compose": "docker compose -p stack-dependencies -f docker/dependencies/docker.compose.yaml",
"stop-deps": "POSTGRES_DELAY_MS=0 pnpm run deps-compose kill && POSTGRES_DELAY_MS=0 pnpm run deps-compose down -v",
"wait-until-postgres-is-ready:pg_isready": "until pg_isready -h localhost -p 5432; do sleep 1; done",
@ -58,7 +58,6 @@
"test:e2e": "pnpm pre && vitest e2e/tests",
"test:unit": "pnpm pre && vitest src",
"verify-data-integrity": "pnpm pre && pnpm -C apps/backend run verify-data-integrity",
"generate-openapi": "pnpm pre && turbo run generate-openapi",
"generate-openapi-fumadocs": "turbo run generate-openapi-fumadocs",
"generate-keys": "pnpm pre && turbo run generate-keys",
"generate-sdks": "npx --package=tsx tsx ./scripts/generate-sdks.ts",

View File

@ -59,11 +59,6 @@
],
"outputLogs": "new-only"
},
"@stackframe/mcp-server#build": {
"dependsOn": [
"@stackframe/stack-backend#build"
]
},
"@stackframe/stack-backend#build": {
"dependsOn": [
"codegen"
@ -97,9 +92,6 @@
"typecheck": {
"dependsOn": []
},
"generate-openapi": {
"cache": false
},
"generate-keys": {
"cache": false
},