Skip to content

v0.0.53

Choose a tag to compare

@justinvdm justinvdm released this 08 Apr 19:18
· 1634 commits to main since this release

What's Changed

Breaking Changes

  1. The appContext prop has been renamed to ctx everywhere
  2. Environment variables must now be imported from cloudflare:workers
  3. Action handlers (in functions.ts files) must now use requestInfo to access request data
  4. The RouteOptions and HandlerOptions types have been replaced by the RequestInfo type
  5. App context types are now configured via rw.d.ts instead of type parameters

Migration Guide

1. appContext Renamed to ctx

The shared context object, previously named appContext, has been renamed to ctx throughout the codebase:

// Before
function MyComponent({ appContext }: RouteOptions) {
  return <div>Hello {appContext.user?.username}</div>;
}

route("/dashboard", ({ appContext }) => {
  if (!appContext.user) {
    return redirect("/login");
  }
});

const middleware = ({ request, appContext }) => {
  appContext.someValue = "test";
};

// After
function MyComponent({ ctx }: RequestInfo) {
  return <div>Hello {ctx.user?.username}</div>;
}

route("/dashboard", ({ ctx }) => {
  if (!ctx.user) {
    return redirect("/login");
  }
});

const middleware = ({ request, ctx }) => {
  ctx.someValue = "test";
};

2. Environment Variables

Environment variables are now accessed through the cloudflare:workers import:

// Before
function MyComponent({ env }: RouteOptions) {
  const db = env.DB;
}

// After
import { env } from "cloudflare:workers";

function MyComponent() {
  const db = env.DB;
}

3. Action Handlers (functions.ts)

Action handlers must now use requestInfo to access request data:

// Before - functions.ts
export async function myAction(input: string, opts?: HandlerOptions) {
  const { request, appContext } = opts!;
  // ...
}

// After - functions.ts
import { requestInfo } from "@redwoodjs/sdk/worker";

export async function myAction(input: string) {
  const { request, headers, ctx } = requestInfo;
  // ...
}

4. Components and Routes

Components, routes and middleware now use the RequestInfo type instead of RouteOptions as their input type:

// Before
import { RouteOptions } from "@redwoodjs/sdk/worker";

export function Home({ appContext }: RouteOptions) {
  return (
    <div>
      <p>
        {appContext.user?.username
          ? `You are logged in as user ${appContext.user.username}`
          : "You are not logged in"}
      </p>
    </div>
  );
}

// After
import { RequestInfo } from "@redwoodjs/sdk/worker";

export function Home({ ctx }: RequestInfo) {
  return (
    <div>
      <p>
        {ctx.user?.username
          ? `You are logged in as user ${ctx.user.username}`
          : "You are not logged in"}
      </p>
    </div>
  );
}

// Before - Route
route("/protected", [
  ({ appContext }: RouteOptions) => {
    if (!appContext.user) {
      return new Response(null, {
        status: 302,
        headers: { Location: "/user/login" },
      });
    }
  },
  Home,
]);

// After - Route
route("/protected", [
  ({ ctx }: RequestInfo) => {
    if (!ctx.user) {
      return new Response(null, {
        status: 302,
        headers: { Location: "/user/login" },
      });
    }
  },
  Home,
]);

// Before - Middleware
import { RouteMiddleware } from "@redwoodjs/sdk/router";

export const authMiddleware =
  (): RouteMiddleware =>
  async ({ request, appContext }) => {
    const session = await sessions.load(request);
    if (session?.userId) {
      appContext.user = await db.user.findUnique({
        where: { id: session.userId },
      });
    }
  };

// After - Middleware
import { RouteMiddleware } from "@redwoodjs/sdk/router";

export const authMiddleware =
  (): RouteMiddleware =>
  async ({ request, ctx }) => {
    const session = await sessions.load(request);
    if (session?.userId) {
      ctx.user = await db.user.findUnique({
        where: { id: session.userId },
      });
    }
  };

5. App Context Configuration

The way app context is configured has changed from using type parameters to using declaration merging in a rw.d.ts file:

// Before
// src/worker.tsx
import type { User } from "@prisma/client";
import { Session } from "./session/durableObject";

export type AppContext = {
  session: Session | null;
  user: User | null;
};

export default defineApp<AppContext>([
  // ... app configuration
])

// After
// src/worker.tsx
import type { User } from "@prisma/client";
import { Session } from "./session/durableObject";

export type AppContext = {
  session: Session | null;
  user: User | null;
};

// types/rw.d.ts - New file
import { AppContext } from "../src/worker";

declare module "@redwoodjs/sdk/worker" {
  export interface DefaultAppContext extends AppContext {}
}

// tsconfig.json
{
  "compilerOptions": {
    // ... other options
    "types": [..., "./types/rw.d.ts"]
  }
}

// src/worker.tsx
export default defineApp([
  // ... app configuration
])

The rw.d.ts file is a TypeScript declaration file that allows you to extend existing types from the SDK. By placing it in a types directory in your tsconfig.json, you can ensure TypeScript picks up your custom type definitions.

Full Changelog: v0.0.52...v0.0.53