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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions e2e/templates/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@
"license": "ISC",
"description": "",
"devDependencies": {
"@cloudflare/vite-plugin": "^1.15.2",
"@cloudflare/workers-types": "^4.20250224.0",
"@orange-js/cli": "workspace:*",
"@orange-js/vite": "workspace:*",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"esbuild": "^0.24.2",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"typescript": "^5.8.2",
"vite": "^7.1.7",
"vite": "^7.2.4",
"vite-tsconfig-paths": "^5.1.4",
"wrangler": "^4.40.1"
"wrangler": "^4.50.0"
},
"dependencies": {
"@orange-js/actors": "workspace:",
"@orange-js/orange": "workspace:",
"@tailwindcss/vite": "^4.0.14",
"hono": "^4.6.20",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwindcss": "^4.0.14"
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
"pnpm": {
"onlyBuiltDependencies": [
"@biomejs/biome",
"@swc/core",
"@tailwindcss/oxide",
"esbuild",
"sharp",
"workerd"
]
}
Expand Down
14 changes: 5 additions & 9 deletions packages/actors/src/client.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
"use client";
import { useEffect, useState } from "react";

const createFromReadableStream = import.meta.env.SSR
? () => {
throw new Error("createFromReadableStream is not available in SSR");
}
: await import("@vitejs/plugin-rsc/browser").then(
(m) => m.createFromReadableStream
);

type ClientComponentProps = {
children: React.ReactNode;
actorName: string;
Expand All @@ -26,7 +18,7 @@ export function ClientComponent({
useEffect(() => {
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const ws = new WebSocket(
`${protocol}//${window.location.host}/${actorName}/${id}`
`${protocol}//${window.location.host}/${actorName}/${id}`,
);

ws.addEventListener("message", async (event) => {
Expand All @@ -38,6 +30,10 @@ export function ClientComponent({
controller.close();
},
});
const { createFromReadableStream } = await import(
"@vitejs/plugin-rsc/browser"
);

const created = await createFromReadableStream(stream);
setComponent((created as any).root);
});
Expand Down
14 changes: 7 additions & 7 deletions packages/actors/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ type RSCPayload = { root: React.ReactNode };

export class Actor<Env> extends CfActor<Env> {
Component(
props: Record<string, unknown>
props: Record<string, unknown>,
): React.ReactNode | Promise<React.ReactNode> {
return null;
}

async __rscStream(
name: string,
props: Record<string, any>
props: Record<string, any>,
): Promise<[ReadableStream, boolean]> {
const Component = (this[name as keyof this] as any).bind(this);
const rscStream = renderToReadableStream<RSCPayload>({
Expand All @@ -47,7 +47,7 @@ async function internalComponent<T extends Actor<Env>, Env>(
props: {
actor: ActorConstructor<T>;
name?: string;
} & PropsFromDurableObject<T, Env, "Component">
} & PropsFromDurableObject<T, Env, "Component">,
) {
if ("children" in props) {
throw new Error("Children are not currently supported");
Expand Down Expand Up @@ -76,7 +76,7 @@ async function internalComponent<T extends Actor<Env>, Env>(

const rscStream = await stub.__rscStream("Component", rest);
const payload = await createFromReadableStream<RSCPayload>(
rscStream[0] as ReadableStream
rscStream[0] as ReadableStream,
);

return {
Expand All @@ -88,14 +88,14 @@ async function internalComponent<T extends Actor<Env>, Env>(
type PropsFromDurableObject<
T extends Actor<Env>,
Env,
K extends keyof T
K extends keyof T,
> = T[K] extends (arg: infer Z) => React.ReactNode | Promise<React.ReactNode>
? Z
: never;

export type ActorConstructor<T extends Actor<any> = Actor<any>> = new (
state: ActorState,
env: any
env: any,
) => T;

export { getActor } from "@cloudflare/actors";
Expand All @@ -104,7 +104,7 @@ async function Component<T extends Actor<Env>, Env>(
props: {
actor: ActorConstructor<T>;
name?: string;
} & PropsFromDurableObject<T, Env, "Component">
} & PropsFromDurableObject<T, Env, "Component">,
) {
const { root, isObserved } = await internalComponent(props);

Expand Down
2 changes: 1 addition & 1 deletion packages/actors/src/observed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { renderToReadableStream } from "@vitejs/plugin-rsc/rsc";

type ClassMethodDecorator<Args extends any[], Return> = (
value: (...args: Args) => Return,
context: ClassMethodDecoratorContext
context: ClassMethodDecoratorContext,
) => any;

export const observedSymbol = Symbol("orange:observed");
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"dedent": "^1.5.3",
"typescript": "^5.7.2",
"vite": "6.2",
"wrangler": "^4.7.2"
"wrangler": "^4.50.0"
},
"files": [
"dist",
Expand Down
32 changes: 16 additions & 16 deletions packages/cli/src/commands/provision/postgres.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {
start: "Fetching existing databases...",
success: (value) => `Found ${value.result.length} existing databases`,
error: "Failed to fetch existing databases",
}
},
);

const existingDatabases = hyperdriveDatbases.result.map((db) => db.name);
Expand Down Expand Up @@ -132,7 +132,7 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {
success: (value) =>
`Database ${databaseName} provisioned as ${orange(value.id)}`,
error: "Failed to provision database",
}
},
);

patchConfig(
Expand All @@ -146,7 +146,7 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {
},
],
},
true
true,
);

const createClient = await confirm({
Expand All @@ -162,15 +162,15 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {
connectFileTemplate(
databaseName,
'import { Client } from "pg";',
`new Client(env.${camelCase(databaseName)}.connectionString)`
)
`new Client(env.${camelCase(databaseName)}.connectionString)`,
),
)
.with("postgres", () =>
connectFileTemplate(
databaseName,
'import postgres from "postgres";',
`postgres(env.${camelCase(databaseName)}.connectionString)`
)
`postgres(env.${camelCase(databaseName)}.connectionString)`,
),
)
.with("drizzle-orm-pg", () =>
connectFileTemplate(
Expand All @@ -179,8 +179,8 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {
'import { drizzle } from "drizzle-orm/node-postgres";',
'import * as schema from "./schema.server";',
],
`drizzle(env.${camelCase(databaseName)}.connectionString, { schema })`
)
`drizzle(env.${camelCase(databaseName)}.connectionString, { schema })`,
),
)
.with("drizzle-orm-postgres", () =>
connectFileTemplate(
Expand All @@ -189,8 +189,8 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {
'import { drizzle } from "drizzle-orm/postgres-js";',
'import * as schema from "./schema.server";',
],
`drizzle(env.${camelCase(databaseName)}.connectionString, { schema })`
)
`drizzle(env.${camelCase(databaseName)}.connectionString, { schema })`,
),
)
.exhaustive();

Expand All @@ -209,17 +209,17 @@ export async function provisionPostgres(client: Cloudflare, accountId: string) {

step(
`Created connection to postgres accessible via \`${c.dim(
`env.${camelCase(databaseName)}`
)}\` and \`${c.dim(`context.${camelCase(databaseName)}`)}\``
`env.${camelCase(databaseName)}`,
)}\` and \`${c.dim(`context.${camelCase(databaseName)}`)}\``,
);

warn(
dedent`
Add \`${orange("connect")}\` from \`${orange(
"app/database.context.ts"
"app/database.context.ts",
)}\` to your entrypoint defined in \`${orange("app/entry.server.tsx")}\`
See more at ${orange("https://orange-js.dev/docs/context")}
`.trim()
`.trim(),
);
}

Expand Down Expand Up @@ -275,7 +275,7 @@ async function determineClient(): Promise<
function connectFileTemplate(
databaseName: string,
imports: string | string[],
databaseExpr: string
databaseExpr: string,
) {
return dedent`
import { env } from "cloudflare:workers";
Expand Down
26 changes: 13 additions & 13 deletions packages/cli/src/commands/provision/sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export async function provisionSqlite(client: Cloudflare, accountId: string) {
start: "Creating database...",
success: () => "Database created",
error: "Failed to create database",
}
},
);

const extraDbConfig = isDrizzleInstalled()
Expand All @@ -91,7 +91,7 @@ export async function provisionSqlite(client: Cloudflare, accountId: string) {
},
],
},
true
true,
);

