auth.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { useSession } from "vinxi/http"
  2. import { createClient } from "@openauthjs/openauth/client"
  3. import { getRequestEvent } from "solid-js/web"
  4. import { and, Database, eq, inArray } from "@opencode/cloud-core/drizzle/index.js"
  5. import { WorkspaceTable } from "@opencode/cloud-core/schema/workspace.sql.js"
  6. import { UserTable } from "@opencode/cloud-core/schema/user.sql.js"
  7. import { query, redirect } from "@solidjs/router"
  8. import { AccountTable } from "@opencode/cloud-core/schema/account.sql.js"
  9. import { Actor } from "@opencode/cloud-core/actor.js"
  10. export async function withActor<T>(fn: () => T) {
  11. const actor = await getActor()
  12. return Actor.provide(actor.type, actor.properties, fn)
  13. }
  14. export const getActor = query(async (): Promise<Actor.Info> => {
  15. "use server"
  16. const evt = getRequestEvent()
  17. const url = new URL(evt!.request.headers.get("referer") ?? evt!.request.url)
  18. const auth = await useAuthSession()
  19. const [workspaceHint] = url.pathname.split("/").filter((x) => x.length > 0)
  20. console.log("here1")
  21. if (!workspaceHint) {
  22. console.log("here2")
  23. if (auth.data.current) {
  24. console.log("here3")
  25. const current = auth.data.account[auth.data.current]
  26. return {
  27. type: "account",
  28. properties: {
  29. email: current.email,
  30. accountID: current.id,
  31. },
  32. }
  33. }
  34. if (Object.keys(auth.data.account ?? {}).length > 0) {
  35. const current = Object.values(auth.data.account)[0]
  36. await auth.update(val => ({
  37. ...val,
  38. current: current.id,
  39. }))
  40. return {
  41. type: "account",
  42. properties: {
  43. email: current.email,
  44. accountID: current.id,
  45. },
  46. }
  47. }
  48. return {
  49. type: "public",
  50. properties: {},
  51. }
  52. }
  53. const accounts = Object.keys(auth.data.account)
  54. const result = await Database.transaction(async (tx) => {
  55. return await tx.select({
  56. user: UserTable
  57. })
  58. .from(AccountTable)
  59. .innerJoin(UserTable, and(eq(UserTable.email, AccountTable.email)))
  60. .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, UserTable.workspaceID))
  61. .where(
  62. and(
  63. inArray(AccountTable.id, accounts),
  64. eq(WorkspaceTable.id, workspaceHint),
  65. )
  66. )
  67. .limit(1)
  68. .execute()
  69. .then((x) => x[0])
  70. })
  71. if (result) {
  72. return {
  73. type: "user",
  74. properties: {
  75. userID: result.user.id,
  76. workspaceID: result.user.workspaceID,
  77. },
  78. }
  79. }
  80. throw redirect("/auth/authorize")
  81. }, "actor")
  82. export const AuthClient = createClient({
  83. clientID: "app",
  84. issuer: import.meta.env.VITE_AUTH_URL,
  85. })
  86. export interface AuthSession {
  87. account: Record<string, {
  88. id: string
  89. email: string
  90. }>
  91. current?: string
  92. }
  93. export function useAuthSession() {
  94. return useSession<AuthSession>({
  95. password: "0".repeat(32),
  96. name: "auth",
  97. })
  98. }
  99. export function AuthProvider() {
  100. }