Skip to content

Commit 12ec1d2

Browse files
authored
Merge pull request #36 from AsyncStatus/feat/changelogs
Feat/changelogs
2 parents 41c564a + fdc4d82 commit 12ec1d2

111 files changed

Lines changed: 22850 additions & 127 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Deploy API and Changelog App
2+
on:
3+
push:
4+
branches:
5+
- main
6+
workflow_dispatch:
7+
8+
jobs:
9+
deploy:
10+
runs-on: ubuntu-latest
11+
timeout-minutes: 60
12+
steps:
13+
- uses: oven-sh/setup-bun@v2
14+
with:
15+
bun-version: 1.2.18
16+
- uses: actions/checkout@v4
17+
- name: Install dependencies
18+
run: bun install
19+
20+
- name: Deploy Changelog API
21+
id: deploy-changelog-api
22+
uses: cloudflare/wrangler-action@v3
23+
with:
24+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
25+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
26+
workingDirectory: apps/changelog-api
27+
packageManager: bun
28+
29+
- name: Build Changelog App
30+
run: cd apps/changelog-app && bun run build
31+
env:
32+
VITE_CHANGELOG_API_URL: ${{ vars.VITE_CHANGELOG_API_URL }}
33+
VITE_CHANGELOGS_APP_URL: ${{ vars.VITE_CHANGELOGS_APP_URL }}
34+
VITE_SHORT_URL: ${{ vars.VITE_SHORT_URL }}
35+
TZ: UTC
36+
37+
- name: Deploy Changelog App
38+
uses: cloudflare/wrangler-action@v3
39+
with:
40+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
41+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
42+
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
43+
workingDirectory: apps/changelog-app
44+
packageManager: bun
45+
46+

