DINO
DINO
Explore posts from servers
RReactiflux
Created by DINO on 11/13/2024 in #react-forum
How do I handle authentication state in a SPA react app?
Hello, I have implemented authentication in my backend that uses http only cookies, so now I am not sure how do I handle authentication state in a SPA react app. When the user logs in I would like to store the auth state in a store like React Context or Zustand, but what if the user closes the app and opens it again? Should I hit an API route like getUser every time he opens it and if it returns the user that means he is sill logged in? Should I use Provider component (React Context) that wraps the whole app that checks the API? I would like to use a HashRouter instead of a BrowserRouter in my app. Thanks.
5 replies
TTCTheo's Typesafe Cult
Created by DINO on 11/1/2024 in #questions
Hello how do I do authentication without Next-Auth or any other auth library?
Hello, I would like implement a session based authentication in my t3 app but without Next-Auth or any auth library, this might be a dumb question but I really don't know where to start. I know how to do it using Express, or Fastify though but i don't how to do with this stack and tempalte, is it using Express behind the scenes so I need to use express-session or what. Thanks.
10 replies
TtRPC
Created by DINO on 10/7/2024 in #❓-help
Migrating to v11 problem: 'reactQueryContext' does not exist in type 'CreateTRPCReactOptions
Hello, When I upgraded to v11, I got this error that I didn't know how to solve it.
Object literal may only specify known properties, and 'reactQueryContext' does not exist in type 'CreateTRPCReactOptions<BuiltRouter<{ ctx: { req: fastify.FastifyRequest<fastify.RouteGenericInterface, fastify.RawServerDefault, IncomingMessage, fastify.FastifySchema, fastify.FastifyTypeProviderDefault, unknown, fastify.FastifyBaseLogger, fastify_types_type_provider.ResolveFastifyRequestType<fastify.FastifyTypePro...'.
Object literal may only specify known properties, and 'reactQueryContext' does not exist in type 'CreateTRPCReactOptions<BuiltRouter<{ ctx: { req: fastify.FastifyRequest<fastify.RouteGenericInterface, fastify.RawServerDefault, IncomingMessage, fastify.FastifySchema, fastify.FastifyTypeProviderDefault, unknown, fastify.FastifyBaseLogger, fastify_types_type_provider.ResolveFastifyRequestType<fastify.FastifyTypePro...'.
This is my code:
export const contextZS = createContext<QueryClient | undefined>(undefined)

export const trpcReact = createTRPCReact<AppRouter>()
export const trpcReactZS = createTRPCReact<AppRouterZS>({
context: createContext(null),
reactQueryContext: contextZS
})
export const contextZS = createContext<QueryClient | undefined>(undefined)

