"use client" import { createJazzReactApp } from "jazz-react" import { LaAccount } from "@/lib/schema" import { useClerk } from "@clerk/nextjs" import { createContext, useMemo, useState } from "react" import { AuthMethodCtx } from "jazz-react" const Jazz = createJazzReactApp({ AccountSchema: LaAccount }) export const { useAccount, useCoState, useAcceptInvite } = Jazz export function JazzProvider({ children }: { children: React.ReactNode }) { return {children} } export const JazzClerkAuthCtx = createContext<{ errors: string[] }>({ errors: [] }) export function JazzClerkAuth({ children }: { children: React.ReactNode }) { const clerk = useClerk() const [errors, setErrors] = useState([]) const authMethod = useMemo(() => { return new BrowserClerkAuth( { onError: error => { void clerk.signOut() setErrors(errors => [...errors, error.toString()]) } }, clerk ) }, [clerk]) return ( {children} ) } import { Account, AuthMethod, AuthResult, ID } from "jazz-tools" import type { LoadedClerk } from "@clerk/types" import { AgentSecret } from "cojson" export class BrowserClerkAuth implements AuthMethod { constructor( public driver: BrowserClerkAuth.Driver, private readonly clerkClient: LoadedClerk ) {} async start(): Promise { if (this.clerkClient.user) { const storedCredentials = this.clerkClient.user.unsafeMetadata if (storedCredentials.jazzAccountID) { if (!storedCredentials.jazzAccountSecret) { throw new Error("No secret for existing user") } return { type: "existing", credentials: { accountID: storedCredentials.jazzAccountID as ID, secret: storedCredentials.jazzAccountSecret as AgentSecret }, onSuccess: () => {}, onError: (error: string | Error) => { this.driver.onError(error) } } } else { return { type: "new", creationProps: { name: this.clerkClient.user.fullName || this.clerkClient.user.username || this.clerkClient.user.id }, saveCredentials: async (credentials: { accountID: ID; secret: AgentSecret }) => { await this.clerkClient.user?.update({ unsafeMetadata: { jazzAccountID: credentials.accountID, jazzAccountSecret: credentials.secret } }) }, onSuccess: () => {}, onError: (error: string | Error) => { this.driver.onError(error) } } } } else { throw new Error("Not signed in") } } } export namespace BrowserClerkAuth { export interface Driver { onError: (error: string | Error) => void } }