Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/.release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.15.0"
".": "1.15.1"
}
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [1.15.1](https://github.com/trycompai/crm/compare/v1.15.0...v1.15.1) (2026-08-20)


### Fixes

* **api:** serve openapi.json and bundle swagger deps in function build ([#166](https://github.com/trycompai/crm/issues/166)) ([7ea4f37](https://github.com/trycompai/crm/commit/7ea4f37cd65e93d62d3977e08a0df476b3aa4479))

## [1.15.0](https://github.com/trycompai/crm/compare/v1.14.0...v1.15.0) (2026-08-20)


Expand Down
2 changes: 1 addition & 1 deletion apps/api/scripts/build-func.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const EXTERNALS = [
"cardinal",
];

const VENDOR_ROOTS = ["express"];
const VENDOR_ROOTS = ["express", "@nestjs/swagger", "reflect-metadata"];

rmSync(outDir, { recursive: true, force: true });
mkdirSync(funcDir, { recursive: true });
Expand Down
75 changes: 40 additions & 35 deletions apps/api/src/create-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,45 +58,50 @@ export async function createApp(): Promise<NestExpressApplication> {
// routing (wired up during init) otherwise shadows anything registered after
// it. The factory form defers building the document (which needs the tRPC
// router, only available post-init) to first request instead.
SwaggerModule.setup("", app, () => {
const { appRouter } = app.get(AppRouterHost);
SwaggerModule.setup(
"",
app,
() => {
const { appRouter } = app.get(AppRouterHost);

const trpcDocument = generateOpenApiDocument(appRouter, {
title: "CRM API — tRPC bridge",
description:
"Every tRPC procedure, reachable over REST for tooling that cannot speak tRPC. Same validation, same middlewares, same services as the tRPC transport — this only translates the wire format.",
version: "1.0",
baseUrl: `${apiUrl}${REST_BRIDGE_PATH}`,
securitySchemes: { apiKey: apiKeySecurityScheme },
});
const trpcDocument = generateOpenApiDocument(appRouter, {
title: "CRM API — tRPC bridge",
description:
"Every tRPC procedure, reachable over REST for tooling that cannot speak tRPC. Same validation, same middlewares, same services as the tRPC transport — this only translates the wire format.",
version: "1.0",
baseUrl: `${apiUrl}${REST_BRIDGE_PATH}`,
securitySchemes: { apiKey: apiKeySecurityScheme },
});

const swaggerConfig = new DocumentBuilder()
.setTitle("CRM API")
.setDescription(
`REST surface of the CRM API — auth, health, the internal cron routes, and a generated REST bridge (under ${REST_BRIDGE_PATH}) for every tRPC procedure.`,
)
.setVersion("1.0")
.addCookieAuth(SESSION_COOKIE_NAME)
.addApiKey(apiKeySecurityScheme, "apiKey")
.build();
const swaggerDocument = SwaggerModule.createDocument(app, swaggerConfig);
const swaggerConfig = new DocumentBuilder()
.setTitle("CRM API")
.setDescription(
`REST surface of the CRM API — auth, health, the internal cron routes, and a generated REST bridge (under ${REST_BRIDGE_PATH}) for every tRPC procedure.`,
)
.setVersion("1.0")
.addCookieAuth(SESSION_COOKIE_NAME)
.addApiKey(apiKeySecurityScheme, "apiKey")
.build();
const swaggerDocument = SwaggerModule.createDocument(app, swaggerConfig);

swaggerDocument.paths = {
...swaggerDocument.paths,
...(trpcDocument.paths as typeof swaggerDocument.paths),
};
swaggerDocument.components = {
...swaggerDocument.components,
schemas: {
...swaggerDocument.components?.schemas,
...(trpcDocument.components?.schemas as NonNullable<
typeof swaggerDocument.components
>["schemas"]),
},
};
swaggerDocument.paths = {
...swaggerDocument.paths,
...(trpcDocument.paths as typeof swaggerDocument.paths),
};
swaggerDocument.components = {
...swaggerDocument.components,
schemas: {
...swaggerDocument.components?.schemas,
...(trpcDocument.components?.schemas as NonNullable<
typeof swaggerDocument.components
>["schemas"]),
},
};

return swaggerDocument;
});
return swaggerDocument;
},
{ jsonDocumentUrl: "openapi.json" },
);

await app.init();

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "crm",
"private": true,
"license": "MIT",
"version": "1.15.0",
"version": "1.15.1",
"scripts": {
"prepare": "git config core.hooksPath .githooks 2>/dev/null || true",
"build": "turbo run build",
Expand Down