Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions playgrounds/astro/src/middlewares/auth.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { User } from '../schemas/user'
import { os } from '@orpc/server'
import { ORPCError, os } from '@orpc/server'

export const requiredAuthMiddleware = os
.$context<{ session?: { user?: User } }>()
.middleware(async ({ context, next }) => {
if (!context.session || !context.session.user) {
throw new Error('UNAUTHORIZED')
throw new ORPCError('UNAUTHORIZED')
}

return next({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { User } from '../schemas/user'
import { os } from '@orpc/server'
import { ORPCError, os } from '@orpc/server'

export const requiredAuthMiddleware = os
.$context<{ session?: { user?: User } }>()
Expand All @@ -12,7 +12,7 @@ export const requiredAuthMiddleware = os
const session = context.session ?? await getSession()

if (!session.user) {
throw new Error('UNAUTHORIZED')
throw new ORPCError('UNAUTHORIZED')
}

return next({
Expand Down
6 changes: 6 additions & 0 deletions playgrounds/cloudflare-worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
"@cloudflare/vite-plugin": "^1.9.6",
"@orpc/client": "next",
"@orpc/experimental-durable-event-iterator": "next",
"@orpc/json-schema": "next",
"@orpc/openapi": "next",
"@orpc/server": "next",
"@orpc/tanstack-query": "next",
"@orpc/zod": "next",
"@scalar/api-reference-react": "^0.7.34",
"@tanstack/react-query": "^5.83.0",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.5",
"@vitejs/plugin-react": "^4.6.0",
Expand Down
31 changes: 29 additions & 2 deletions playgrounds/cloudflare-worker/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
import { ChatRoom } from './components/chat-room'
import { CreatePlanetMutationForm } from './components/orpc-mutation'
import { ListPlanetsQuery } from './components/orpc-query'
import '@scalar/api-reference-react/style.css'
import { ApiReferenceReact } from '@scalar/api-reference-react'

export default function App() {
if (location.pathname === '/api') {
return (
<ApiReferenceReact
configuration={{
url: '/api/spec.json',
}}
/>
)
}

return (
<div>
<main>
<h1>ORPC Playground</h1>
<p>
You can visit the
{' '}
<a href="/api">Scalar API Reference</a>
{' '}
page.
</p>
<hr />
<CreatePlanetMutationForm />
<hr />
<ListPlanetsQuery />
<hr />
<ChatRoom />
</div>
</main>
)
}
8 changes: 5 additions & 3 deletions playgrounds/cloudflare-worker/src/components/chat-room.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { client } from '../lib/orpc'

export function ChatRoom() {
const [messages, setMessages] = useState<string[]>([])
const [iterator, setIterator] = useState<Awaited<ReturnType<typeof client.onMessage>> | null>(null)
const [iterator, setIterator] = useState<Awaited<ReturnType<typeof client.message.on>> | null>(null)

useEffect(() => {
const controller = new AbortController()

void (async () => {
const iterator = await client.onMessage(undefined, { signal: controller.signal })
const iterator = await client.message.on(undefined, { signal: controller.signal })
setIterator(iterator)

for await (const message of iterator) {
Expand All @@ -28,7 +28,9 @@ export function ChatRoom() {
const form = new FormData(e.target as HTMLFormElement)
const message = form.get('message') as string

await client.sendMessage({ message })
await client.message.send({ message })
// or ---
// await iterator?.publishMessageRPC({ message })
}

return (
Expand Down
58 changes: 58 additions & 0 deletions playgrounds/cloudflare-worker/src/components/orpc-mutation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { orpc } from '../lib/orpc'

export function CreatePlanetMutationForm() {
const queryClient = useQueryClient()

const { mutate } = useMutation(
orpc.planet.create.mutationOptions({
onSuccess() {
queryClient.invalidateQueries({
queryKey: orpc.planet.key(),
})
},
onError(error) {
console.error(error)
alert(error.message)
},
Comment thread
dinwwwh marked this conversation as resolved.
}),
)
Comment thread
dinwwwh marked this conversation as resolved.

return (
<div>
<h2>oRPC and Tanstack Query | Create Planet example</h2>

<form
onSubmit={(e) => {
e.preventDefault()
const form = new FormData(e.target as HTMLFormElement)

const name = form.get('name') as string
const description
= (form.get('description') as string | null) ?? undefined
Comment thread
dinwwwh marked this conversation as resolved.
const image = form.get('image') as File

mutate({
name,
description,
image: image.size > 0 ? image : undefined,
Comment thread
dinwwwh marked this conversation as resolved.
})
}}
>
<label>
Name
<input type="text" name="name" required />
</label>
<label>
Description
<textarea name="description" />
</label>
<label>
Image
<input type="file" name="image" accept="image/*" />
</label>
<button type="submit">Submit</button>
</form>
</div>
)
}
68 changes: 68 additions & 0 deletions playgrounds/cloudflare-worker/src/components/orpc-query.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useSuspenseInfiniteQuery } from '@tanstack/react-query'
import { orpc } from '../lib/orpc'

export function ListPlanetsQuery() {
const { data, refetch, fetchNextPage, hasNextPage, status } = useSuspenseInfiniteQuery(
orpc.planet.list.infiniteOptions({
input: cursor => ({ cursor, limit: 10 }),
getNextPageParam: lastPage => lastPage.length === 10 ? lastPage.at(-1)?.id : null,
initialPageParam: 0,
}),
)

if (status === 'error') {
return (
<p>
Something went wrong.
</p>
)
}

return (
<div>
<h2>oRPC and Tanstack Query | List Planets example</h2>

<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>Image</th>
</tr>
</thead>
<tbody>
{data.pages.flatMap((page, i) =>
page.map(planet => (
<tr key={`${planet.id}-${i}`}>
<td>{planet.id}</td>
<td>{planet.name}</td>
<td>{planet.description}</td>
<td>{planet.imageUrl}</td>
</tr>
)),
)}
</tbody>

<tfoot>
<tr>
<td colSpan={4}>
<button
type="button"
onClick={() => fetchNextPage()}
disabled={!hasNextPage}
>
Load more
</button>

<button type="button" onClick={() => refetch()}>
Refresh
</button>
</td>
</tr>
</tfoot>
</table>
</div>

)
}
7 changes: 5 additions & 2 deletions playgrounds/cloudflare-worker/src/lib/orpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
import { DurableEventIteratorLinkPlugin } from '@orpc/experimental-durable-event-iterator/client'
import type { RouterClient } from '@orpc/server'
import type { router } from '../../worker'
import { createTanstackQueryUtils } from '@orpc/tanstack-query'
import type { router } from '../../worker/router'

const link = new RPCLink({
url: `${window.location.origin}`,
url: `${window.location.origin}/rpc`,
plugins: [
new DurableEventIteratorLinkPlugin({
url: `${window.location.origin}/chat-room`,
Expand All @@ -14,3 +15,5 @@ const link = new RPCLink({
})

export const client: RouterClient<typeof router> = createORPCClient(link)

export const orpc = createTanstackQueryUtils(client)
7 changes: 6 additions & 1 deletion playgrounds/cloudflare-worker/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

const queryClient = new QueryClient()

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</StrictMode>,
)
Loading