Skip to content

Commit fd3fe8a

Browse files
committed
gonna eject from tanstack start. API routes aren't there yet. I want to use containers but not clear how to get a public url with those
1 parent 6d3af03 commit fd3fe8a

File tree

16 files changed

+1064
-52
lines changed

16 files changed

+1064
-52
lines changed

app/components/app-navbar.tsx

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,52 +16,45 @@ import { LogOut, User, Settings } from "lucide-react";
1616

1717
export function AppNavbar() {
1818
return (
19-
<nav className="fixed top-0 left-0 right-0 z-50 backdrop-blur-sm border-b border-border/60 bg-background/95">
19+
<nav className="fixed left-0 right-0 top-0 z-50 border-b border-border/60 bg-background/95 backdrop-blur-sm">
2020
<header className="flex h-16 items-center px-4 lg:px-6">
2121
<div className="flex flex-1 items-center gap-6">
2222
<div className="flex items-center gap-4">
23-
<Link
24-
to="/"
25-
className="flex items-center transition-opacity hover:opacity-80"
26-
>
27-
<img
28-
src="/images/braid-logo-light.svg"
29-
alt="Braid Logo"
30-
className="h-7 w-auto"
31-
/>
23+
<Link to="/" className="flex items-center transition-opacity hover:opacity-80">
24+
<img src="/images/braid-logo-light.svg" alt="Braid Logo" className="h-7 w-auto" />
3225
</Link>
3326
<Separator orientation="vertical" className="mx-1 h-5 opacity-30" />
3427
<DashboardBreadcrumb />
3528
</div>
36-
29+
3730
<div className="ml-auto flex items-center gap-4">
3831
<Link
3932
to="/feed"
40-
activeProps={{
41-
className: "text-foreground bg-muted"
33+
activeProps={{
34+
className: "text-foreground bg-muted",
4235
}}
43-
inactiveProps={{
44-
className: "text-muted-foreground hover:text-foreground hover:bg-muted/60"
36+
inactiveProps={{
37+
className: "text-muted-foreground hover:text-foreground hover:bg-muted/60",
4538
}}
46-
className="relative px-3 py-2 rounded-lg font-medium transition-all duration-200 ease-in-out"
39+
className="relative rounded-lg px-3 py-2 font-medium transition-all duration-200 ease-in-out"
4740
>
4841
Feed
4942
</Link>
5043
<Link
5144
to="/config"
52-
activeProps={{
53-
className: "text-foreground bg-muted"
45+
activeProps={{
46+
className: "text-foreground bg-muted",
5447
}}
55-
inactiveProps={{
56-
className: "text-muted-foreground hover:text-foreground hover:bg-muted/60"
48+
inactiveProps={{
49+
className: "text-muted-foreground hover:text-foreground hover:bg-muted/60",
5750
}}
58-
className="relative px-3 py-2 rounded-lg font-medium transition-all duration-200 ease-in-out"
51+
className="relative rounded-lg px-3 py-2 font-medium transition-all duration-200 ease-in-out"
5952
>
6053
Config
6154
</Link>
62-
55+
6356
<Separator orientation="vertical" className="h-8 opacity-30" />
64-
57+
6558
<DropdownMenu>
6659
<DropdownMenuTrigger asChild>
6760
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
@@ -75,9 +68,7 @@ export function AppNavbar() {
7568
<DropdownMenuLabel className="font-normal">
7669
<div className="flex flex-col space-y-1">
7770
<p className="text-sm font-medium leading-none">Henry Dowling</p>
78-
<p className="text-xs leading-none text-muted-foreground">
79-
henry@example.com
80-
</p>
71+
<p className="text-xs leading-none text-muted-foreground">henry@example.com</p>
8172
</div>
8273
</DropdownMenuLabel>
8374
<DropdownMenuSeparator />
@@ -103,4 +94,4 @@ export function AppNavbar() {
10394
</header>
10495
</nav>
10596
);
106-
}
97+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
CREATE TABLE IF NOT EXISTS "config" (
2+
"installation_id" integer,
3+
"product" text NOT NULL,
4+
"services" jsonb DEFAULT '[]'::jsonb NOT NULL,
5+
CONSTRAINT "config_installation_id_product_pk" PRIMARY KEY("installation_id","product")
6+
);
7+
--> statement-breakpoint
8+
CREATE TABLE IF NOT EXISTS "slack_installations" (
9+
"id" serial PRIMARY KEY NOT NULL,
10+
"team_id" text NOT NULL,
11+
"team_name" text NOT NULL,
12+
"bot" jsonb NOT NULL,
13+
"incoming_webhook" jsonb NOT NULL,
14+
CONSTRAINT "slack_installations_team_id_unique" UNIQUE("team_id")
15+
);
16+
--> statement-breakpoint
17+
CREATE TABLE IF NOT EXISTS "status_messages" (
18+
"guid" text PRIMARY KEY NOT NULL,
19+
"title" text NOT NULL,
20+
"content" text NOT NULL,
21+
"pub_date" timestamp NOT NULL,
22+
"product" text NOT NULL,
23+
"affected_services" jsonb DEFAULT '[]'::jsonb NOT NULL
24+
);
25+
--> statement-breakpoint
26+
DO $$ BEGIN
27+
ALTER TABLE "config" ADD CONSTRAINT "config_installation_id_slack_installations_id_fk" FOREIGN KEY ("installation_id") REFERENCES "public"."slack_installations"("id") ON DELETE no action ON UPDATE no action;
28+
EXCEPTION
29+
WHEN duplicate_object THEN null;
30+
END $$;
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
{
2+
"id": "2d74bcdf-e356-4cf8-afec-1141f1f02c04",
3+
"prevId": "00000000-0000-0000-0000-000000000000",
4+
"version": "7",
5+
"dialect": "postgresql",
6+
"tables": {
7+
"public.config": {
8+
"name": "config",
9+
"schema": "",
10+
"columns": {
11+
"installation_id": {
12+
"name": "installation_id",
13+
"type": "integer",
14+
"primaryKey": false,
15+
"notNull": false
16+
},
17+
"product": {
18+
"name": "product",
19+
"type": "text",
20+
"primaryKey": false,
21+
"notNull": true
22+
},
23+
"services": {
24+
"name": "services",
25+
"type": "jsonb",
26+
"primaryKey": false,
27+
"notNull": true,
28+
"default": "'[]'::jsonb"
29+
}
30+
},
31+
"indexes": {},
32+
"foreignKeys": {
33+
"config_installation_id_slack_installations_id_fk": {
34+
"name": "config_installation_id_slack_installations_id_fk",
35+
"tableFrom": "config",
36+
"tableTo": "slack_installations",
37+
"columnsFrom": [
38+
"installation_id"
39+
],
40+
"columnsTo": [
41+
"id"
42+
],
43+
"onDelete": "no action",
44+
"onUpdate": "no action"
45+
}
46+
},
47+
"compositePrimaryKeys": {
48+
"config_installation_id_product_pk": {
49+
"name": "config_installation_id_product_pk",
50+
"columns": [
51+
"installation_id",
52+
"product"
53+
]
54+
}
55+
},
56+
"uniqueConstraints": {},
57+
"policies": {},
58+
"checkConstraints": {},
59+
"isRLSEnabled": false
60+
},
61+
"public.slack_installations": {
62+
"name": "slack_installations",
63+
"schema": "",
64+
"columns": {
65+
"id": {
66+
"name": "id",
67+
"type": "serial",
68+
"primaryKey": true,
69+
"notNull": true
70+
},
71+
"team_id": {
72+
"name": "team_id",
73+
"type": "text",
74+
"primaryKey": false,
75+
"notNull": true
76+
},
77+
"team_name": {
78+
"name": "team_name",
79+
"type": "text",
80+
"primaryKey": false,
81+
"notNull": true
82+
},
83+
"bot": {
84+
"name": "bot",
85+
"type": "jsonb",
86+
"primaryKey": false,
87+
"notNull": true
88+
},
89+
"incoming_webhook": {
90+
"name": "incoming_webhook",
91+
"type": "jsonb",
92+
"primaryKey": false,
93+
"notNull": true
94+
}
95+
},
96+
"indexes": {},
97+
"foreignKeys": {},
98+
"compositePrimaryKeys": {},
99+
"uniqueConstraints": {
100+
"slack_installations_team_id_unique": {
101+
"name": "slack_installations_team_id_unique",
102+
"nullsNotDistinct": false,
103+
"columns": [
104+
"team_id"
105+
]
106+
}
107+
},
108+
"policies": {},
109+
"checkConstraints": {},
110+
"isRLSEnabled": false
111+
},
112+
"public.status_messages": {
113+
"name": "status_messages",
114+
"schema": "",
115+
"columns": {
116+
"guid": {
117+
"name": "guid",
118+
"type": "text",
119+
"primaryKey": true,
120+
"notNull": true
121+
},
122+
"title": {
123+
"name": "title",
124+
"type": "text",
125+
"primaryKey": false,
126+
"notNull": true
127+
},
128+
"content": {
129+
"name": "content",
130+
"type": "text",
131+
"primaryKey": false,
132+
"notNull": true
133+
},
134+
"pub_date": {
135+
"name": "pub_date",
136+
"type": "timestamp",
137+
"primaryKey": false,
138+
"notNull": true
139+
},
140+
"product": {
141+
"name": "product",
142+
"type": "text",
143+
"primaryKey": false,
144+
"notNull": true
145+
},
146+
"affected_services": {
147+
"name": "affected_services",
148+
"type": "jsonb",
149+
"primaryKey": false,
150+
"notNull": true,
151+
"default": "'[]'::jsonb"
152+
}
153+
},
154+
"indexes": {},
155+
"foreignKeys": {},
156+
"compositePrimaryKeys": {},
157+
"uniqueConstraints": {},
158+
"policies": {},
159+
"checkConstraints": {},
160+
"isRLSEnabled": false
161+
}
162+
},
163+
"enums": {},
164+
"schemas": {},
165+
"sequences": {},
166+
"roles": {},
167+
"policies": {},
168+
"views": {},
169+
"_meta": {
170+
"columns": {},
171+
"schemas": {},
172+
"tables": {}
173+
}
174+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"version": "7",
3+
"dialect": "postgresql",
4+
"entries": [
5+
{
6+
"idx": 0,
7+
"version": "7",
8+
"when": 1733794040374,
9+
"tag": "0000_dark_zeigeist",
10+
"breakpoints": true
11+
}
12+
]
13+
}

app/functions/auth.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Hono } from "hono";
2+
import { handle } from "hono/aws-lambda";
3+
import { trimTrailingSlash } from "hono/trailing-slash";
4+
import { z } from "zod";
5+
import { zValidator } from "@hono/zod-validator";
6+
import { client } from "integrations/slack/client";
7+
import { Resource } from "sst";
8+
import { RedirectStatusCode, StatusCode } from "hono/utils/http-status";
9+
10+
const routes = new Hono().all("*", async (c) => {
11+
const url = `http://localhost:3000${c.req.path}?${new URLSearchParams(c.req.query()).toString()}`;
12+
const res = await fetch(url, {
13+
method: c.req.method,
14+
headers: c.req.raw.headers,
15+
body: c.req.raw.body,
16+
});
17+
18+
// Handle redirects by returning redirect response
19+
if (res.status >= 300 && res.status < 400) {
20+
const location = res.headers.get("Location");
21+
if (location) {
22+
return c.redirect(location, res.status as RedirectStatusCode);
23+
}
24+
}
25+
26+
const body = await res.arrayBuffer();
27+
return c.body(body, res.status as StatusCode, Object.fromEntries(res.headers.entries()));
28+
});
29+
// .get(
30+
// "/auth/slack/oauth_redirect",
31+
// zValidator("query", z.object({ code: z.string(), state: z.string().optional() })),
32+
// async (c) => {
33+
// const { code } = c.req.valid("query");
34+
// console.log(code);
35+
// const response = await client.oauth.v2.access({
36+
// code: code,
37+
// client_id: Resource.SlackClientId.value,
38+
// client_secret: Resource.SlackClientSecret.value,
39+
// redirect_uri:
40+
// "https://pjhqiendzsqsqjb64jzome2c6u0tfdnx.lambda-url.us-east-1.on.aws/api/auth/slack/oauth_redirect",
41+
// });
42+
// console.log(response);
43+
// const identity = await client.users.profile.get({
44+
// token: response.authed_user?.access_token,
45+
// });
46+
// console.log(identity);
47+
// return c.json(response);
48+
// },
49+
// );
50+
51+
const api = new Hono()
52+
.use(trimTrailingSlash())
53+
.route("/api", routes)
54+
.get("/ping", async (c) => {
55+
console.log("ping");
56+
return c.body("pong");
57+
})
58+
.notFound((c) => {
59+
console.log("not found", c.req.url);
60+
return c.notFound();
61+
});
62+
63+
export type ApiRoutes = typeof routes;
64+
export const handler = handle(api);

0 commit comments

Comments
 (0)