https://github.com/imrea/cf-worker-react-router-prisma-rpc-poc
https://github.com/imrea/cf-worker-react-router-prisma-rpc-poc
cloudflare cloudflare-vite-plugin d1 prisma react-router rpc vite worker
Last synced: 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/imrea/cf-worker-react-router-prisma-rpc-poc
- Owner: imrea
- Created: 2025-05-06T17:51:45.000Z (5 months ago)
- Default Branch: master
- Last Pushed: 2025-05-09T17:25:53.000Z (5 months ago)
- Last Synced: 2025-05-11T16:54:25.731Z (5 months ago)
- Topics: cloudflare, cloudflare-vite-plugin, d1, prisma, react-router, rpc, vite, worker
- Language: TypeScript
- Homepage:
- Size: 167 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Worker + D1 + RPC + React Router + Prisma + Vite + Cloudflare Vite Plugin + Wrangler
[]()
A little POC setup with Vite and TurboRepo to demonstrate a decoupled architecture built with all these great tools.
The goal was to create an Object Capability Model, where instead of passing authentication info / tokens, an implicit capabability or collection of available capabilites is returned.
This provides typesafety, simplifies explicit permission checking, and executing processes that could throw due to lack of permissions.### Spinning up
Install dependencies in `root`:
```sh
pnpm i
```Set up and seed D1 from `workers/api`:
```sh
cd workers/api && pnpm db:reset
```Spin up dev server from `workers/app`:
```sh
cd ../app && pnpm dev
```Open [http://localhost:5173/](http://localhost:5173/) and check Terminal console logs. You should see something like
```
Hello from Public scope
Hello, sc9n9sdblnwv5ibcvcu0o9bf, from Private scope.
There are 2 Users
Is admin: false
```### Example
Consider an authenticated User with a role of "user" and a functionality of deleting any user from a database for which an "admin" role is expected
A theoretical flow with traditional API/Rest approach would look something this:
```ts
try {
await fetch('/api/user/123', {
method: 'DELETE',
headers: { Authorization: 'Bearer ' },
})
console.log('User is deleted')
} catch (error) {
if (error.status === 403)
console.log('You are not an admin, deleting users is not allowed')
else console.log('Something else went wrong')
}
```With Object Capabilities, it could be solved something like this:
```ts
// A user object after authentication, which the API service
// will use to built the capabilities
let user = { name: 'John', role: 'user', id: '...' }/**
* Obtain a proper RPC Stub, implicitly representing actions
* available as per the user's role/permissions/etc.
* The RPC Stub might look something like this:
*
* {
* deleteUser?: (userId: string) => Promise
* }
*
*/
let api = API.authorize(user)// `deleteUser` method might not be available, it's existence
// in itself denotes the cabability
await api.deleteUser?.('123')
console.log('User is deleted') // If the capability is present, otherwise failing silently// OR we can check for explicit permissions too
if (!api.deleteUser)
throw new Response('You are not an admin, deleting users is not allowed', {
status: 403,
})await api.deleteUser('123')
console.log('User is deleted')
```### Gotchas
- A refined version of Prisma Migrate is still in Early Access, and `diff` lacks finegrained support for D1 (eg. when location differs from a local `.wrangler` folder). I'm symlinking the shared root-level `.wrangler` folder now.
- The POC still uses the `prisma-client-js` generator for Prisma Client, which will be replaced by a more modular and "bundler-friendly" `prisma-client` in the next major version. Currently generating such client source code depends on importing the `wasm` query engine from `@prisma/client`, which is improperly resolved by Vite. There are also some improper paths/types generated. Although there might be some workarounds (hacking with `resolve` configs, handwritten custom Vite plugin, etc.), bugs are still expected, as this feature is in Early Access too.
- A custom output path has to be provided for `@prisma/client`, the default destination has Vite resolver issues too, that's why the `@prisma/client-generated` is used. (Currently `output` is optional, but will be required indeed in further Prisma releases.)