apps/changelog-api/.gitignore

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# prod
2+
dist/
3+
4+
# dev
5+
.yarn/
6+
!.yarn/releases
7+
.vscode/*
8+
!.vscode/launch.json
9+
!.vscode/*.code-snippets
10+
.idea/workspace.xml
11+
.idea/usage.statistics.xml
12+
.idea/shelf
13+
14+
# deps
15+
node_modules/
16+
.wrangler
17+
18+
# env
19+
.env
20+
.env.production
21+
.dev.vars
22+
23+
# logs
24+
logs/
25+
*.log
26+
npm-debug.log*
27+
yarn-debug.log*
28+
yarn-error.log*
29+
pnpm-debug.log*
30+
lerna-debug.log*
31+
32+
# misc
33+
.DS_Store
34+
35+
# turso dev
36+
src/db/local-db
37+
src/db/local-db-shm
38+
src/db/local-db-wal

apps/changelog-api/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# AsyncStatus Changelog API
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { config } from "dotenv";
2+
import { defineConfig } from "drizzle-kit";
3+
4+
const processEnv = {} as Record<string, string>;
5+
config({ path: ".dev.vars", processEnv });
6+
7+
if (!processEnv.TURSO_URL) {
8+
throw new Error("TURSO_URL is not set");
9+
}
10+
11+
export default defineConfig({
12+
out: "./drizzle",
13+
schema: "./src/db/index.ts",
14+
strict: true,
15+
verbose: true,
16+
dialect: "turso",
17+
dbCredentials: {
18+
url: processEnv.TURSO_URL,
19+
authToken: processEnv.TURSO_AUTH_TOKEN,
20+
},
21+
});

apps/changelog-api/package.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@asyncstatus/changelog-api",
3+
"private": true,
4+
"type": "module",
5+
"exports": {
6+
"./filters": "./src/lib/filters.ts",
7+
"./typed-handlers/changelog": "./src/typed-handlers/changelog-contracts.ts"
8+
},
9+
"scripts": {
10+
"dev": "TZ=UTC wrangler dev --test-scheduled --port 8788",
11+
"dev:remote": "wrangler dev --remote",
12+
"deploy": "wrangler deploy --minify",
13+
"lint": "eslint . --max-warnings 0",
14+
"lint:fix": "eslint . --max-warnings 0 --fix",
15+
"format": "prettier --write .",
16+
"check-types": "tsc --noEmit"
17+
},
18+
"dependencies": {
19+
"@anthropic-ai/sdk": "0.55.1",
20+
"@asyncstatus/dayjs": "workspace:*",
21+
"@asyncstatus/db": "workspace:*",
22+
"@asyncstatus/typed-handlers": "workspace:*",
23+
"@hono-rate-limiter/cloudflare": "0.2.2",
24+
"@octokit/auth-oauth-user": "6.0.0",
25+
"@octokit/webhooks": "14.1.1",
26+
"@openrouter/ai-sdk-provider": "0.7.2",
27+
"@sindresorhus/slugify": "catalog:",
28+
"ai": "4.3.18",
29+
"better-auth": "catalog:",
30+
"drizzle-orm": "catalog:",
31+
"hono": "catalog:",
32+
"hono-rate-limiter": "0.4.2",
33+
"jose": "6.0.12",
34+
"nanoid": "catalog:",
35+
"octokit": "5.0.3",
36+
"resend": "4.7.0",
37+
"voyageai": "0.0.4",
38+
"zod": "catalog:"
39+
},
40+
"devDependencies": {
41+
"@asyncstatus/typescript-config": "workspace:*",
42+
"@cloudflare/workers-types": "catalog:",
43+
"@octokit/openapi-webhooks-types": "12.0.3",
44+
"@types/bun": "catalog:",
45+
"wrangler": "catalog:"
46+
}
47+
}

apps/changelog-api/src/index.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import {
2+
TYPED_HANDLERS_ERROR_STATUS_CODES_BY_KEY,
3+
TypedHandlersError,
4+
} from "@asyncstatus/typed-handlers";
5+
import { typedHandlersHonoServer } from "@asyncstatus/typed-handlers/hono";
6+
import { Hono } from "hono";
7+
import { cors } from "hono/cors";
8+
import type { ContentfulStatusCode } from "hono/utils/http-status";
9+
import { createContext, type HonoEnv } from "./lib/env";
10+
import {
11+
getChangelogBySlugHandler,
12+
listChangelogsByRepoHandler,
13+
listReposByOwnerHandler,
14+
startChangelogGenerationHandler,
15+
} from "./typed-handlers/changelog-handlers";
16+
17+
const app = new Hono<HonoEnv>()
18+
.use(
19+
"*",
20+
cors({
21+
origin: (origin, c) => {
22+
if (c.env.NODE_ENV === "development") {
23+
return origin;
24+
}
25+
if (origin.endsWith("asyncstatus.com")) {
26+
return origin;
27+
}
28+
if (origin.endsWith("changelogs.ai")) {
29+
return origin;
30+
}
31+
if (origin.endsWith("chlgs.ai")) {
32+
return origin;
33+
}
34+
return "https://changelogs.ai";
35+
},
36+
allowHeaders: [
37+
"Content-Type",
38+
"Authorization",
39+
"Content-Disposition",
40+
"Content-Length",
41+
"ETag",
42+
"Cache-Control",
43+
],
44+
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
45+
maxAge: 600,
46+
credentials: true,
47+
}),
48+
)
49+
.use(async (c, next) => {
50+
const context = await createContext(c);
51+
c.set("db", context.db);
52+
c.set("resend", context.resend);
53+
c.set("anthropicClient", context.anthropicClient);
54+
c.set("openRouterProvider", context.openRouterProvider);
55+
c.set("voyageClient", context.voyageClient);
56+
c.set("workflow", context.workflow);
57+
c.set("slack", context.slack);
58+
c.set("discord", context.discord);
59+
c.set("betterAuthUrl", context.betterAuthUrl);
60+
c.set("github", context.github);
61+
c.set("gitlab", context.gitlab);
62+
c.set("linear", context.linear);
63+
return next();
64+
})
65+
.onError((err, c) => {
66+
console.error(err);
67+
if (err instanceof TypedHandlersError) {
68+
return c.json(
69+
{ type: err.name, message: err.message, code: err.code, cause: err.cause },
70+
TYPED_HANDLERS_ERROR_STATUS_CODES_BY_KEY[
71+
err.code ?? "INTERNAL_SERVER_ERROR"
72+
] as ContentfulStatusCode,
73+
);
74+
}
75+
return c.json({ message: "Unknown error", code: "INTERNAL_SERVER_ERROR", cause: err }, 500);
76+
});
77+
78+
const typedHandlersApp = typedHandlersHonoServer(
79+
app,
80+
[
81+
listChangelogsByRepoHandler,
82+
listReposByOwnerHandler,
83+
getChangelogBySlugHandler,
84+
startChangelogGenerationHandler,
85+
],
86+
{
87+
getContext: (c) => ({
88+
db: c.get("db"),
89+
resend: c.get("resend"),
90+
anthropicClient: c.get("anthropicClient"),
91+
openRouterProvider: c.get("openRouterProvider"),
92+
voyageClient: c.get("voyageClient"),
93+
discord: c.get("discord"),
94+
slack: c.get("slack"),
95+
changelogAppUrl: c.env.CHANGELOG_APP_URL,
96+
workflow: c.get("workflow"),
97+
betterAuthUrl: c.env.BETTER_AUTH_URL,
98+
github: c.get("github"),
99+
gitlab: c.get("gitlab"),
100+
linear: c.get("linear"),
101+
}),
102+
},
103+
);
104+
105+
export default {
106+
fetch: typedHandlersApp.fetch,
107+
};
108+
export type App = typeof app;
109+
110+
export { ChangelogGenerationJobWorkflow } from "./workflows/github/changelog-generation-job";

0 commit comments

Comments
 (0)