await loader(generateWranglerTypes(), {
Expand All @@ -107,35 +107,35 @@ export async function provisionSqlite(client: Cloudflare, accountId: string) {
'import { drizzle } from "drizzle-orm/d1";',
'import * as schema from "./schema.server";',
],
`drizzle(env.${camelCase(sqliteName)}, { schema })`
`drizzle(env.${camelCase(sqliteName)}, { schema })`,
);

writeFileSync(join(process.cwd(), "app/database.server.ts"), databaseFile);

log(
c.dim("You'll need to create a schema file in your app directory."),
c.dim("See more at https://orm.drizzle.team/docs/sql-schema-declaration")
c.dim("See more at https://orm.drizzle.team/docs/sql-schema-declaration"),
);

step(
`Created SQLite database accessible via \`${c.dim(
`context.${camelCase(sqliteName)}`
)}\``
`context.${camelCase(sqliteName)}`,
)}\``,
);

warn(
dedent`
Add \`${orange("database")}\` from \`${orange(
"app/database.context.ts"
"app/database.context.ts",
)}\` to your entrypoint defined in \`${orange("app/entry.server.tsx")}\`
See more at ${orange("https://orange-js.dev/docs/context")}
`.trim()
`.trim(),
);
} else {
step(
`Created SQLite database accessible via \`${c.dim(
`env.${camelCase(sqliteName)}`
)}\``
`env.${camelCase(sqliteName)}`,
)}\``,
);
}
}
Expand All @@ -150,7 +150,7 @@ async function existingDatabaseNames(client: Cloudflare, accountId: string) {
names.push(
...existingDatabases.result
.map((db) => db.name?.toLowerCase())
.filter((name) => name !== undefined)
.filter((name) => name !== undefined),
);

while (existingDatabases.result.length === 100) {
Expand All @@ -163,7 +163,7 @@ async function existingDatabaseNames(client: Cloudflare, accountId: string) {
names.push(
...existingDatabases.result
.map((db) => db.name?.toLowerCase())
.filter((name) => name !== undefined)
.filter((name) => name !== undefined),
);
}

Expand All @@ -173,7 +173,7 @@ async function existingDatabaseNames(client: Cloudflare, accountId: string) {
function databaseFileTemplate(
databaseName: string,
imports: string | string[],
databaseExpr: string
databaseExpr: string,
) {
return dedent`
import { env } from "cloudflare:workers";
Expand Down
14 changes: 9 additions & 5 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,18 @@
"@cloudflare/actors": "0.0.1-beta.1"
},
"peerDependencies": {
"react": ">=19",
"react-dom": ">=19"
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@cloudflare/actors": "0.0.1-beta.1",
"@cloudflare/workers-types": "^4.20250413.0",
"@types/node": "^22.13.0",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-rsc": "^0.5.2",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"typescript": "^5.7.2"
},
"files": [
Expand All @@ -58,6 +61,7 @@
"LICENSE"
],
"dependencies": {
"hono": "^4.6.20"
"hono": "^4.6.20",
"rsc-html-stream": "^0.0.7"
}
}
Loading