From a28ec68b09e16beb46da230a54d9abeec2e5a30c Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 10:52:10 +0200 Subject: [PATCH 1/9] document -> render --- docs/src/content/docs/core/routing.mdx | 11 +++++------ docs/src/content/docs/core/security.mdx | 2 +- .../content/docs/getting-started/first-project.mdx | 4 ++-- docs/src/content/docs/reference/routing.mdx | 8 ++++---- experiments/ai-stream/src/worker.tsx | 4 ++-- experiments/billable/src/worker.tsx | 4 ++-- experiments/cutable/src/worker.tsx | 4 ++-- experiments/realtime-poc/src/worker.tsx | 4 ++-- experiments/yt-dos/src/worker.tsx | 4 ++-- experiments/zoomshare/src/worker.tsx | 4 ++-- starters/drizzle/src/worker.tsx | 4 ++-- starters/minimal/src/worker.tsx | 4 ++-- starters/passkey-auth/src/worker.tsx | 4 ++-- starters/prisma/src/worker.tsx | 4 ++-- starters/sessions/src/worker.tsx | 4 ++-- starters/standard/src/worker.tsx | 4 ++-- 16 files changed, 36 insertions(+), 37 deletions(-) diff --git a/docs/src/content/docs/core/routing.mdx b/docs/src/content/docs/core/routing.mdx index 6c5f949c1..9d831033d 100644 --- a/docs/src/content/docs/core/routing.mdx +++ b/docs/src/content/docs/core/routing.mdx @@ -177,22 +177,21 @@ The `ctx` object: ## Documents -Documents are how you define the "shell" of your application's html: the ``, ``, `` tags, scripts, stylesheets, ``, and where in the `` your actual page content is rendered. In RedwoodSDK, documents are defined using the `document` function in `defineApp`. +Documents are how you define the "shell" of your application's html: the ``, ``, `` tags, scripts, stylesheets, ``, and where in the `` your actual page content is rendered. In RedwoodSDK, you tell it which document to use with the `render()` function in `defineApp`. In other words, you're asking RedwoodSDK to "render" the document. ```tsx title="src/worker.tsx" "document" import { defineApp } from "@redwoodjs/sdk/worker"; -import { route, document } from "@redwoodjs/sdk/router"; +import { route, render } from "@redwoodjs/sdk/router"; import { Document } from "@/pages/Document"; import { HomePage } from "@/pages/HomePage"; export default defineApp([ - document( - Document, [route("/", HomePage)] -)]); + render(Document, [route("/", HomePage)]) +]); --- -The `document` function takes a React component and an array of route handlers. The document will be applied to all the routes that are passed to it. +The `render` function takes a React component and an array of route handlers. The document will be applied to all the routes that are passed to it. This component will be rendered on the server side when the page loads. When defining this component, you'd add: * Your application's stylesheets and scripts diff --git a/docs/src/content/docs/core/security.mdx b/docs/src/content/docs/core/security.mdx index 9c3eb5e04..10623ff2c 100644 --- a/docs/src/content/docs/core/security.mdx +++ b/docs/src/content/docs/core/security.mdx @@ -75,7 +75,7 @@ export const Document = ({ rw, children }) => ( export default defineApp([ // ... - document(Document, [ + render(Document, [ // ... ]), ]); diff --git a/docs/src/content/docs/getting-started/first-project.mdx b/docs/src/content/docs/getting-started/first-project.mdx index 08451302d..517c7eaba 100644 --- a/docs/src/content/docs/getting-started/first-project.mdx +++ b/docs/src/content/docs/getting-started/first-project.mdx @@ -75,7 +75,7 @@ export default defineApp([ // setup ctx here ctx; }, - document(Document, [ + render(Document, [ index([ Home, ]), @@ -119,7 +119,7 @@ export default defineApp([ // setup ctx here ctx; }, - document(Document, [index([Home]), route("/about", About)]), + render(Document, [index([Home]), route("/about", About)]), ]); ``` diff --git a/docs/src/content/docs/reference/routing.mdx b/docs/src/content/docs/reference/routing.mdx index e8b277640..ce28c3855 100644 --- a/docs/src/content/docs/reference/routing.mdx +++ b/docs/src/content/docs/reference/routing.mdx @@ -180,7 +180,7 @@ By default, RedwoodSDK only renders your component's HTML without ``, ` @@ -245,13 +245,13 @@ Here's an example using both helpers: language="tsx" code={`\ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document, prefix } from "@redwoodjs/sdk/router"; +import { index, render, prefix } from "@redwoodjs/sdk/router"; import { authRoutes } from 'src/pages/auth/routes'; import { invoiceRoutes } from 'src/pages/invoice/routes'; import HomePage from 'src/pages/Home/HomePage'; export default defineApp([ - document(Document, [ + render(Document, [ // Define root route using index index([ HomePage, diff --git a/experiments/ai-stream/src/worker.tsx b/experiments/ai-stream/src/worker.tsx index 29e0e7057..089a1e9aa 100644 --- a/experiments/ai-stream/src/worker.tsx +++ b/experiments/ai-stream/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document } from "@redwoodjs/sdk/router"; +import { index, render } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import { Chat } from "src/pages/Chat/Chat"; import { setCommonHeaders } from "src/headers"; @@ -8,5 +8,5 @@ type Context = {}; export default defineApp([ setCommonHeaders(), - document(Document, [index([Chat])]), + render(Document, [index([Chat])]), ]); diff --git a/experiments/billable/src/worker.tsx b/experiments/billable/src/worker.tsx index c3e5d5554..de10e2e6c 100644 --- a/experiments/billable/src/worker.tsx +++ b/experiments/billable/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document, prefix } from "@redwoodjs/sdk/router"; +import { index, render, prefix } from "@redwoodjs/sdk/router"; import { ExecutionContext } from "@cloudflare/workers-types"; import { link } from "src/shared/links"; @@ -39,7 +39,7 @@ const app = defineApp([ setupSessionStore(env); ctx.user = await getUser(request); }, - document(Document, [ + render(Document, [ index([ ({ ctx }) => { if (ctx.user) { diff --git a/experiments/cutable/src/worker.tsx b/experiments/cutable/src/worker.tsx index af79c54d0..8c56f43ca 100644 --- a/experiments/cutable/src/worker.tsx +++ b/experiments/cutable/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document } from "@redwoodjs/sdk/router"; +import { index, render } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import HomePage from "src/pages/home/HomePage"; @@ -17,5 +17,5 @@ export default defineApp([ ctx.foo = 23; }, // @ts-ignore - document(Document, [index([HomePage])]), + render(Document, [index([HomePage])]), ]); diff --git a/experiments/realtime-poc/src/worker.tsx b/experiments/realtime-poc/src/worker.tsx index 9da6adbfd..354b19db1 100644 --- a/experiments/realtime-poc/src/worker.tsx +++ b/experiments/realtime-poc/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { route, document } from "@redwoodjs/sdk/router"; +import { route, render } from "@redwoodjs/sdk/router"; import { Document } from "@/app/Document"; import { setCommonHeaders } from "@/app/headers"; import { @@ -20,7 +20,7 @@ export type Context = {}; export default defineApp([ setCommonHeaders(), realtimeRoute((env) => env.REALTIME_DURABLE_OBJECT), - document(Document, [ + render(Document, [ route("/", () => { const randomName = uniqueNamesGenerator({ dictionaries: [adjectives, colors, animals], diff --git a/experiments/yt-dos/src/worker.tsx b/experiments/yt-dos/src/worker.tsx index 652607455..d3e609e3c 100644 --- a/experiments/yt-dos/src/worker.tsx +++ b/experiments/yt-dos/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document, route } from "@redwoodjs/sdk/router"; +import { index, render, route } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import { HomePage } from "src/pages/Home"; import { fetchYoutubeVideos } from "src/pages/serverFunctions"; @@ -13,7 +13,7 @@ export default defineApp([ ctx; }, // @ts-ignore - document(Document, [ + render(Document, [ index([HomePage]), route("/sitemap.xml", async () => { const sitemap = ` diff --git a/experiments/zoomshare/src/worker.tsx b/experiments/zoomshare/src/worker.tsx index 71a4b4dd5..e4a59cec3 100644 --- a/experiments/zoomshare/src/worker.tsx +++ b/experiments/zoomshare/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { document, prefix, route } from "@redwoodjs/sdk/router"; +import { render, prefix, route } from "@redwoodjs/sdk/router"; import { Document } from "@/app/Document"; import { authRoutes } from "@/app/pages/auth/routes"; import { Session } from "./session/durableObject"; @@ -41,7 +41,7 @@ const app = defineApp([ await setupDb(env); }, - document(Document, [ + render(Document, [ route("/", function () { return new Response("Hello World"); }), diff --git a/starters/drizzle/src/worker.tsx b/starters/drizzle/src/worker.tsx index 50c846541..92280ac3d 100644 --- a/starters/drizzle/src/worker.tsx +++ b/starters/drizzle/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document } from "@redwoodjs/sdk/router"; +import { index, render } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import { Home } from "src/pages/Home"; import { setCommonHeaders } from "src/headers"; @@ -19,5 +19,5 @@ export default defineApp([ // setup db in ctx ctx.db = drizzle(env.DB); }, - document(Document, [index([Home])]), + render(Document, [index([Home])]), ]); diff --git a/starters/minimal/src/worker.tsx b/starters/minimal/src/worker.tsx index 74d3679d4..28de27124 100644 --- a/starters/minimal/src/worker.tsx +++ b/starters/minimal/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document } from "@redwoodjs/sdk/router"; +import { index, render } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import { Home } from "src/pages/Home"; import { setCommonHeaders } from "src/headers"; @@ -12,5 +12,5 @@ export default defineApp([ // setup ctx here ctx; }, - document(Document, [index([Home])]), + render(Document, [index([Home])]), ]); diff --git a/starters/passkey-auth/src/worker.tsx b/starters/passkey-auth/src/worker.tsx index db5e5daf0..94c76bcfd 100644 --- a/starters/passkey-auth/src/worker.tsx +++ b/starters/passkey-auth/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp, ErrorResponse } from "@redwoodjs/sdk/worker"; -import { index, document, prefix } from "@redwoodjs/sdk/router"; +import { index, render, prefix } from "@redwoodjs/sdk/router"; import { Document } from "@/app/Document"; import { Home } from "@/app/pages/Home"; import { setCommonHeaders } from "@/app/headers"; @@ -45,7 +45,7 @@ export default defineApp([ }); } }, - document(Document, [ + render(Document, [ index([ ({ ctx }) => { if (!ctx.user) { diff --git a/starters/prisma/src/worker.tsx b/starters/prisma/src/worker.tsx index 548cbae0d..cc7ff9497 100644 --- a/starters/prisma/src/worker.tsx +++ b/starters/prisma/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp } from "@redwoodjs/sdk/worker"; -import { index, document } from "@redwoodjs/sdk/router"; +import { index, render } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import { Home } from "src/pages/Home"; import { setupDb } from "./db"; @@ -11,5 +11,5 @@ export default defineApp([ async ({ ctx, env, request }) => { await setupDb(env); }, - document(Document, [index([Home])]), + render(Document, [index([Home])]), ]); diff --git a/starters/sessions/src/worker.tsx b/starters/sessions/src/worker.tsx index e285004ba..482096d82 100644 --- a/starters/sessions/src/worker.tsx +++ b/starters/sessions/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp, ErrorResponse } from "@redwoodjs/sdk/worker"; -import { index, document, prefix } from "@redwoodjs/sdk/router"; +import { index, render, prefix } from "@redwoodjs/sdk/router"; import { Document } from "@/app/Document"; import { Home } from "@/app/pages/Home"; import { userRoutes } from "@/app/pages/user/routes"; @@ -32,5 +32,5 @@ export default defineApp([ } } }, - document(Document, [index([Home]), prefix("/user", userRoutes)]), + render(Document, [index([Home]), prefix("/user", userRoutes)]), ]); diff --git a/starters/standard/src/worker.tsx b/starters/standard/src/worker.tsx index a412a57dd..da5d50dc9 100644 --- a/starters/standard/src/worker.tsx +++ b/starters/standard/src/worker.tsx @@ -1,5 +1,5 @@ import { defineApp, ErrorResponse } from "@redwoodjs/sdk/worker"; -import { route, document, prefix } from "@redwoodjs/sdk/router"; +import { route, render, prefix } from "@redwoodjs/sdk/router"; import { Document } from "@/app/Document"; import { Home } from "@/app/pages/Home"; import { setCommonHeaders } from "@/app/headers"; @@ -45,7 +45,7 @@ export default defineApp([ }); } }, - document(Document, [ + render(Document, [ route("/", () => new Response("Hello, World!")), route("/protected", [ ({ ctx }) => { From 70a40a738f0bd598316f195793adabe814c353f3 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 10:56:46 +0200 Subject: [PATCH 2/9] AppContext --- docs/src/content/docs/core/security.mdx | 2 +- .../docs/getting-started/first-project.mdx | 4 +- experiments/ai-stream/src/worker.tsx | 4 +- .../app/pages/invoice/ListPage/functions.ts | 2 +- experiments/billable/src/worker.tsx | 4 +- .../app/pages/project/ListPage/functions.ts | 2 +- experiments/cutable/src/worker.tsx | 4 +- .../app/pages/project/ListPage/functions.ts | 23 ++++--- experiments/cutl/src/worker.tsx | 5 +- experiments/realtime-poc/src/worker.tsx | 4 +- experiments/yt-dos/src/worker.tsx | 4 +- .../src/app/pages/meetings/MeetingList.tsx | 2 +- experiments/zoomshare/src/worker.tsx | 4 +- sdk/src/runtime/lib/router.ts | 66 +++++++++---------- sdk/src/runtime/register/worker.ts | 4 +- sdk/src/runtime/worker.tsx | 8 +-- starters/drizzle/src/app/pages/Home.tsx | 4 +- starters/drizzle/src/worker.tsx | 4 +- starters/minimal/src/worker.tsx | 4 +- starters/passkey-auth/src/app/pages/Home.tsx | 2 +- starters/passkey-auth/src/worker.tsx | 4 +- starters/prisma/src/worker.tsx | 4 +- starters/sessions/src/app/pages/Home.tsx | 2 +- starters/sessions/src/worker.tsx | 4 +- starters/standard/src/app/pages/Home.tsx | 2 +- starters/standard/src/worker.tsx | 4 +- 26 files changed, 87 insertions(+), 89 deletions(-) diff --git a/docs/src/content/docs/core/security.mdx b/docs/src/content/docs/core/security.mdx index 10623ff2c..b7f76c1f2 100644 --- a/docs/src/content/docs/core/security.mdx +++ b/docs/src/content/docs/core/security.mdx @@ -73,7 +73,7 @@ export const Document = ({ rw, children }) => ( ); -export default defineApp([ +export default defineApp([ // ... render(Document, [ // ... diff --git a/docs/src/content/docs/getting-started/first-project.mdx b/docs/src/content/docs/getting-started/first-project.mdx index 517c7eaba..2f67c0883 100644 --- a/docs/src/content/docs/getting-started/first-project.mdx +++ b/docs/src/content/docs/getting-started/first-project.mdx @@ -70,7 +70,7 @@ import { Home } from 'src/pages/Home'; ... -export default defineApp([ +export default defineApp([ ({ ctx }) => { // setup ctx here ctx; @@ -114,7 +114,7 @@ You can add additional routes by: ```tsx import { About } from "src/pages/About"; -export default defineApp([ +export default defineApp([ ({ ctx }) => { // setup ctx here ctx; diff --git a/experiments/ai-stream/src/worker.tsx b/experiments/ai-stream/src/worker.tsx index 089a1e9aa..cf66bba87 100644 --- a/experiments/ai-stream/src/worker.tsx +++ b/experiments/ai-stream/src/worker.tsx @@ -4,9 +4,9 @@ import { Document } from "src/Document"; import { Chat } from "src/pages/Chat/Chat"; import { setCommonHeaders } from "src/headers"; -type Context = {}; +type AppContext = {}; -export default defineApp([ +export default defineApp([ setCommonHeaders(), render(Document, [index([Chat])]), ]); diff --git a/experiments/billable/src/app/pages/invoice/ListPage/functions.ts b/experiments/billable/src/app/pages/invoice/ListPage/functions.ts index ffefa1cfd..9438cddd4 100644 --- a/experiments/billable/src/app/pages/invoice/ListPage/functions.ts +++ b/experiments/billable/src/app/pages/invoice/ListPage/functions.ts @@ -1,7 +1,7 @@ "use server"; import { db } from "src/db"; -import { Context } from "../../../../worker"; +import { AppContext } from "../../../../worker"; // We need to pass the context to these somehow? export async function createInvoice({ ctx }: { ctx: Context }) { diff --git a/experiments/billable/src/worker.tsx b/experiments/billable/src/worker.tsx index de10e2e6c..ec4cfc756 100644 --- a/experiments/billable/src/worker.tsx +++ b/experiments/billable/src/worker.tsx @@ -12,7 +12,7 @@ import { sessions, setupSessionStore } from "./sessionStore"; export { SessionDO } from "./session"; -export type Context = { +export type AppContext = { user: Awaited>; }; @@ -33,7 +33,7 @@ export const getUser = async (request: Request) => { } }; -const app = defineApp([ +const app = defineApp([ async ({ request, ctx, env }) => { await setupDb(env); setupSessionStore(env); diff --git a/experiments/cutable/src/app/pages/project/ListPage/functions.ts b/experiments/cutable/src/app/pages/project/ListPage/functions.ts index ea65212f3..bce84a195 100644 --- a/experiments/cutable/src/app/pages/project/ListPage/functions.ts +++ b/experiments/cutable/src/app/pages/project/ListPage/functions.ts @@ -7,7 +7,7 @@ import { getContext } from "../../../../worker"; export async function createProject({ ctx, }: { - ctx: Awaited>; + ctx: Awaited>; }) { const userId = ctx.user.id; diff --git a/experiments/cutable/src/worker.tsx b/experiments/cutable/src/worker.tsx index 8c56f43ca..28598b776 100644 --- a/experiments/cutable/src/worker.tsx +++ b/experiments/cutable/src/worker.tsx @@ -5,11 +5,11 @@ import HomePage from "src/pages/home/HomePage"; export { SessionDO } from "./session"; -type Context = { +type AppContext = { foo: number; }; -export default defineApp([ +export default defineApp([ // >>> Replaces `getContext()` ({ ctx }: { ctx: Context }) => { // >>> You can do side effects (e.g, setup like `setupDb()`) here diff --git a/experiments/cutl/src/app/pages/project/ListPage/functions.ts b/experiments/cutl/src/app/pages/project/ListPage/functions.ts index 82a6101e3..bce84a195 100644 --- a/experiments/cutl/src/app/pages/project/ListPage/functions.ts +++ b/experiments/cutl/src/app/pages/project/ListPage/functions.ts @@ -1,15 +1,15 @@ -'use server'; - +"use server"; import { db } from "../../../../db"; import { getContext } from "../../../../worker"; - - // We need to pass the context to these somehow? -export async function createProject({ ctx }: { ctx: Awaited>}) { - - const userId = ctx.user.id +export async function createProject({ + ctx, +}: { + ctx: Awaited>; +}) { + const userId = ctx.user.id; const newProject = await db.project.create({ data: { @@ -22,15 +22,14 @@ export async function createProject({ ctx }: { ctx: Awaited> = { - user: { id: '', email: '' } + let ctx: Awaited> = { + user: { id: "", email: "" }, }; let session: Awaited> | undefined; try { diff --git a/experiments/realtime-poc/src/worker.tsx b/experiments/realtime-poc/src/worker.tsx index 354b19db1..54a54ffd2 100644 --- a/experiments/realtime-poc/src/worker.tsx +++ b/experiments/realtime-poc/src/worker.tsx @@ -15,9 +15,9 @@ import Note from "./app/pages/note/Note"; export { RealtimeDurableObject } from "@redwoodjs/sdk/realtime/durableObject"; export { NoteDurableObject } from "@/noteDurableObject"; -export type Context = {}; +export type AppContext = {}; -export default defineApp([ +export default defineApp([ setCommonHeaders(), realtimeRoute((env) => env.REALTIME_DURABLE_OBJECT), render(Document, [ diff --git a/experiments/yt-dos/src/worker.tsx b/experiments/yt-dos/src/worker.tsx index d3e609e3c..bba894367 100644 --- a/experiments/yt-dos/src/worker.tsx +++ b/experiments/yt-dos/src/worker.tsx @@ -3,11 +3,11 @@ import { index, render, route } from "@redwoodjs/sdk/router"; import { Document } from "src/Document"; import { HomePage } from "src/pages/Home"; import { fetchYoutubeVideos } from "src/pages/serverFunctions"; -type Context = { +type AppContext = { YT_API_KEY: string; }; -export default defineApp([ +export default defineApp([ ({ ctx }) => { // setup ctx here ctx; diff --git a/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx b/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx index 2221a4045..1c821b12c 100644 --- a/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx +++ b/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx @@ -1,4 +1,4 @@ -import type { Context } from "@/worker"; +import type { AppContext } from "@/worker"; import { db } from "@/db"; export async function MeetingList({ ctx }: { ctx: Context }) { diff --git a/experiments/zoomshare/src/worker.tsx b/experiments/zoomshare/src/worker.tsx index e4a59cec3..7ed7ff22a 100644 --- a/experiments/zoomshare/src/worker.tsx +++ b/experiments/zoomshare/src/worker.tsx @@ -10,7 +10,7 @@ export { SessionDurableObject } from "./session/durableObject"; import crypto from "node:crypto"; import { meetingRoutes } from "./app/pages/meetings/routes"; -export type Context = { +export type AppContext = { session: Session | null; user: User; }; @@ -36,7 +36,7 @@ async function validateZoomWebhook(body: any, env: Env) { } } -const app = defineApp([ +const app = defineApp([ async ({ env, ctx, request }) => { await setupDb(env); }, diff --git a/sdk/src/runtime/lib/router.ts b/sdk/src/runtime/lib/router.ts index 33375ec21..8076f4bdb 100644 --- a/sdk/src/runtime/lib/router.ts +++ b/sdk/src/runtime/lib/router.ts @@ -7,7 +7,7 @@ export type HandlerOptions> = { cf: ExecutionContext; ctx: TContext; headers: Headers; - rw: RwContext; + rw: RwContext; }; export type RouteOptions, TParams = any> = { @@ -17,38 +17,38 @@ export type RouteOptions, TParams = any> = { env: Env; ctx: TContext; headers: Headers; - rw: RwContext; + rw: RwContext; }; -export type PageProps = Omit< - RouteOptions, +export type PageProps = Omit< + RouteOptions, "request" | "headers" | "rw" | "cf" > & { rw: { nonce: string } }; -export type DocumentProps = PageProps & { +export type DocumentProps = PageProps & { children: React.ReactNode; }; -export type RenderPageParams = { +export type RenderPageParams = { Page: React.FC>; - props: PageProps; + props: PageProps; actionResult: unknown; - Document: React.FC>; + Document: React.FC>; }; -export type RenderPage = ( - params: RenderPageParams, +export type RenderPage = ( + params: RenderPageParams, ) => Promise; -export type RwContext = { +export type RwContext = { nonce: string; - Document: React.FC>; - renderPage: RenderPage; - handleAction: (opts: RouteOptions) => Promise; + Document: React.FC>; + renderPage: RenderPage; + handleAction: (opts: RouteOptions) => Promise; }; export type RouteMiddleware = ( - opts: RouteOptions, + opts: RouteOptions, ) => | Response | Promise @@ -66,14 +66,14 @@ type RouteHandler = | RouteFunction | RouteComponent | [ - ...RouteMiddleware[], + ...RouteMiddleware[], RouteFunction | RouteComponent, ]; -export type Route = - | RouteMiddleware - | RouteDefinition - | Array>; +export type Route = + | RouteMiddleware + | RouteDefinition + | Array>; export type RouteDefinition, TParams = any> = { path: string; @@ -121,21 +121,21 @@ function matchPath( return params; } -function flattenRoutes( - routes: Route[], -): (RouteMiddleware | RouteDefinition)[] { - return routes.reduce((acc: Route[], route) => { +function flattenRoutes( + routes: Route[], +): (RouteMiddleware | RouteDefinition)[] { + return routes.reduce((acc: Route[], route) => { if (Array.isArray(route)) { return [...acc, ...flattenRoutes(route)]; } return [...acc, route]; - }, []) as (RouteMiddleware | RouteDefinition)[]; + }, []) as (RouteMiddleware | RouteDefinition)[]; } export function defineRoutes>( - routes: Route[], + routes: Route[], ): { - routes: Route[]; + routes: Route[]; handle: ({ cf, request, @@ -148,7 +148,7 @@ export function defineRoutes>( request: Request; ctx: TContext; env: Env; - rw: RwContext; + rw: RwContext; headers: Headers; }) => Response | Promise; } { @@ -165,8 +165,8 @@ export function defineRoutes>( } // Find matching route - let match: RouteMatch | null = null; - const routeOptions: RouteOptions = { + let match: RouteMatch | null = null; + const routeOptions: RouteOptions = { cf, request, params: {}, @@ -268,9 +268,9 @@ export function prefix( export function document( Document: React.FC<{ children: React.ReactNode }>, - routes: Route[], -): Route[] { - const documentMiddleware: RouteMiddleware = ({ rw }) => { + routes: Route[], +): Route[] { + const documentMiddleware: RouteMiddleware = ({ rw }) => { rw.Document = Document; }; diff --git a/sdk/src/runtime/register/worker.ts b/sdk/src/runtime/register/worker.ts index f1ae24817..9ea97e8fc 100644 --- a/sdk/src/runtime/register/worker.ts +++ b/sdk/src/runtime/register/worker.ts @@ -31,9 +31,9 @@ export function registerClientReference>( }); } -export async function rscActionHandler( +export async function rscActionHandler( req: Request, - opts: HandlerOptions, + opts: HandlerOptions, ): Promise { const url = new URL(req.url); const contentType = req.headers.get("content-type"); diff --git a/sdk/src/runtime/worker.tsx b/sdk/src/runtime/worker.tsx index aa9d0067a..e815b9161 100644 --- a/sdk/src/runtime/worker.tsx +++ b/sdk/src/runtime/worker.tsx @@ -24,7 +24,7 @@ declare global { }; } -export const defineApp = (routes: Route[]) => { +export const defineApp = (routes: Route[]) => { return { fetch: async (request: Request, env: Env, cf: ExecutionContext) => { globalThis.__webpack_require__ = ssrWebpackRequire; @@ -68,7 +68,7 @@ export const defineApp = (routes: Route[]) => { props: fullPageProps, actionResult, Document, - }: RenderPageParams) => { + }: RenderPageParams) => { let props = fullPageProps; let documentProps = fullPageProps; @@ -78,7 +78,7 @@ export const defineApp = (routes: Route[]) => { Object.prototype.hasOwnProperty.call(Page, "$$isClientReference") ) { const { ctx, params } = fullPageProps; - props = { ctx, params } as PageProps; + props = { ctx, params } as PageProps; } if ( @@ -88,7 +88,7 @@ export const defineApp = (routes: Route[]) => { ) ) { const { ctx, params } = fullPageProps; - documentProps = { ctx, params } as DocumentProps; + documentProps = { ctx, params } as DocumentProps; } const nonce = fullPageProps.rw.nonce; diff --git a/starters/drizzle/src/app/pages/Home.tsx b/starters/drizzle/src/app/pages/Home.tsx index 1cc90f797..893c3d74a 100644 --- a/starters/drizzle/src/app/pages/Home.tsx +++ b/starters/drizzle/src/app/pages/Home.tsx @@ -1,8 +1,8 @@ import { users } from "../../db/schema"; import { RouteOptions } from "@redwoodjs/sdk/router"; -import { Context } from "@/worker"; +import { AppContext } from "@/worker"; -export async function Home({ ctx }: RouteOptions) { +export async function Home({ ctx }: RouteOptions) { const allUsers = await ctx.db.select().from(users).all(); return (
diff --git a/starters/drizzle/src/worker.tsx b/starters/drizzle/src/worker.tsx index 92280ac3d..583e65d54 100644 --- a/starters/drizzle/src/worker.tsx +++ b/starters/drizzle/src/worker.tsx @@ -9,11 +9,11 @@ export interface Env { DB: D1Database; } -export type Context = { +export type AppContext = { db: ReturnType; }; -export default defineApp([ +export default defineApp([ setCommonHeaders(), ({ ctx, env }) => { // setup db in ctx diff --git a/starters/minimal/src/worker.tsx b/starters/minimal/src/worker.tsx index 28de27124..8f9fe8cae 100644 --- a/starters/minimal/src/worker.tsx +++ b/starters/minimal/src/worker.tsx @@ -4,9 +4,9 @@ import { Document } from "src/Document"; import { Home } from "src/pages/Home"; import { setCommonHeaders } from "src/headers"; -type Context = {}; +type AppContext = {}; -export default defineApp([ +export default defineApp([ setCommonHeaders(), ({ ctx }) => { // setup ctx here diff --git a/starters/passkey-auth/src/app/pages/Home.tsx b/starters/passkey-auth/src/app/pages/Home.tsx index 1294c68d2..ce8eb5743 100644 --- a/starters/passkey-auth/src/app/pages/Home.tsx +++ b/starters/passkey-auth/src/app/pages/Home.tsx @@ -1,4 +1,4 @@ -import { Context } from "@/worker"; +import { AppContext } from "@/worker"; export function Home({ ctx }: { ctx: Context }) { return ( diff --git a/starters/passkey-auth/src/worker.tsx b/starters/passkey-auth/src/worker.tsx index 94c76bcfd..10f52f092 100644 --- a/starters/passkey-auth/src/worker.tsx +++ b/starters/passkey-auth/src/worker.tsx @@ -10,12 +10,12 @@ import { db, setupDb } from "./db"; import { User } from "@prisma/client"; export { SessionDurableObject } from "./session/durableObject"; -export type Context = { +export type AppContext = { session: Session | null; user: User | null; }; -export default defineApp([ +export default defineApp([ setCommonHeaders(), async ({ env, ctx, request, headers }) => { await setupDb(env); diff --git a/starters/prisma/src/worker.tsx b/starters/prisma/src/worker.tsx index cc7ff9497..ba88ed59d 100644 --- a/starters/prisma/src/worker.tsx +++ b/starters/prisma/src/worker.tsx @@ -4,9 +4,9 @@ import { Document } from "src/Document"; import { Home } from "src/pages/Home"; import { setupDb } from "./db"; import { setCommonHeaders } from "src/headers"; -type Context = {}; +type AppContext = {}; -export default defineApp([ +export default defineApp([ setCommonHeaders(), async ({ ctx, env, request }) => { await setupDb(env); diff --git a/starters/sessions/src/app/pages/Home.tsx b/starters/sessions/src/app/pages/Home.tsx index e16059958..7b0654ddc 100644 --- a/starters/sessions/src/app/pages/Home.tsx +++ b/starters/sessions/src/app/pages/Home.tsx @@ -1,4 +1,4 @@ -import { Context } from "@/worker"; +import { AppContext } from "@/worker"; export function Home({ ctx }: { ctx: Context }) { return ( diff --git a/starters/sessions/src/worker.tsx b/starters/sessions/src/worker.tsx index 482096d82..78d0ba235 100644 --- a/starters/sessions/src/worker.tsx +++ b/starters/sessions/src/worker.tsx @@ -9,11 +9,11 @@ import { setCommonHeaders } from "./app/headers"; export { SessionDurableObject } from "./session/durableObject"; -export type Context = { +export type AppContext = { session: Session | null; }; -export default defineApp([ +export default defineApp([ setCommonHeaders(), async ({ env, ctx, request, headers }) => { setupSessionStore(env); diff --git a/starters/standard/src/app/pages/Home.tsx b/starters/standard/src/app/pages/Home.tsx index 1294c68d2..ce8eb5743 100644 --- a/starters/standard/src/app/pages/Home.tsx +++ b/starters/standard/src/app/pages/Home.tsx @@ -1,4 +1,4 @@ -import { Context } from "@/worker"; +import { AppContext } from "@/worker"; export function Home({ ctx }: { ctx: Context }) { return ( diff --git a/starters/standard/src/worker.tsx b/starters/standard/src/worker.tsx index da5d50dc9..321d2cf82 100644 --- a/starters/standard/src/worker.tsx +++ b/starters/standard/src/worker.tsx @@ -10,12 +10,12 @@ import { db, setupDb } from "./db"; import type { User } from "@prisma/client"; export { SessionDurableObject } from "./session/durableObject"; -export type Context = { +export type AppContext = { session: Session | null; user: User | null; }; -export default defineApp([ +export default defineApp([ setCommonHeaders(), async ({ env, ctx, request, headers }) => { await setupDb(env); From 548ea1c655fea1cec2a088a26f4410d4590077d7 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:08:51 +0200 Subject: [PATCH 3/9] ctx: Context -> appContext: AppContext --- .../docs/core/react-server-components.mdx | 14 ++-- docs/src/content/docs/core/routing.mdx | 38 +++++----- .../docs/getting-started/first-project.mdx | 12 ++-- docs/src/content/docs/reference/routing.mdx | 24 +++---- experiments/billable/docs/Routing.md | 7 +- .../billable/src/app/pages/Home/HomePage.tsx | 6 +- experiments/billable/src/app/pages/Layout.tsx | 6 +- .../billable/src/app/pages/auth/LoginPage.tsx | 2 +- .../invoice/DetailPage/InvoiceDetailPage.tsx | 8 +-- .../pages/invoice/DetailPage/InvoiceForm.tsx | 4 +- .../app/pages/invoice/DetailPage/functions.ts | 8 +-- .../invoice/ListPage/InvoiceListPage.tsx | 6 +- .../app/pages/invoice/ListPage/functions.ts | 8 ++- .../billable/src/app/pages/invoice/routes.ts | 8 +-- experiments/billable/src/session.tsx | 6 +- experiments/billable/src/worker.tsx | 12 ++-- experiments/cutable/src/app/pages/Layout.tsx | 6 +- .../cutable/src/app/pages/home/HomePage.tsx | 4 +- .../project/DetailPage/CutlistDetailPage.tsx | 6 +- .../project/DetailPage/ProjectDetailPage.tsx | 6 +- .../project/ListPage/ProjectListPage.tsx | 6 +- .../app/pages/project/ListPage/functions.ts | 6 +- experiments/cutable/src/session.tsx | 6 +- experiments/cutable/src/worker.tsx | 4 +- experiments/cutl/docs/Routing.md | 7 +- .../cutl/src/app/pages/Home/HomePage.tsx | 4 +- experiments/cutl/src/app/pages/Layout.tsx | 6 +- .../cutl/src/app/pages/auth/LoginPage.tsx | 4 +- .../project/DetailPage/CutlistDetailPage.tsx | 6 +- .../project/DetailPage/ProjectDetailPage.tsx | 6 +- .../project/ListPage/ProjectListPage.tsx | 6 +- .../app/pages/project/ListPage/functions.ts | 6 +- experiments/cutl/src/lib/router.ts | 17 +++-- experiments/cutl/src/register/worker.ts | 24 ++++--- experiments/cutl/src/session.tsx | 20 +++--- experiments/cutl/src/worker.tsx | 16 ++--- .../src/app/pages/note/functions.ts | 12 ++-- .../realtime-poc/src/session/durableObject.ts | 6 +- experiments/yt-dos/src/worker.tsx | 6 +- .../zoomshare/src/app/pages/auth/functions.ts | 16 ++--- .../src/app/pages/meetings/MeetingList.tsx | 2 +- .../zoomshare/src/session/durableObject.ts | 6 +- experiments/zoomshare/src/worker.tsx | 4 +- sdk/src/runtime/lib/router.ts | 72 ++++++++++--------- sdk/src/runtime/worker.tsx | 16 ++--- starters/drizzle/src/app/pages/Home.tsx | 4 +- starters/drizzle/src/worker.tsx | 6 +- starters/minimal/src/worker.tsx | 6 +- starters/passkey-auth/src/app/pages/Home.tsx | 6 +- .../passkey-auth/src/session/durableObject.ts | 6 +- starters/passkey-auth/src/worker.tsx | 14 ++-- starters/prisma/src/worker.tsx | 2 +- starters/sessions/src/app/pages/Home.tsx | 6 +- .../sessions/src/session/durableObject.ts | 6 +- starters/sessions/src/worker.tsx | 4 +- starters/standard/src/app/pages/Home.tsx | 6 +- .../standard/src/session/durableObject.ts | 6 +- starters/standard/src/worker.tsx | 14 ++-- 58 files changed, 286 insertions(+), 275 deletions(-) diff --git a/docs/src/content/docs/core/react-server-components.mdx b/docs/src/content/docs/core/react-server-components.mdx index 8b54d6c44..4039f2c52 100644 --- a/docs/src/content/docs/core/react-server-components.mdx +++ b/docs/src/content/docs/core/react-server-components.mdx @@ -28,8 +28,8 @@ export default function MyClientComponent() { React Server Components run on the server, they can easily fetch data and make it part of the payload that's sent to the client. ```tsx title="src/app/pages/todos/TodoPage.tsx" "async" -export async function Todos({ ctx }) { - const todos = await db.todo.findMany({ where: { userId: ctx.user.id } }); +export async function Todos({ appContext }) { + const todos = await db.todo.findMany({ where: { userId: appContext.user.id } }); return (
    {todos.map((todo) => ( @@ -39,19 +39,19 @@ export async function Todos({ ctx }) { ); } -export async function TodoPage({ ctx }) { +export async function TodoPage({ appContext }) { return (

    Todos

    Loading...
    }> - +
); } --- -The `TodoPage` component is a server component. It it rendered by a route, so it receives the `ctx` object. We pass this to the `Todos` component, which is also a server component, +The `TodoPage` component is a server component. It it rendered by a route, so it receives the `appContext` object. We pass this to the `Todos` component, which is also a server component, and renders the todos. --- ``` @@ -69,9 +69,9 @@ Allow you to execute code on the server from a client component. ```tsx title="@/pages/todos/functions.tsx" mark={1} "use server"; -export async function addTodo(formData: FormData, { ctx }: RouteOptions) { +export async function addTodo(formData: FormData, { appContext }: RouteOptions) { const title = formData.get("title"); - await db.todo.create({ data: { title, userId: ctx.user.id } }); + await db.todo.create({ data: { title, userId: appContext.user.id } }); } --- diff --git a/docs/src/content/docs/core/routing.mdx b/docs/src/content/docs/core/routing.mdx index 9d831033d..6a25083f7 100644 --- a/docs/src/content/docs/core/routing.mdx +++ b/docs/src/content/docs/core/routing.mdx @@ -13,13 +13,13 @@ import { route } from "@redwoodjs/sdk/router"; export default defineApp([ // Middleware - function middleware({ request, env, ctx }) { /* Modify context */ }, - function middleware({ request, env, ctx }) { /* Modify context */ }, + function middleware({ request, env, appContext }) { /* Modify context */ }, + function middleware({ request, env, appContext }) { /* Modify context */ }, // Request Handlers - route("/", function handler({ request, env, ctx }) { + route("/", function handler({ request, env, appContext }) { return new Response("Hello, world!") }), - route("/ping", function handler({ request, env, ctx }) { + route("/ping", function handler({ request, env, appContext }) { return new Response("Pong!") }), ]); @@ -87,7 +87,7 @@ The request handler is a function, or array of functions (See [Interruptors](#in import { route } from "@redwoodjs/sdk/router"; defineApp([ - route("/a-standard-response", ({ request, params, env, ctx }) => { + route("/a-standard-response", ({ request, params, env, appContext }) => { return new Response("Hello, world!") }), route('/a-jsx-response', () => { @@ -100,7 +100,7 @@ The request handler function takes in the following options: 1. `request`: The request object. 2. `params`: The matched parameters from the request URL. 3. `env`: The Cloudflare environment. -4. `ctx`: The context object (See [Middleware & Context](#middleware-context)). +4. `appContext`: The context object (See [Middleware & Context](#middleware-context)). 5. `cf:` Cloudflare's [Execution Context API](https://developers.cloudflare.com/workers/runtime-apis/context/) methods, e.g. `waitUntil()` Return values: @@ -118,9 +118,9 @@ import { defineApp } from "@redwoodjs/sdk/worker"; import { route } from "@redwoodjs/sdk/router"; import { EditBlogPage } from "src/pages/blog/EditBlogPage"; -function isAuthenticated({ request, env, ctx }) { +function isAuthenticated({ request, env, appContext }) { // Ensure that this user is authenticated - if (!ctx.user) { + if (!appContext.user) { return new Response("Unauthorized", { status: 401 }) } } @@ -146,31 +146,31 @@ import { route } from "@redwoodjs/sdk/router"; defineApp([ sessionMiddleware, - async function getUserMiddleware({ request, env, ctx }) { - if (ctx.session.userId) { - ctx.user = await db.user.find({ where: { id: ctx.session.userId } }); + async function getUserMiddleware({ request, env, appContext }) { + if (appContext.session.userId) { + appContext.user = await db.user.find({ where: { id: appContext.session.userId } }); } }, route("/hello", [ - function ({ ctx }) { - if (!ctx.user) { + function ({ appContext }) { + if (!appContext.user) { return new Response("Unauthorized", { status: 401 }); } }, - function ({ ctx }) { - return new Response(`Hello ${ctx.user.username}!`); + function ({ appContext }) { + return new Response(`Hello ${appContext.user.username}!`); }, ]), ]); --- -The `ctx` object: +The `appContext` object: -1. `sessionMiddleware` is a function that is used to populate the `ctx.session` object -2. `getUserMiddleware` is a middleware function that is used to populate the `ctx.user` object +1. `sessionMiddleware` is a function that is used to populate the `appContext.session` object +2. `getUserMiddleware` is a middleware function that is used to populate the `appContext.user` object 3. `"/hello"` is a an array of route handlers that are executed when "/hello" is matched: - if the user is not authenticated the request will be interrupted and a 401 Unauthorized response will be returned - - if the user is authenticated the request will be passed to the next request handler and `"Hello {ctx.user.username}!"` will be returned + - if the user is authenticated the request will be passed to the next request handler and `"Hello {appContext.user.username}!"` will be returned --- ``` diff --git a/docs/src/content/docs/getting-started/first-project.mdx b/docs/src/content/docs/getting-started/first-project.mdx index 2f67c0883..307458c35 100644 --- a/docs/src/content/docs/getting-started/first-project.mdx +++ b/docs/src/content/docs/getting-started/first-project.mdx @@ -71,9 +71,9 @@ import { Home } from 'src/pages/Home'; ... export default defineApp([ - ({ ctx }) => { - // setup ctx here - ctx; + ({ appContext }) => { + // setup appContext here + appContext; }, render(Document, [ index([ @@ -115,9 +115,9 @@ You can add additional routes by: import { About } from "src/pages/About"; export default defineApp([ - ({ ctx }) => { - // setup ctx here - ctx; + ({ appContext }) => { + // setup appContext here + appContext; }, render(Document, [index([Home]), route("/about", About)]), ]); diff --git a/docs/src/content/docs/reference/routing.mdx b/docs/src/content/docs/reference/routing.mdx index ce28c3855..fd7306552 100644 --- a/docs/src/content/docs/reference/routing.mdx +++ b/docs/src/content/docs/reference/routing.mdx @@ -41,7 +41,7 @@ Route functions handle incoming requests and return either a Response object or - `request`: The incoming Request object - `params`: URL parameters parsed from the route definition - `env`: CloudFlare environment variables and bindings -- `ctx`: A mutable object for storing request-scoped data +- `appContext`: A mutable object for storing request-scoped data Here's a basic example: @@ -50,7 +50,7 @@ Here's a basic example: code={`\ import { route } from "@redwoodjs/sdk/router"; -route("/", function ({ request, params, env, ctx }) { +route("/", function ({ request, params, env, appContext }) { return new Response("Hello, world!", { status: 200 }); });`} /> @@ -82,8 +82,8 @@ import { route } from "@redwoodjs/sdk/router"; export default defineApp([ route("/user/settings", [ // Authentication check - function checkAuth({ ctx }) { - if (!ctx.user) { + function checkAuth({ appContext }) { + if (!appContext.user) { return Response.redirect("/user/login", 302); } }, @@ -96,7 +96,7 @@ export default defineApp([ The interruptors pattern complements the global middleware system, allowing you to apply route-specific checks without cluttering your main request functions. -Note: All request functions in the chain receive the same route context (`request`, `params`, `env`, `ctx`), making it easy to share data between functions. +Note: All request functions in the chain receive the same route context (`request`, `params`, `env`, `appContext`), making it easy to share data between functions. ## Global Middleware @@ -107,7 +107,7 @@ Global middleware allows you to inspect or modify every request and response in title="src/worker.tsx" code={`\ export default defineApp([ - async function getUserMiddleware({ request, env, ctx }) { + async function getUserMiddleware({ request, env, appContext }) { const session = getSession({ request, env }) try { const user = await db.user.findFirstOrThrow({ @@ -119,13 +119,13 @@ export default defineApp([ id: session?.userId } }) - ctx.user = user + appContext.user = user } catch { - ctx.user = null + appContext.user = null } }, - route('/', function({ ctx }) { - return new Response(\`You are logged in as "\${ctx.user.email}"\`) + route('/', function({ appContext }) { + return new Response(\`You are logged in as "\${appContext.user.email}"\`) }) ])`} /> @@ -134,9 +134,9 @@ In this example, we define a global middleware function `getUserMiddleware` that 1. Retrieves the user's session information 2. Attempts to fetch the user from the database using the session's userId -3. Stores the user object in the request context (`ctx`) +3. Stores the user object in the request context (`appContext`) -The `ctx` object is then available to all subsequent route handlers and middleware functions. +The `appContext` object is then available to all subsequent route handlers and middleware functions. ## JSX diff --git a/experiments/billable/docs/Routing.md b/experiments/billable/docs/Routing.md index 77d6254fd..4f4aebeda 100644 --- a/experiments/billable/docs/Routing.md +++ b/experiments/billable/docs/Routing.md @@ -49,10 +49,9 @@ const router = defineRoutes([ }) ]) -router.handle({ request, ctx, env, renderPage }) +router.handle({ request, appContext, env, renderPage }) ``` - # API Reference - `defineRoutes` @@ -60,7 +59,6 @@ router.handle({ request, ctx, env, renderPage }) - `index` - `prefix` - # Links We also include an interface to generate paths in a typesafe way. This allows you to confidently @@ -88,7 +86,6 @@ link('/invoice/:id', { id: 1 }) ``` - ## TODO - Type safety. How do we ensure that the params have types? Maybe the route array has some sort of response... Like the type that it returns is a function that returns a thing... That's interesting. @@ -96,7 +93,7 @@ link('/invoice/:id', { id: 1 }) Ok. That seems like a possible way forward. What else to consider? - Type casting? Should we consider have the ability to cast things via the router? Seems like an overreach to me. -Loaders. Stick with Suspense boundary. I kinda see the benefit of been able to declare this on the component itself... Or near the component. + Loaders. Stick with Suspense boundary. I kinda see the benefit of been able to declare this on the component itself... Or near the component. - Don't hide files. I want to be able to follow the request-response cycle in my own code. What does that mean? - We should expose the express (or something else) part of the framework. The user should invoke a function to pass the request off to Redwood SDK diff --git a/experiments/billable/src/app/pages/Home/HomePage.tsx b/experiments/billable/src/app/pages/Home/HomePage.tsx index a3fcae727..6d904aed9 100644 --- a/experiments/billable/src/app/pages/Home/HomePage.tsx +++ b/experiments/billable/src/app/pages/Home/HomePage.tsx @@ -1,9 +1,9 @@ import { RouteOptions } from "@redwoodjs/sdk/worker"; import { Layout } from "../Layout"; import { InvoiceForm } from "../invoice/DetailPage/InvoiceForm"; -export default function HomePage({ ctx }: RouteOptions) { +export default function HomePage({ appContext }: RouteOptions) { return ( - + ); diff --git a/experiments/billable/src/app/pages/Layout.tsx b/experiments/billable/src/app/pages/Layout.tsx index 6f2e65aaa..a738f2a26 100644 --- a/experiments/billable/src/app/pages/Layout.tsx +++ b/experiments/billable/src/app/pages/Layout.tsx @@ -44,14 +44,14 @@ function Header({ user }: { user?: User }) { export function Layout({ children, - ctx, + appContext, }: { children: React.ReactNode; - ctx: { user?: User }; + appContext: { user?: User }; }) { return (
-
+
{children}
diff --git a/experiments/billable/src/app/pages/auth/LoginPage.tsx b/experiments/billable/src/app/pages/auth/LoginPage.tsx index b388a7b5f..3891d6142 100644 --- a/experiments/billable/src/app/pages/auth/LoginPage.tsx +++ b/experiments/billable/src/app/pages/auth/LoginPage.tsx @@ -29,7 +29,7 @@ export function LoginPage(opts: RouteOptions) { }; return ( - +

Continue with Email Address diff --git a/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceDetailPage.tsx b/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceDetailPage.tsx index 7eae9e6f8..874c32814 100644 --- a/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceDetailPage.tsx +++ b/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceDetailPage.tsx @@ -52,19 +52,19 @@ export async function getInvoice(id: string, userId: string) { export async function InvoiceDetailPage({ params, - ctx, + appContext, }: RouteOptions<{ id: string }>) { - const invoice = await getInvoice(params.id, ctx.user.id); + const invoice = await getInvoice(params.id, appContext.user.id); return ( - + Invoices Edit Invoice - + ); } diff --git a/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceForm.tsx b/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceForm.tsx index bbc9726c3..0bca65d97 100644 --- a/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceForm.tsx +++ b/experiments/billable/src/app/pages/invoice/DetailPage/InvoiceForm.tsx @@ -35,7 +35,7 @@ function calculateTaxes(subtotal: number, taxes: InvoiceTaxes[]) { export function InvoiceForm(props: { invoice: Awaited>; - ctx: RouteOptions["ctx"]; + appContext: RouteOptions["appContext"]; }) { const [invoice, setInvoice] = useState(props.invoice); const [items, setItems] = useState(props.invoice.items); @@ -47,7 +47,7 @@ export function InvoiceForm(props: { const pdfContentRef = useRef(null); - const isLoggedIn = props.ctx?.user; + const isLoggedIn = props.appContext?.user; return (
diff --git a/experiments/billable/src/app/pages/invoice/DetailPage/functions.ts b/experiments/billable/src/app/pages/invoice/DetailPage/functions.ts index efea7839b..387b1ffd2 100644 --- a/experiments/billable/src/app/pages/invoice/DetailPage/functions.ts +++ b/experiments/billable/src/app/pages/invoice/DetailPage/functions.ts @@ -9,12 +9,12 @@ export async function saveInvoice( invoice: Omit, items: InvoiceItem[], taxes: InvoiceTaxes[], - { ctx }, + { appContext }, ) { await db.invoice.findFirstOrThrow({ where: { id, - userId: ctx.user.id, + userId: appContext.user.id, }, }); @@ -34,11 +34,11 @@ export async function saveInvoice( }); } -export async function deleteLogo(id: string, { ctx }) { +export async function deleteLogo(id: string, { appContext }) { await db.invoice.findFirstOrThrow({ where: { id, - userId: ctx.user.id, + userId: appContext.user.id, }, }); diff --git a/experiments/billable/src/app/pages/invoice/ListPage/InvoiceListPage.tsx b/experiments/billable/src/app/pages/invoice/ListPage/InvoiceListPage.tsx index 6dcbfae9d..02e1d5f5c 100644 --- a/experiments/billable/src/app/pages/invoice/ListPage/InvoiceListPage.tsx +++ b/experiments/billable/src/app/pages/invoice/ListPage/InvoiceListPage.tsx @@ -58,10 +58,10 @@ async function getInvoiceListSummary(userId: string) { }); } -export async function InvoiceListPage({ ctx }: RouteOptions) { - const invoices = await getInvoiceListSummary(ctx.user.id); +export async function InvoiceListPage({ appContext }: RouteOptions) { + const invoices = await getInvoiceListSummary(appContext.user.id); return ( - +
diff --git a/experiments/billable/src/app/pages/invoice/ListPage/functions.ts b/experiments/billable/src/app/pages/invoice/ListPage/functions.ts index 9438cddd4..a2ed285b3 100644 --- a/experiments/billable/src/app/pages/invoice/ListPage/functions.ts +++ b/experiments/billable/src/app/pages/invoice/ListPage/functions.ts @@ -4,8 +4,12 @@ import { db } from "src/db"; import { AppContext } from "../../../../worker"; // We need to pass the context to these somehow? -export async function createInvoice({ ctx }: { ctx: Context }) { - const userId = ctx.user.id; +export async function createInvoice({ + appContext, +}: { + appContext: AppContext; +}) { + const userId = appContext.user.id; // todo(peterp, 28-01-2025): Implement templates. let lastInvoice = await db.invoice.findFirst({ diff --git a/experiments/billable/src/app/pages/invoice/routes.ts b/experiments/billable/src/app/pages/invoice/routes.ts index f01784334..79b904f47 100644 --- a/experiments/billable/src/app/pages/invoice/routes.ts +++ b/experiments/billable/src/app/pages/invoice/routes.ts @@ -4,8 +4,8 @@ import { InvoiceDetailPage } from "./DetailPage/InvoiceDetailPage"; import { InvoiceListPage } from "./ListPage/InvoiceListPage"; import { link } from "src/shared/links"; -function isAuthenticated({ ctx }) { - if (!ctx.user) { +function isAuthenticated({ appContext }) { + if (!appContext.user) { return new Response(null, { status: 302, headers: { Location: link("/") }, @@ -27,7 +27,7 @@ export const invoiceRoutes = [ route("/:id", [isAuthenticated, InvoiceDetailPage]), route("/:id/upload", [ isAuthenticated, - async ({ request, params, env, ctx }) => { + async ({ request, params, env, appContext }) => { if ( request.method !== "POST" && !request.headers.get("content-type")?.includes("multipart/form-data") @@ -40,7 +40,7 @@ export const invoiceRoutes = [ const file = formData.get("file") as File; // Stream the file directly to R2 - const r2ObjectKey = `/invoice/logos/${ctx.user.id}/${params.id}-${Date.now()}-${file.name}`; + const r2ObjectKey = `/invoice/logos/${appContext.user.id}/${params.id}-${Date.now()}-${file.name}`; await env.R2.put(r2ObjectKey, file.stream(), { httpMetadata: { contentType: file.type, diff --git a/experiments/billable/src/session.tsx b/experiments/billable/src/session.tsx index 4d3dee7e3..e54564b0d 100644 --- a/experiments/billable/src/session.tsx +++ b/experiments/billable/src/session.tsx @@ -19,7 +19,7 @@ export class SessionDO extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDO extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); // context(justinvdm, 2025-01-15): If the session DO exists but there's no session state // it means we received a valid session id (it passed the signature check), but the session @@ -53,7 +53,7 @@ export class SessionDO extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/billable/src/worker.tsx b/experiments/billable/src/worker.tsx index ec4cfc756..7c5ab3bac 100644 --- a/experiments/billable/src/worker.tsx +++ b/experiments/billable/src/worker.tsx @@ -34,15 +34,15 @@ export const getUser = async (request: Request) => { }; const app = defineApp([ - async ({ request, ctx, env }) => { + async ({ request, appContext, env }) => { await setupDb(env); setupSessionStore(env); - ctx.user = await getUser(request); + appContext.user = await getUser(request); }, render(Document, [ index([ - ({ ctx }) => { - if (ctx.user) { + ({ appContext }) => { + if (appContext.user) { return new Response(null, { status: 302, headers: { Location: link("/invoice/list") }, @@ -57,7 +57,7 @@ const app = defineApp([ ]); export default { - fetch(request: Request, env: Env, ctx: ExecutionContext) { - return app.fetch(request, env, ctx); + fetch(request: Request, env: Env, cf: ExecutionContext) { + return app.fetch(request, env, cf); }, }; diff --git a/experiments/cutable/src/app/pages/Layout.tsx b/experiments/cutable/src/app/pages/Layout.tsx index 30a54daa8..9facc951c 100644 --- a/experiments/cutable/src/app/pages/Layout.tsx +++ b/experiments/cutable/src/app/pages/Layout.tsx @@ -28,14 +28,14 @@ function Header({ user }: { user?: User }) { export function Layout({ children, - ctx, + appContext, }: { children: React.ReactNode; - ctx: { user?: User }; + appContext: { user?: User }; }) { return (
-
+
{children}
diff --git a/experiments/cutable/src/app/pages/home/HomePage.tsx b/experiments/cutable/src/app/pages/home/HomePage.tsx index 9be6d43cb..51aab8364 100644 --- a/experiments/cutable/src/app/pages/home/HomePage.tsx +++ b/experiments/cutable/src/app/pages/home/HomePage.tsx @@ -2,9 +2,9 @@ import { RouteOptions } from "@redwoodjs/sdk/router"; import { Layout } from "../Layout"; import { CalculateSheets } from "./CalculateSheets"; // import { Test } from "./Test" -export default function HomePage({ ctx }: RouteOptions) { +export default function HomePage({ appContext }: RouteOptions) { return ( - + {/* */} diff --git a/experiments/cutable/src/app/pages/project/DetailPage/CutlistDetailPage.tsx b/experiments/cutable/src/app/pages/project/DetailPage/CutlistDetailPage.tsx index 91f70370d..f800648e2 100644 --- a/experiments/cutable/src/app/pages/project/DetailPage/CutlistDetailPage.tsx +++ b/experiments/cutable/src/app/pages/project/DetailPage/CutlistDetailPage.tsx @@ -11,9 +11,9 @@ import { findOptimalPacking, calculateFreeSpaces } from "./clientFunctions"; export default async function CutlistDetailPage({ params, - ctx, + appContext, }: RouteOptions<{ id: string }>) { - const project = await getProject(params.id, ctx.user.id); + const project = await getProject(params.id, appContext.user.id); const cutlistItems = JSON.parse( project.cutlistItems as string, ) as ProjectItem[]; @@ -72,7 +72,7 @@ export default async function CutlistDetailPage({ // boards? return ( - + Projects diff --git a/experiments/cutable/src/app/pages/project/DetailPage/ProjectDetailPage.tsx b/experiments/cutable/src/app/pages/project/DetailPage/ProjectDetailPage.tsx index 2f00537ec..03ed6f0ab 100644 --- a/experiments/cutable/src/app/pages/project/DetailPage/ProjectDetailPage.tsx +++ b/experiments/cutable/src/app/pages/project/DetailPage/ProjectDetailPage.tsx @@ -51,12 +51,12 @@ export async function updateProject( export default async function ProjectDetailPage({ params, - ctx, + appContext, }: RouteOptions<{ id: string }>) { - const project = await getProject(params.id, ctx.user.id); + const project = await getProject(params.id, appContext.user.id); return ( - + Projects diff --git a/experiments/cutable/src/app/pages/project/ListPage/ProjectListPage.tsx b/experiments/cutable/src/app/pages/project/ListPage/ProjectListPage.tsx index e4565581d..b4d675f99 100644 --- a/experiments/cutable/src/app/pages/project/ListPage/ProjectListPage.tsx +++ b/experiments/cutable/src/app/pages/project/ListPage/ProjectListPage.tsx @@ -61,10 +61,10 @@ async function getProjectListSummary(userId: string) { }); } -export default async function ProjectListPage({ ctx }: RouteOptions) { - const projects = await getProjectListSummary(ctx.user.id); +export default async function ProjectListPage({ appContext }: RouteOptions) { + const projects = await getProjectListSummary(appContext.user.id); return ( - +
diff --git a/experiments/cutable/src/app/pages/project/ListPage/functions.ts b/experiments/cutable/src/app/pages/project/ListPage/functions.ts index bce84a195..7b95fa411 100644 --- a/experiments/cutable/src/app/pages/project/ListPage/functions.ts +++ b/experiments/cutable/src/app/pages/project/ListPage/functions.ts @@ -5,11 +5,11 @@ import { getContext } from "../../../../worker"; // We need to pass the context to these somehow? export async function createProject({ - ctx, + appContext, }: { - ctx: Awaited>; + appContext: Awaited>; }) { - const userId = ctx.user.id; + const userId = appContext.user.id; const newProject = await db.project.create({ data: { diff --git a/experiments/cutable/src/session.tsx b/experiments/cutable/src/session.tsx index 212289176..1c75230b8 100644 --- a/experiments/cutable/src/session.tsx +++ b/experiments/cutable/src/session.tsx @@ -19,7 +19,7 @@ export class SessionDO extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDO extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); // context(justinvdm, 2025-01-15): If the session DO exists but there's no session state // it means we received a valid session id (it passed the signature check), but the session @@ -53,7 +53,7 @@ export class SessionDO extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/cutable/src/worker.tsx b/experiments/cutable/src/worker.tsx index 28598b776..d2ec246f8 100644 --- a/experiments/cutable/src/worker.tsx +++ b/experiments/cutable/src/worker.tsx @@ -11,10 +11,10 @@ type AppContext = { export default defineApp([ // >>> Replaces `getContext()` - ({ ctx }: { ctx: Context }) => { + ({ appContext }: { appContext: AppContext }) => { // >>> You can do side effects (e.g, setup like `setupDb()`) here // >>> You can set your context here - ctx.foo = 23; + appContext.foo = 23; }, // @ts-ignore render(Document, [index([HomePage])]), diff --git a/experiments/cutl/docs/Routing.md b/experiments/cutl/docs/Routing.md index 77d6254fd..4f4aebeda 100644 --- a/experiments/cutl/docs/Routing.md +++ b/experiments/cutl/docs/Routing.md @@ -49,10 +49,9 @@ const router = defineRoutes([ }) ]) -router.handle({ request, ctx, env, renderPage }) +router.handle({ request, appContext, env, renderPage }) ``` - # API Reference - `defineRoutes` @@ -60,7 +59,6 @@ router.handle({ request, ctx, env, renderPage }) - `index` - `prefix` - # Links We also include an interface to generate paths in a typesafe way. This allows you to confidently @@ -88,7 +86,6 @@ link('/invoice/:id', { id: 1 }) ``` - ## TODO - Type safety. How do we ensure that the params have types? Maybe the route array has some sort of response... Like the type that it returns is a function that returns a thing... That's interesting. @@ -96,7 +93,7 @@ link('/invoice/:id', { id: 1 }) Ok. That seems like a possible way forward. What else to consider? - Type casting? Should we consider have the ability to cast things via the router? Seems like an overreach to me. -Loaders. Stick with Suspense boundary. I kinda see the benefit of been able to declare this on the component itself... Or near the component. + Loaders. Stick with Suspense boundary. I kinda see the benefit of been able to declare this on the component itself... Or near the component. - Don't hide files. I want to be able to follow the request-response cycle in my own code. What does that mean? - We should expose the express (or something else) part of the framework. The user should invoke a function to pass the request off to Redwood SDK diff --git a/experiments/cutl/src/app/pages/Home/HomePage.tsx b/experiments/cutl/src/app/pages/Home/HomePage.tsx index ada3288ad..ba0e8d377 100644 --- a/experiments/cutl/src/app/pages/Home/HomePage.tsx +++ b/experiments/cutl/src/app/pages/Home/HomePage.tsx @@ -2,9 +2,9 @@ import { RouteOptions } from "../../../lib/router"; import { Layout } from "../Layout"; import { CalculateSheets } from "./CalculateSheets"; // import { Test } from "./Test" -export default function HomePage({ ctx }: RouteOptions) { +export default function HomePage({ appContext }: RouteOptions) { return ( - + {/* */} diff --git a/experiments/cutl/src/app/pages/Layout.tsx b/experiments/cutl/src/app/pages/Layout.tsx index e84c9482a..ae591bcda 100644 --- a/experiments/cutl/src/app/pages/Layout.tsx +++ b/experiments/cutl/src/app/pages/Layout.tsx @@ -29,14 +29,14 @@ function Header({ user }: { user?: User }) { export function Layout({ children, - ctx, + appContext, }: { children: React.ReactNode; - ctx: { user?: User }; + appContext: { user?: User }; }) { return (
-
+
{children}
diff --git a/experiments/cutl/src/app/pages/auth/LoginPage.tsx b/experiments/cutl/src/app/pages/auth/LoginPage.tsx index c68b78684..d1823b8cc 100644 --- a/experiments/cutl/src/app/pages/auth/LoginPage.tsx +++ b/experiments/cutl/src/app/pages/auth/LoginPage.tsx @@ -16,7 +16,7 @@ import { } from "../../components/ui/input-otp"; import { link } from "../../shared/links"; -export function LoginPage({ ctx }: RouteOptions) { +export function LoginPage({ appContext }: RouteOptions) { const [email, setEmail] = useState("her.stander@gmail.com"); const [isPending, startTransition] = useTransition(); const [success, setSuccess] = useState(false); @@ -30,7 +30,7 @@ export function LoginPage({ ctx }: RouteOptions) { }; return ( - +

Continue with Email Address diff --git a/experiments/cutl/src/app/pages/project/DetailPage/CutlistDetailPage.tsx b/experiments/cutl/src/app/pages/project/DetailPage/CutlistDetailPage.tsx index 66d29fb2c..af8f0efe8 100644 --- a/experiments/cutl/src/app/pages/project/DetailPage/CutlistDetailPage.tsx +++ b/experiments/cutl/src/app/pages/project/DetailPage/CutlistDetailPage.tsx @@ -11,9 +11,9 @@ import { findOptimalPacking, calculateFreeSpaces } from "./clientFunctions"; export default async function CutlistDetailPage({ params, - ctx, + appContext, }: RouteOptions<{ id: string }>) { - const project = await getProject(params.id, ctx.user.id); + const project = await getProject(params.id, appContext.user.id); const cutlistItems = JSON.parse( project.cutlistItems as string, ) as ProjectItem[]; @@ -72,7 +72,7 @@ export default async function CutlistDetailPage({ // boards? return ( - + Projects diff --git a/experiments/cutl/src/app/pages/project/DetailPage/ProjectDetailPage.tsx b/experiments/cutl/src/app/pages/project/DetailPage/ProjectDetailPage.tsx index 2f00537ec..03ed6f0ab 100644 --- a/experiments/cutl/src/app/pages/project/DetailPage/ProjectDetailPage.tsx +++ b/experiments/cutl/src/app/pages/project/DetailPage/ProjectDetailPage.tsx @@ -51,12 +51,12 @@ export async function updateProject( export default async function ProjectDetailPage({ params, - ctx, + appContext, }: RouteOptions<{ id: string }>) { - const project = await getProject(params.id, ctx.user.id); + const project = await getProject(params.id, appContext.user.id); return ( - + Projects diff --git a/experiments/cutl/src/app/pages/project/ListPage/ProjectListPage.tsx b/experiments/cutl/src/app/pages/project/ListPage/ProjectListPage.tsx index e4565581d..b4d675f99 100644 --- a/experiments/cutl/src/app/pages/project/ListPage/ProjectListPage.tsx +++ b/experiments/cutl/src/app/pages/project/ListPage/ProjectListPage.tsx @@ -61,10 +61,10 @@ async function getProjectListSummary(userId: string) { }); } -export default async function ProjectListPage({ ctx }: RouteOptions) { - const projects = await getProjectListSummary(ctx.user.id); +export default async function ProjectListPage({ appContext }: RouteOptions) { + const projects = await getProjectListSummary(appContext.user.id); return ( - +
diff --git a/experiments/cutl/src/app/pages/project/ListPage/functions.ts b/experiments/cutl/src/app/pages/project/ListPage/functions.ts index bce84a195..7b95fa411 100644 --- a/experiments/cutl/src/app/pages/project/ListPage/functions.ts +++ b/experiments/cutl/src/app/pages/project/ListPage/functions.ts @@ -5,11 +5,11 @@ import { getContext } from "../../../../worker"; // We need to pass the context to these somehow? export async function createProject({ - ctx, + appContext, }: { - ctx: Awaited>; + appContext: Awaited>; }) { - const userId = ctx.user.id; + const userId = appContext.user.id; const newProject = await db.project.create({ data: { diff --git a/experiments/cutl/src/lib/router.ts b/experiments/cutl/src/lib/router.ts index 7f751e026..12afa71a2 100644 --- a/experiments/cutl/src/lib/router.ts +++ b/experiments/cutl/src/lib/router.ts @@ -4,7 +4,7 @@ export type RouteOptions> = { request: Request; params: TParams; env: Env; - ctx?: any; + appContext?: any; }; type RouteMiddleware = ( @@ -70,19 +70,19 @@ export function defineRoutes(routes: RouteDefinition[]): { routes: RouteDefinition[]; handle: ({ request, - ctx, + appContext, env, renderPage, }: { request: Request; - ctx: any; + appContext: any; env: Env; renderPage: (page: any, props: Record) => Promise; }) => Response | Promise; } { return { routes, - async handle({ request, ctx, env, renderPage }) { + async handle({ request, appContext, env, renderPage }) { try { const url = new URL(request.url); let path = url.pathname; @@ -122,7 +122,7 @@ export function defineRoutes(routes: RouteDefinition[]): { ); } - const r = await h({ request, params, ctx, env }); + const r = await h({ request, params, appContext, env }); if (r instanceof Response) { return r; } @@ -131,12 +131,15 @@ export function defineRoutes(routes: RouteDefinition[]): { if (isRouteComponent(handler)) { // TODO(peterp, 2025-01-30): Serialize the request - return await renderPage(handler as RouteComponent, { params, ctx }); + return await renderPage(handler as RouteComponent, { + params, + appContext, + }); } else { return await (handler({ request, params, - ctx, + appContext, env, }) as Promise); } diff --git a/experiments/cutl/src/register/worker.ts b/experiments/cutl/src/register/worker.ts index 70f5c6bc7..ff090dbd6 100644 --- a/experiments/cutl/src/register/worker.ts +++ b/experiments/cutl/src/register/worker.ts @@ -17,18 +17,22 @@ export function registerServerReference( return baseRegisterServerReference(action, id, name); } -export function registerClientReference>(id: string, exportName: string, target: Target) { +export function registerClientReference>( + id: string, + exportName: string, + target: Target, +) { const reference = baseRegisterClientReference({}, id, exportName); - return Object.defineProperties( - target, - { - ...Object.getOwnPropertyDescriptors(reference), - $$async: { value: true }, - }, - ); + return Object.defineProperties(target, { + ...Object.getOwnPropertyDescriptors(reference), + $$async: { value: true }, + }); } -export async function rscActionHandler(req: Request, ctx: any): Promise { +export async function rscActionHandler( + req: Request, + appContext: any, +): Promise { const url = new URL(req.url); const contentType = req.headers.get("content-type"); @@ -44,5 +48,5 @@ export async function rscActionHandler(req: Request, ctx: any): Promise throw new Error(`Action ${actionId} is not a function`); } - return action(...args, { ctx }); + return action(...args, { appContext }); } diff --git a/experiments/cutl/src/session.tsx b/experiments/cutl/src/session.tsx index 01e8ee3e2..1c75230b8 100644 --- a/experiments/cutl/src/session.tsx +++ b/experiments/cutl/src/session.tsx @@ -1,9 +1,9 @@ import { DurableObject } from "cloudflare:workers"; -import { MAX_TOKEN_DURATION } from './constants'; +import { MAX_TOKEN_DURATION } from "./constants"; interface Session { userId: string; - createdAt: number + createdAt: number; } export class SessionDO extends DurableObject { @@ -17,9 +17,9 @@ export class SessionDO extends DurableObject { const session: Session = { userId, createdAt: Date.now(), - } + }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -29,23 +29,23 @@ export class SessionDO extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); // context(justinvdm, 2025-01-15): If the session DO exists but there's no session state // it means we received a valid session id (it passed the signature check), but the session // has been revoked. if (!session) { return { - error: 'Invalid session' - } + error: "Invalid session", + }; } // context(justinvdm, 2025-01-15): If the session is expired, we need to revoke it. if (session.createdAt + MAX_TOKEN_DURATION < Date.now()) { await this.revokeSession(); return { - error: 'Session expired' - } + error: "Session expired", + }; } this.session = session; @@ -53,7 +53,7 @@ export class SessionDO extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/cutl/src/worker.tsx b/experiments/cutl/src/worker.tsx index 7244add87..19db494db 100644 --- a/experiments/cutl/src/worker.tsx +++ b/experiments/cutl/src/worker.tsx @@ -35,8 +35,8 @@ export const getContext = async ( }; }; -function authRequired({ ctx }: any) { - if (!ctx.user) { +function authRequired({ appContext }: any) { + if (!appContext.user) { return new Response("Unauthorized", { status: 401 }); } } @@ -47,8 +47,8 @@ export default { const router = defineRoutes([ // index([ - // function ({ ctx }) { - // if (ctx.user.id) { + // function ({ appContext }) { + // if (appContext.user.id) { // return new Response(null, { // status: 302, // headers: { Location: link('/project/list') }, @@ -79,13 +79,13 @@ export default { // the request will not hang. This makes this issue particularly hard to debug. await db.$queryRaw`SELECT 1`; - let ctx: Awaited> = { + let appContext: Awaited> = { user: { id: "", email: "" }, }; let session: Awaited> | undefined; try { session = await getSession(request, env); - ctx = await getContext(session); + appContext = await getContext(session); } catch (e) { console.error("Error getting session", e); } @@ -95,7 +95,7 @@ export default { const isRSCActionHandler = url.searchParams.has("__rsc_action_id"); let actionResult: any; if (isRSCActionHandler) { - actionResult = await rscActionHandler(request, ctx); // maybe we should include params and ctx in the action handler? + actionResult = await rscActionHandler(request, appContext); // maybe we should include params and appContext in the action handler? } if (url.pathname.startsWith("/assets/")) { @@ -130,7 +130,7 @@ export default { const response = await router.handle({ request, - ctx, + appContext, env, renderPage, }); diff --git a/experiments/realtime-poc/src/app/pages/note/functions.ts b/experiments/realtime-poc/src/app/pages/note/functions.ts index 308ae2327..a3fe218a5 100644 --- a/experiments/realtime-poc/src/app/pages/note/functions.ts +++ b/experiments/realtime-poc/src/app/pages/note/functions.ts @@ -2,18 +2,18 @@ import { RouteOptions } from "@redwoodjs/sdk/router"; -export const getContent = async (key: string, ctx?: RouteOptions) => { - const doId = ctx!.env.NOTE_DURABLE_OBJECT.idFromName(key); - const noteDO = ctx!.env.NOTE_DURABLE_OBJECT.get(doId); +export const getContent = async (key: string, opts?: RouteOptions) => { + const doId = opts!.env.NOTE_DURABLE_OBJECT.idFromName(key); + const noteDO = opts!.env.NOTE_DURABLE_OBJECT.get(doId); return noteDO.getContent(); }; export const updateContent = async ( key: string, content: string, - ctx?: RouteOptions, + opts?: RouteOptions, ) => { - const doId = ctx!.env.NOTE_DURABLE_OBJECT.idFromName(key); - const noteDO = ctx!.env.NOTE_DURABLE_OBJECT.get(doId); + const doId = opts!.env.NOTE_DURABLE_OBJECT.idFromName(key); + const noteDO = opts!.env.NOTE_DURABLE_OBJECT.get(doId); await noteDO.setContent(content); }; diff --git a/experiments/realtime-poc/src/session/durableObject.ts b/experiments/realtime-poc/src/session/durableObject.ts index cfcfb9580..46af0314a 100644 --- a/experiments/realtime-poc/src/session/durableObject.ts +++ b/experiments/realtime-poc/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/yt-dos/src/worker.tsx b/experiments/yt-dos/src/worker.tsx index bba894367..6b4add0c4 100644 --- a/experiments/yt-dos/src/worker.tsx +++ b/experiments/yt-dos/src/worker.tsx @@ -8,9 +8,9 @@ type AppContext = { }; export default defineApp([ - ({ ctx }) => { - // setup ctx here - ctx; + ({ appContext }) => { + // setup appContext here + appContext; }, // @ts-ignore render(Document, [ diff --git a/experiments/zoomshare/src/app/pages/auth/functions.ts b/experiments/zoomshare/src/app/pages/auth/functions.ts index d98b74daf..9d4ee675d 100644 --- a/experiments/zoomshare/src/app/pages/auth/functions.ts +++ b/experiments/zoomshare/src/app/pages/auth/functions.ts @@ -15,9 +15,9 @@ import { db } from "@/db"; export async function startPasskeyRegistration( username: string, - ctx?: RouteOptions, + appContext?: RouteOptions, ) { - const { headers, env } = ctx!; + const { headers, env } = appContext!; const options = await generateRegistrationOptions({ rpName: env.APP_NAME, @@ -39,9 +39,9 @@ export async function startPasskeyRegistration( export async function finishPasskeyRegistration( username: string, registration: RegistrationResponseJSON, - ctx?: RouteOptions, + appContext?: RouteOptions, ) { - const { request, headers, env } = ctx!; + const { request, headers, env } = appContext!; const { origin } = new URL(request.url); const session = await sessions.load(request); @@ -82,8 +82,8 @@ export async function finishPasskeyRegistration( return true; } -export async function startPasskeyLogin(ctx?: RouteOptions) { - const { request, headers, env } = ctx!; +export async function startPasskeyLogin(appContext?: RouteOptions) { + const { request, headers, env } = appContext!; const options = await generateAuthenticationOptions({ rpID: env.RP_ID, @@ -98,9 +98,9 @@ export async function startPasskeyLogin(ctx?: RouteOptions) { export async function finishPasskeyLogin( login: AuthenticationResponseJSON, - ctx?: RouteOptions, + appContext?: RouteOptions, ) { - const { request, headers, env } = ctx!; + const { request, headers, env } = appContext!; const { origin } = new URL(request.url); const session = await sessions.load(request); diff --git a/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx b/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx index 1c821b12c..5e91f2ce8 100644 --- a/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx +++ b/experiments/zoomshare/src/app/pages/meetings/MeetingList.tsx @@ -1,7 +1,7 @@ import type { AppContext } from "@/worker"; import { db } from "@/db"; -export async function MeetingList({ ctx }: { ctx: Context }) { +export async function MeetingList({ appContext }: { appContext: AppContext }) { const meetings = await db.meeting.findMany({ orderBy: { createdAt: "desc", diff --git a/experiments/zoomshare/src/session/durableObject.ts b/experiments/zoomshare/src/session/durableObject.ts index cfcfb9580..46af0314a 100644 --- a/experiments/zoomshare/src/session/durableObject.ts +++ b/experiments/zoomshare/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/zoomshare/src/worker.tsx b/experiments/zoomshare/src/worker.tsx index 7ed7ff22a..5b97df629 100644 --- a/experiments/zoomshare/src/worker.tsx +++ b/experiments/zoomshare/src/worker.tsx @@ -37,7 +37,7 @@ async function validateZoomWebhook(body: any, env: Env) { } const app = defineApp([ - async ({ env, ctx, request }) => { + async ({ env, appContext, request }) => { await setupDb(env); }, @@ -49,7 +49,7 @@ const app = defineApp([ ]), prefix("/webhook", [ route("/meeting.recording.completed", [ - async function ({ request, env, ctx }) { + async function ({ request, env, appContext }) { if ( request.method !== "POST" && request.headers.get("Content-Type") !== "application/json" diff --git a/sdk/src/runtime/lib/router.ts b/sdk/src/runtime/lib/router.ts index 8076f4bdb..209d40fe9 100644 --- a/sdk/src/runtime/lib/router.ts +++ b/sdk/src/runtime/lib/router.ts @@ -1,21 +1,21 @@ import { isValidElementType } from "react-is"; import { ExecutionContext } from "@cloudflare/workers-types"; -export type HandlerOptions> = { +export type HandlerOptions> = { request: Request; env: Env; cf: ExecutionContext; - ctx: TContext; + appContext: TAppContext; headers: Headers; rw: RwContext; }; -export type RouteOptions, TParams = any> = { +export type RouteOptions, TParams = any> = { cf: ExecutionContext; request: Request; params: TParams; env: Env; - ctx: TContext; + appContext: TAppContext; headers: Headers; rw: RwContext; }; @@ -47,7 +47,7 @@ export type RwContext = { handleAction: (opts: RouteOptions) => Promise; }; -export type RouteMiddleware = ( +export type RouteMiddleware = ( opts: RouteOptions, ) => | Response @@ -55,19 +55,22 @@ export type RouteMiddleware = ( | void | Promise | Promise; -type RouteFunction = ( - opts: RouteOptions, +type RouteFunction = ( + opts: RouteOptions, ) => Response | Promise; -type RouteComponent = ( - opts: RouteOptions, +type RouteComponent = ( + opts: RouteOptions, ) => JSX.Element | Promise; -type RouteHandler = - | RouteFunction - | RouteComponent +type RouteHandler = + | RouteFunction + | RouteComponent | [ ...RouteMiddleware[], - RouteFunction | RouteComponent, + ( + | RouteFunction + | RouteComponent + ), ]; export type Route = @@ -75,14 +78,17 @@ export type Route = | RouteDefinition | Array>; -export type RouteDefinition, TParams = any> = { +export type RouteDefinition< + TAppContext = Record, + TParams = any, +> = { path: string; - handler: RouteHandler; + handler: RouteHandler; }; -type RouteMatch, TParams = any> = { +type RouteMatch, TParams = any> = { params: TParams; - handler: RouteHandler; + handler: RouteHandler; }; function matchPath( @@ -132,21 +138,21 @@ function flattenRoutes( }, []) as (RouteMiddleware | RouteDefinition)[]; } -export function defineRoutes>( +export function defineRoutes>( routes: Route[], ): { routes: Route[]; handle: ({ cf, request, - ctx, + appContext, env, rw, headers, }: { cf: ExecutionContext; request: Request; - ctx: TContext; + appContext: TAppContext; env: Env; rw: RwContext; headers: Headers; @@ -155,7 +161,7 @@ export function defineRoutes>( const flattenedRoutes = flattenRoutes(routes); return { routes: flattenedRoutes, - async handle({ cf, request, ctx, env, rw, headers }) { + async handle({ cf, request, appContext, env, rw, headers }) { const url = new URL(request.url); let path = url.pathname; @@ -170,7 +176,7 @@ export function defineRoutes>( cf, request, params: {}, - ctx, + appContext, env, rw, headers, @@ -209,7 +215,7 @@ export function defineRoutes>( const props = { params, env, - ctx, + appContext, rw: { nonce: rw.nonce }, }; return await rw.renderPage({ @@ -234,10 +240,10 @@ export function defineRoutes>( }; } -export function route( +export function route( path: string, - handler: RouteHandler, -): RouteDefinition { + handler: RouteHandler, +): RouteDefinition { if (!path.endsWith("/")) { path = path + "/"; } @@ -248,16 +254,16 @@ export function route( }; } -export function index( - handler: RouteHandler, -): RouteDefinition { +export function index( + handler: RouteHandler, +): RouteDefinition { return route("/", handler); } -export function prefix( +export function prefix( prefix: string, - routes: ReturnType>[], -): RouteDefinition[] { + routes: ReturnType>[], +): RouteDefinition[] { return routes.map((r) => { return { path: prefix + r.path, @@ -266,7 +272,7 @@ export function prefix( }); } -export function document( +export function document( Document: React.FC<{ children: React.ReactNode }>, routes: Route[], ): Route[] { diff --git a/sdk/src/runtime/worker.tsx b/sdk/src/runtime/worker.tsx index e815b9161..0e25da1b4 100644 --- a/sdk/src/runtime/worker.tsx +++ b/sdk/src/runtime/worker.tsx @@ -24,7 +24,7 @@ declare global { }; } -export const defineApp = (routes: Route[]) => { +export const defineApp = (routes: Route[]) => { return { fetch: async (request: Request, env: Env, cf: ExecutionContext) => { globalThis.__webpack_require__ = ssrWebpackRequire; @@ -54,12 +54,12 @@ export const defineApp = (routes: Route[]) => { const isRSCRequest = url.searchParams.has("__rsc"); const handleAction = async ( - opts: RouteOptions>, + opts: RouteOptions>, ) => { const isRSCActionHandler = url.searchParams.has("__rsc_action_id"); if (isRSCActionHandler) { - return await rscActionHandler(request, opts); // maybe we should include params and ctx in the action handler? + return await rscActionHandler(request, opts); // maybe we should include params and appContext in the action handler? } }; @@ -77,8 +77,8 @@ export const defineApp = (routes: Route[]) => { if ( Object.prototype.hasOwnProperty.call(Page, "$$isClientReference") ) { - const { ctx, params } = fullPageProps; - props = { ctx, params } as PageProps; + const { appContext, params } = fullPageProps; + props = { appContext, params } as PageProps; } if ( @@ -87,8 +87,8 @@ export const defineApp = (routes: Route[]) => { "$$isClientReference", ) ) { - const { ctx, params } = fullPageProps; - documentProps = { ctx, params } as DocumentProps; + const { appContext, params } = fullPageProps; + documentProps = { appContext, params } as DocumentProps; } const nonce = fullPageProps.rw.nonce; @@ -133,7 +133,7 @@ export const defineApp = (routes: Route[]) => { cf, request, headers: userHeaders, - ctx: {} as Context, + appContext: {} as AppContext, env, rw: { Document: DefaultDocument, diff --git a/starters/drizzle/src/app/pages/Home.tsx b/starters/drizzle/src/app/pages/Home.tsx index 893c3d74a..cb70166b2 100644 --- a/starters/drizzle/src/app/pages/Home.tsx +++ b/starters/drizzle/src/app/pages/Home.tsx @@ -2,8 +2,8 @@ import { users } from "../../db/schema"; import { RouteOptions } from "@redwoodjs/sdk/router"; import { AppContext } from "@/worker"; -export async function Home({ ctx }: RouteOptions) { - const allUsers = await ctx.db.select().from(users).all(); +export async function Home({ appContext }: RouteOptions) { + const allUsers = await appContext.db.select().from(users).all(); return (

Hello World

diff --git a/starters/drizzle/src/worker.tsx b/starters/drizzle/src/worker.tsx index 583e65d54..371e027c9 100644 --- a/starters/drizzle/src/worker.tsx +++ b/starters/drizzle/src/worker.tsx @@ -15,9 +15,9 @@ export type AppContext = { export default defineApp([ setCommonHeaders(), - ({ ctx, env }) => { - // setup db in ctx - ctx.db = drizzle(env.DB); + ({ appContext, env }) => { + // setup db in appContext + appContext.db = drizzle(env.DB); }, render(Document, [index([Home])]), ]); diff --git a/starters/minimal/src/worker.tsx b/starters/minimal/src/worker.tsx index 8f9fe8cae..c98f17083 100644 --- a/starters/minimal/src/worker.tsx +++ b/starters/minimal/src/worker.tsx @@ -8,9 +8,9 @@ type AppContext = {}; export default defineApp([ setCommonHeaders(), - ({ ctx }) => { - // setup ctx here - ctx; + ({ appContext }) => { + // setup appContext here + appContext; }, render(Document, [index([Home])]), ]); diff --git a/starters/passkey-auth/src/app/pages/Home.tsx b/starters/passkey-auth/src/app/pages/Home.tsx index ce8eb5743..032763d12 100644 --- a/starters/passkey-auth/src/app/pages/Home.tsx +++ b/starters/passkey-auth/src/app/pages/Home.tsx @@ -1,11 +1,11 @@ import { AppContext } from "@/worker"; -export function Home({ ctx }: { ctx: Context }) { +export function Home({ appContext }: { appContext: AppContext }) { return (

- {ctx.user?.username - ? `You are logged in as user ${ctx.user.username}` + {appContext.user?.username + ? `You are logged in as user ${appContext.user.username}` : "You are not logged in"}

diff --git a/starters/passkey-auth/src/session/durableObject.ts b/starters/passkey-auth/src/session/durableObject.ts index cfcfb9580..46af0314a 100644 --- a/starters/passkey-auth/src/session/durableObject.ts +++ b/starters/passkey-auth/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/starters/passkey-auth/src/worker.tsx b/starters/passkey-auth/src/worker.tsx index 10f52f092..1b17cb2eb 100644 --- a/starters/passkey-auth/src/worker.tsx +++ b/starters/passkey-auth/src/worker.tsx @@ -17,12 +17,12 @@ export type AppContext = { export default defineApp([ setCommonHeaders(), - async ({ env, ctx, request, headers }) => { + async ({ env, appContext, request, headers }) => { await setupDb(env); setupSessionStore(env); try { - ctx.session = await sessions.load(request); + appContext.session = await sessions.load(request); } catch (error) { if (error instanceof ErrorResponse && error.code === 401) { await sessions.remove(request, headers); @@ -37,18 +37,18 @@ export default defineApp([ throw error; } - if (ctx.session?.userId) { - ctx.user = await db.user.findUnique({ + if (appContext.session?.userId) { + appContext.user = await db.user.findUnique({ where: { - id: ctx.session.userId, + id: appContext.session.userId, }, }); } }, render(Document, [ index([ - ({ ctx }) => { - if (!ctx.user) { + ({ appContext }) => { + if (!appContext.user) { return new Response(null, { status: 302, headers: { Location: "/user/login" }, diff --git a/starters/prisma/src/worker.tsx b/starters/prisma/src/worker.tsx index ba88ed59d..c47ed101c 100644 --- a/starters/prisma/src/worker.tsx +++ b/starters/prisma/src/worker.tsx @@ -8,7 +8,7 @@ type AppContext = {}; export default defineApp([ setCommonHeaders(), - async ({ ctx, env, request }) => { + async ({ appContext, env, request }) => { await setupDb(env); }, render(Document, [index([Home])]), diff --git a/starters/sessions/src/app/pages/Home.tsx b/starters/sessions/src/app/pages/Home.tsx index 7b0654ddc..32716f677 100644 --- a/starters/sessions/src/app/pages/Home.tsx +++ b/starters/sessions/src/app/pages/Home.tsx @@ -1,11 +1,11 @@ import { AppContext } from "@/worker"; -export function Home({ ctx }: { ctx: Context }) { +export function Home({ appContext }: { appContext: AppContext }) { return (

- {ctx.session?.userId - ? `You are logged in as user ${ctx.session.userId}` + {appContext.session?.userId + ? `You are logged in as user ${appContext.session.userId}` : "You are not logged in"}

diff --git a/starters/sessions/src/session/durableObject.ts b/starters/sessions/src/session/durableObject.ts index 93bb24e65..52ddab099 100644 --- a/starters/sessions/src/session/durableObject.ts +++ b/starters/sessions/src/session/durableObject.ts @@ -19,7 +19,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); if (!session) { return { @@ -49,7 +49,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/starters/sessions/src/worker.tsx b/starters/sessions/src/worker.tsx index 78d0ba235..94e11b65d 100644 --- a/starters/sessions/src/worker.tsx +++ b/starters/sessions/src/worker.tsx @@ -15,11 +15,11 @@ export type AppContext = { export default defineApp([ setCommonHeaders(), - async ({ env, ctx, request, headers }) => { + async ({ env, appContext, request, headers }) => { setupSessionStore(env); try { - ctx.session = await sessions.load(request); + appContext.session = await sessions.load(request); } catch (error) { if (error instanceof ErrorResponse && error.code === 401) { await sessions.remove(request, headers); diff --git a/starters/standard/src/app/pages/Home.tsx b/starters/standard/src/app/pages/Home.tsx index ce8eb5743..032763d12 100644 --- a/starters/standard/src/app/pages/Home.tsx +++ b/starters/standard/src/app/pages/Home.tsx @@ -1,11 +1,11 @@ import { AppContext } from "@/worker"; -export function Home({ ctx }: { ctx: Context }) { +export function Home({ appContext }: { appContext: AppContext }) { return (

- {ctx.user?.username - ? `You are logged in as user ${ctx.user.username}` + {appContext.user?.username + ? `You are logged in as user ${appContext.user.username}` : "You are not logged in"}

diff --git a/starters/standard/src/session/durableObject.ts b/starters/standard/src/session/durableObject.ts index cfcfb9580..46af0314a 100644 --- a/starters/standard/src/session/durableObject.ts +++ b/starters/standard/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.ctx.storage.put("session", session); + await this.appContext.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.ctx.storage.get("session"); + const session = await this.appContext.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.ctx.storage.delete("session"); + await this.appContext.storage.delete("session"); this.session = undefined; } } diff --git a/starters/standard/src/worker.tsx b/starters/standard/src/worker.tsx index 321d2cf82..1a2dd625d 100644 --- a/starters/standard/src/worker.tsx +++ b/starters/standard/src/worker.tsx @@ -17,12 +17,12 @@ export type AppContext = { export default defineApp([ setCommonHeaders(), - async ({ env, ctx, request, headers }) => { + async ({ env, appContext, request, headers }) => { await setupDb(env); setupSessionStore(env); try { - ctx.session = await sessions.load(request); + appContext.session = await sessions.load(request); } catch (error) { if (error instanceof ErrorResponse && error.code === 401) { await sessions.remove(request, headers); @@ -37,10 +37,10 @@ export default defineApp([ throw error; } - if (ctx.session?.userId) { - ctx.user = await db.user.findUnique({ + if (appContext.session?.userId) { + appContext.user = await db.user.findUnique({ where: { - id: ctx.session.userId, + id: appContext.session.userId, }, }); } @@ -48,8 +48,8 @@ export default defineApp([ render(Document, [ route("/", () => new Response("Hello, World!")), route("/protected", [ - ({ ctx }) => { - if (!ctx.user) { + ({ appContext }) => { + if (!appContext.user) { return new Response(null, { status: 302, headers: { Location: "/user/login" }, From 3716699da246213b316d23f410c8ea4ebaa232f9 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:13:11 +0200 Subject: [PATCH 4/9] progress --- sdk/src/runtime/lib/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/runtime/lib/router.ts b/sdk/src/runtime/lib/router.ts index 209d40fe9..e6fb35814 100644 --- a/sdk/src/runtime/lib/router.ts +++ b/sdk/src/runtime/lib/router.ts @@ -272,7 +272,7 @@ export function prefix( }); } -export function document( +export function render( Document: React.FC<{ children: React.ReactNode }>, routes: Route[], ): Route[] { From 0665ea558dbd60b68fd8230d131daa60314e2621 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:14:49 +0200 Subject: [PATCH 5/9] progress --- starters/passkey-auth/src/session/durableObject.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/starters/passkey-auth/src/session/durableObject.ts b/starters/passkey-auth/src/session/durableObject.ts index 46af0314a..cfcfb9580 100644 --- a/starters/passkey-auth/src/session/durableObject.ts +++ b/starters/passkey-auth/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } From 395524019798cd8e522d4cddeabaf18b9cb5f780 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:15:16 +0200 Subject: [PATCH 6/9] progress --- starters/sessions/src/session/durableObject.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/starters/sessions/src/session/durableObject.ts b/starters/sessions/src/session/durableObject.ts index 52ddab099..93bb24e65 100644 --- a/starters/sessions/src/session/durableObject.ts +++ b/starters/sessions/src/session/durableObject.ts @@ -19,7 +19,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); if (!session) { return { @@ -49,7 +49,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } From b285673392248ab751bef2325b5d7d09d2549d28 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:15:35 +0200 Subject: [PATCH 7/9] progress --- starters/standard/src/session/durableObject.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/starters/standard/src/session/durableObject.ts b/starters/standard/src/session/durableObject.ts index 46af0314a..cfcfb9580 100644 --- a/starters/standard/src/session/durableObject.ts +++ b/starters/standard/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } From 3d3782618e44d9ab4c78596dcba1baebfb9d28e8 Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:22:11 +0200 Subject: [PATCH 8/9] progress --- docs/src/content/docs/core/routing.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/content/docs/core/routing.mdx b/docs/src/content/docs/core/routing.mdx index 6a25083f7..5b0e7782e 100644 --- a/docs/src/content/docs/core/routing.mdx +++ b/docs/src/content/docs/core/routing.mdx @@ -100,7 +100,7 @@ The request handler function takes in the following options: 1. `request`: The request object. 2. `params`: The matched parameters from the request URL. 3. `env`: The Cloudflare environment. -4. `appContext`: The context object (See [Middleware & Context](#middleware-context)). +4. `appContext`: The context object (See [Middleware & `AppContext`](#middleware--app-context)). 5. `cf:` Cloudflare's [Execution Context API](https://developers.cloudflare.com/workers/runtime-apis/context/) methods, e.g. `waitUntil()` Return values: @@ -134,9 +134,9 @@ For the `/blog/:slug/edit` route, the `isAuthenticated` function will be execute --- ``` -## Middleware & Context +## Middleware & `AppContext` -Context is a mutable object that is passed to each request handler, interruptors, and React Server Functions. It's used to share data between the different parts of your application. You populate the context on a per-request basis via Middleware. +`appContext` is a mutable object that is passed to each request handler, interruptors, and React Server Functions. It's used to share data between the different parts of your application. You populate the context on a per-request basis via Middleware. Middleware runs before the request is matched to a route. You can specify multiple middleware functions, they'll be executed in the order they are defined. From b601808a0670a6582a69f85d942a16a7738366bf Mon Sep 17 00:00:00 2001 From: justinvdm Date: Mon, 31 Mar 2025 11:25:14 +0200 Subject: [PATCH 9/9] progress --- experiments/billable/src/session.tsx | 6 +++--- experiments/cutable/src/session.tsx | 6 +++--- experiments/cutl/src/session.tsx | 6 +++--- experiments/realtime-poc/src/session/durableObject.ts | 6 +++--- experiments/zoomshare/src/session/durableObject.ts | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/experiments/billable/src/session.tsx b/experiments/billable/src/session.tsx index e54564b0d..4d3dee7e3 100644 --- a/experiments/billable/src/session.tsx +++ b/experiments/billable/src/session.tsx @@ -19,7 +19,7 @@ export class SessionDO extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDO extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); // context(justinvdm, 2025-01-15): If the session DO exists but there's no session state // it means we received a valid session id (it passed the signature check), but the session @@ -53,7 +53,7 @@ export class SessionDO extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/cutable/src/session.tsx b/experiments/cutable/src/session.tsx index 1c75230b8..212289176 100644 --- a/experiments/cutable/src/session.tsx +++ b/experiments/cutable/src/session.tsx @@ -19,7 +19,7 @@ export class SessionDO extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDO extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); // context(justinvdm, 2025-01-15): If the session DO exists but there's no session state // it means we received a valid session id (it passed the signature check), but the session @@ -53,7 +53,7 @@ export class SessionDO extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/cutl/src/session.tsx b/experiments/cutl/src/session.tsx index 1c75230b8..212289176 100644 --- a/experiments/cutl/src/session.tsx +++ b/experiments/cutl/src/session.tsx @@ -19,7 +19,7 @@ export class SessionDO extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -29,7 +29,7 @@ export class SessionDO extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); // context(justinvdm, 2025-01-15): If the session DO exists but there's no session state // it means we received a valid session id (it passed the signature check), but the session @@ -53,7 +53,7 @@ export class SessionDO extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/realtime-poc/src/session/durableObject.ts b/experiments/realtime-poc/src/session/durableObject.ts index 46af0314a..cfcfb9580 100644 --- a/experiments/realtime-poc/src/session/durableObject.ts +++ b/experiments/realtime-poc/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } } diff --git a/experiments/zoomshare/src/session/durableObject.ts b/experiments/zoomshare/src/session/durableObject.ts index 46af0314a..cfcfb9580 100644 --- a/experiments/zoomshare/src/session/durableObject.ts +++ b/experiments/zoomshare/src/session/durableObject.ts @@ -27,7 +27,7 @@ export class SessionDurableObject extends DurableObject { createdAt: Date.now(), }; - await this.appContext.storage.put("session", session); + await this.ctx.storage.put("session", session); this.session = session; return session; } @@ -37,7 +37,7 @@ export class SessionDurableObject extends DurableObject { return { value: this.session }; } - const session = await this.appContext.storage.get("session"); + const session = await this.ctx.storage.get("session"); if (!session) { return { @@ -57,7 +57,7 @@ export class SessionDurableObject extends DurableObject { } async revokeSession() { - await this.appContext.storage.delete("session"); + await this.ctx.storage.delete("session"); this.session = undefined; } }