export const trpcReact = createTRPCReact<AppRouter>()
export const trpcReactZS = createTRPCReact<AppRouterZS>({
context: createContext(null),
reactQueryContext: contextZS
})
I would really appreciate any help. Thanks.
2 replies
RReactiflux
Created by DINO on 9/29/2024 in #react-forum
I would like implement multiple tabs navigation inside my React app, where do I start?
No description
12 replies
TtRPC
Created by DINO on 9/1/2024 in #❓-help
How do I create a React/Node full-stack project with tRPC?
No description
9 replies
TtRPC
Created by DINO on 7/27/2024 in #❓-help
How do I implement API key authorization along with JWT authorization in tRPC?
Hello, I want to make some routes protected and to be accessed by either JWT auth or by API keys auth. So I check both auth methods in the same context. To make things clear i will just share the code of my context:
export async function createContext({ req, res }: CreateFastifyContextOptions) {
async function getUser() {
try {
const apiKey = req.headers['x-api-key']

if (apiKey) {
if (typeof apiKey !== 'string') {
throw new TRPCError({ code: 'BAD_REQUEST', message: 'Invalid API key' })
}
const isValid = await validateApiKey(apiKey)
return {
user: null,
isAuthorized: isValid
}
} else {
await req.jwtVerify()
const em = orm.em.fork()
const user = await em.findOne(User, { _id: new ObjectId(req.user.id) })

if (!user) return null
const u = wrap(user).toPOJO()
return {
user: u,
isAuthorized: true
}
}
} catch (err) {
console.log('Error getting user from header or cookie', err)
return null
}
}

const user = await getUser()

return {
req,
res,
user
}
}
export async function createContext({ req, res }: CreateFastifyContextOptions) {
async function getUser() {
try {
const apiKey = req.headers['x-api-key']

if (apiKey) {
if (typeof apiKey !== 'string') {
throw new TRPCError({ code: 'BAD_REQUEST', message: 'Invalid API key' })
}
const isValid = await validateApiKey(apiKey)
return {
user: null,
isAuthorized: isValid
}
} else {
await req.jwtVerify()
const em = orm.em.fork()
const user = await em.findOne(User, { _id: new ObjectId(req.user.id) })

if (!user) return null
const u = wrap(user).toPOJO()
return {
user: u,
isAuthorized: true
}
}
} catch (err) {
console.log('Error getting user from header or cookie', err)
return null
}
}

const user = await getUser()

return {
req,
res,
user
}
}
I am using Fastify.js. What do you think of this approach? Thanks.
2 replies
TTCTheo's Typesafe Cult
Created by DINO on 7/17/2024 in #questions
Uploadthing error "An error occured while parsing input/output" when I try to upload with Insomnia
No description
20 replies
TtRPC
Created by DINO on 6/30/2024 in #❓-help
Is to possible to update the trpc client url?
Hello, I have create my trpc client this way:
trpcClientZS = trpcReactZS.createClient({
links: [
httpBatchLink({
url: `http://192.168.1.2:3000/trpc`,
fetch(url, options) {
return fetch(url, {
...options,
credentials: 'include'
})
},
})
],
transformer: SuperJSON
})
trpcClientZS = trpcReactZS.createClient({
links: [
httpBatchLink({
url: `http://192.168.1.2:3000/trpc`,
fetch(url, options) {
return fetch(url, {
...options,
credentials: 'include'
})
},
})
],
transformer: SuperJSON
})
Is there a way i can change the url in the httpBatchLink when the app is running? I tried to create and override the old instance but it didn't work. Thanks.
2 replies
TtRPC
Created by DINO on 5/23/2024 in #❓-help
How do I set header value from localStorage or Zustand in tRPC and React?
Hello, This is my tRPC client in my App.tsx:
function App(): JSX.Element {
const { token } = useAuthStore()
const [trpcClient] = useState(() =>
trpcReact.createClient({
links: [
httpBatchLink({
url: 'http://192.168.1.17:3000/trpc',
fetch(url, options) {
return fetch(url, {
...options,
credentials: 'include'
})
},
headers: () => {
return {
Authorization: `Bearer ${token || ''}`
}
}
})
],
transformer: SuperJSON
})
)
function App(): JSX.Element {
const { token } = useAuthStore()
const [trpcClient] = useState(() =>
trpcReact.createClient({
links: [
httpBatchLink({
url: 'http://192.168.1.17:3000/trpc',
fetch(url, options) {
return fetch(url, {
...options,
credentials: 'include'
})
},
headers: () => {
return {
Authorization: `Bearer ${token || ''}`
}
}
})
],
transformer: SuperJSON
})
)
The problem is if the jwt token changes, it doesn't get changed in the trpcClient unless I do something like this but I don't like it:
useEffect(() => {
if (token)
setTRPCClientZS(
trpcReactZS.createClient({
links: [
httpBatchLink({
url: 'http://192.168.1.17:3000/trpc',
fetch(url, options) {
return fetch(url, {
...options,
credentials: 'include'
})
},
headers: {
Authorization: `Bearer ${token}`
}
})
],
transformer: SuperJSON
})
)
}, [token])
useEffect(() => {
if (token)
setTRPCClientZS(
trpcReactZS.createClient({
links: [
httpBatchLink({
url: 'http://192.168.1.17:3000/trpc',
fetch(url, options) {
return fetch(url, {
...options,
credentials: 'include'
})
},
headers: {
Authorization: `Bearer ${token}`
}
})
],
transformer: SuperJSON
})
)
}, [token])
What is the best way to set jwt to trpc client?
2 replies
TtRPC
Created by DINO on 4/24/2024 in #❓-help
What do you guys think about the approach of importing/exporting tRPC types to be used in separate B
Hello, I was looking for a way to share tRPC API between multiple electron apps, I thought first about using a Nx monorepo but it turned out it's almost impossible to make it work with electron app that use electron-vite. After more research I found this repo: https://github.com/mkosir/trpc-api-boilerplate What I understood from this approach is you export the types of the tRPC server with all db types from the backend repo and you import them in any other -frontend- repo using GitHub API (Octokit). Is this approach common in general programming environments and what do you think about it? Thanks.
2 replies
RReactiflux
Created by DINO on 4/14/2024 in #react-forum
How do I query data with Tanstack Query if one of the query params can be undefined.
Hello, I have an id variable that can be undefined because I get him from useParams, and I use the id value to query data with Tanstack Query, but Tanstack Query requires to have a value that cannot be undefined which is very logical. So I had to do Number(id) || 1 and enabled: !!id this way:
const { id } = useParams() // const id: string | undefined
const { data: counterSale } = trpcReact.counterSale.get.useQuery(Number(id) || 1, {
enabled: !!id
})
const { id } = useParams() // const id: string | undefined
const { data: counterSale } = trpcReact.counterSale.get.useQuery(Number(id) || 1, {
enabled: !!id
})
Is this a common practice? And is there any other way to do this? Thanks.
4 replies
RReactiflux
Created by DINO on 4/5/2024 in #react-forum
Make Zustand store scalable
Hello, This is my Zustand store state type:
type WaitlistState = {
counterSaleWaitlist: CounterSaleWaitlistItemType[]
salesInvoiceWaitlist: SalesInvoiceWaitlistItemType[]
purchaseInvoiceWaitlist: PurchaseInvoiceWaitlistItemType[]
addCounterSaleItem: (data: CounterSaleWaitlistItemType['data']) => void
addSalesInvoiceItem: (data: SalesInvoiceWaitlistItemType['data']) => void
addPurchaseInvoiceItem: (data: PurchaseInvoiceWaitlistItemType['data']) => void
deleteItem: (date: string) => void
deleteList: (
list: 'counterSaleWaitlist' | 'salesInvoiceWaitlist' | 'purchaseInvoiceWaitlist'
) => void
deleteAll: () => void
}
type WaitlistState = {
counterSaleWaitlist: CounterSaleWaitlistItemType[]
salesInvoiceWaitlist: SalesInvoiceWaitlistItemType[]
purchaseInvoiceWaitlist: PurchaseInvoiceWaitlistItemType[]
addCounterSaleItem: (data: CounterSaleWaitlistItemType['data']) => void
addSalesInvoiceItem: (data: SalesInvoiceWaitlistItemType['data']) => void
addPurchaseInvoiceItem: (data: PurchaseInvoiceWaitlistItemType['data']) => void
deleteItem: (date: string) => void
deleteList: (
list: 'counterSaleWaitlist' | 'salesInvoiceWaitlist' | 'purchaseInvoiceWaitlist'
) => void
deleteAll: () => void
}
In the future I will add more invoices (up to 10), and I kind of don't like doing something like:
counterSaleWaitlist: CounterSaleWaitlistItemType[]
salesInvoiceWaitlist: SalesInvoiceWaitlistItemType[]
purchaseInvoiceWaitlist: PurchaseInvoiceWaitlistItemType[]
xInvoiceWaitlist: XInvoiceWaitlistItemType[]
yInvoiceWaitlist: YInvoiceWaitlistItemType[]
zInvoiceWaitlist: ZInvoiceWaitlistItemType[]
addCounterSaleItem: (data: CounterSaleWaitlistItemType['data']) => void
addSalesInvoiceItem: (data: SalesInvoiceWaitlistItemType['data']) => void
addPurchaseInvoiceItem: (data: PurchaseInvoiceWaitlistItemType['data']) => void
addPurchaseX: (data: XInvoiceWaitlistItemType['data']) => void
addPurchaseY: (data: YInvoiceWaitlistItemType['data']) => void
addPurchaseZ: (data: ZInvoiceWaitlistItemType['data']) => void
// ...
counterSaleWaitlist: CounterSaleWaitlistItemType[]
salesInvoiceWaitlist: SalesInvoiceWaitlistItemType[]
purchaseInvoiceWaitlist: PurchaseInvoiceWaitlistItemType[]
xInvoiceWaitlist: XInvoiceWaitlistItemType[]
yInvoiceWaitlist: YInvoiceWaitlistItemType[]
zInvoiceWaitlist: ZInvoiceWaitlistItemType[]
addCounterSaleItem: (data: CounterSaleWaitlistItemType['data']) => void
addSalesInvoiceItem: (data: SalesInvoiceWaitlistItemType['data']) => void
addPurchaseInvoiceItem: (data: PurchaseInvoiceWaitlistItemType['data']) => void
addPurchaseX: (data: XInvoiceWaitlistItemType['data']) => void
addPurchaseY: (data: YInvoiceWaitlistItemType['data']) => void
addPurchaseZ: (data: ZInvoiceWaitlistItemType['data']) => void
// ...
Are there any common practices to handle such a thing? Thanks.
10 replies
TtRPC
Created by DINO on 2/19/2024 in #❓-help
useMutation() runs 3 times
Hello, I have this weird problem that all my mutations across the app runs 3 times I don't know why. This is my API in the backend:
import { initTRPC } from '@trpc/server'
import superjson from 'superjson'

import routers from './routers'
import { brandFormSchema } from './zod-schemas'

const t = initTRPC.create({ isServer: true, transformer: superjson })

export const router = t.router({
...routers
})

export type AppRouter = typeof router
import { initTRPC } from '@trpc/server'
import superjson from 'superjson'

import routers from './routers'
import { brandFormSchema } from './zod-schemas'

const t = initTRPC.create({ isServer: true, transformer: superjson })

export const router = t.router({
...routers
})

export type AppRouter = typeof router
And this is how I use them in the client:
import { notifications } from '@mantine/notifications'
import { trpcReact } from '@renderer/util/trpc'

import BrandForm from './brand-form'

type Props = {
onCreated: () => void
onCancel: () => void
}

function CreateBrand({ onCreated, onCancel }: Props): JSX.Element {
const utils = trpcReact.useUtils()

const { mutate, isLoading } = trpcReact.brand.create.useMutation({
onSuccess: (): void => {
utils.brand.all.invalidate()
notifications.show({
message: 'Added brand successfully!',
color: 'green'
})
},
onError: (error): void => {
notifications.show({
message: 'Brand not added!' + error,
color: 'red'
})
}
})

return (
<BrandForm
loading={isLoading}
submitHandler={(values): void => {
mutate(values)
onCreated()
}}
cancelHandler={(): void => {
onCancel()
}}
/>
)
}

export default CreateBrand
import { notifications } from '@mantine/notifications'
import { trpcReact } from '@renderer/util/trpc'

import BrandForm from './brand-form'

type Props = {
onCreated: () => void
onCancel: () => void
}

function CreateBrand({ onCreated, onCancel }: Props): JSX.Element {
const utils = trpcReact.useUtils()

const { mutate, isLoading } = trpcReact.brand.create.useMutation({
onSuccess: (): void => {
utils.brand.all.invalidate()
notifications.show({
message: 'Added brand successfully!',
color: 'green'
})
},
onError: (error): void => {
notifications.show({
message: 'Brand not added!' + error,
color: 'red'
})
}
})

return (
<BrandForm
loading={isLoading}
submitHandler={(values): void => {
mutate(values)
onCreated()
}}
cancelHandler={(): void => {
onCancel()
}}
/>
)
}

export default CreateBrand
I am sure that the call from the client doesn't run 3 times. I checked it with console.log. I would be grateful if anyone helped. THanks.
14 replies