Repository navigation
feat!: upgrade to Effect v4 #1288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
de3ea21
4755f19
8adef39
bb977c0
9cc8b55
32496cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| --- | ||
| "@uploadthing/shared": major | ||
| "uploadthing": major | ||
| "@example/backend-adapters-server": patch | ||
| "next-playground": patch | ||
| "next-playground-v6": patch | ||
| "@uploadthing/tsconfig": patch | ||
| --- | ||
|
|
||
| feat!: upgrade to Effect v4 | ||
|
|
||
| - `effect` is bumped from `3.21.0` to `4.0.0-beta.93`. Since `@effect/platform` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Correct the Effect version in the release note. The changed manifests declare 🤖 Prompt for AI Agents |
||
| has been merged into the core `effect` package in v4, the separate | ||
| `@effect/platform` dependency is removed and all HTTP modules are now | ||
| imported from `effect/unstable/http`. | ||
| - Client-side code previously built on `effect/Micro` (which was removed in v4) | ||
| now uses the core `Effect` module, which is aggressively tree-shakeable in v4. | ||
| - The `uploadthing/effect-platform` adapter now returns a plain | ||
| `Effect<HttpServerResponse, unknown, HttpClient | HttpServerRequest | Scope>` | ||
| handler that can be registered on an Effect v4 `HttpRouter` (e.g. via | ||
| `HttpRouter.add("*", "/api/uploadthing", handler)`). | ||
| - Public types that referenced Effect v3 concepts follow the v4 renames, e.g. | ||
| `logLevel` options are now typed as `LogLevel.LogLevel` string literals. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 22.14 | ||
| 22.23 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,70 +1,52 @@ | ||
| import "dotenv/config"; | ||
|
|
||
| import { createServer } from "node:http"; | ||
| import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"; | ||
| import { Config, Effect, Layer, References } from "effect"; | ||
| import { | ||
| FetchHttpClient, | ||
| Headers, | ||
| HttpMiddleware, | ||
| HttpRouter, | ||
| HttpServer, | ||
| HttpServerRequest, | ||
| HttpServerResponse, | ||
| } from "@effect/platform"; | ||
| import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"; | ||
| import { Config, Effect, Layer, Logger, LogLevel } from "effect"; | ||
| } from "effect/unstable/http"; | ||
|
|
||
| import { createRouteHandler } from "uploadthing/effect-platform"; | ||
|
|
||
| import { uploadRouter } from "./router"; | ||
|
|
||
| const uploadthingRouter = createRouteHandler({ | ||
| const uploadthingHandler = createRouteHandler({ | ||
| router: uploadRouter, | ||
| }); | ||
|
|
||
| /** | ||
| * Simple CORS middleware that allows everything | ||
| * Adjust to your needs. | ||
| */ | ||
| const cors = HttpMiddleware.make((app) => | ||
| Effect.gen(function* () { | ||
| const req = yield* HttpServerRequest.HttpServerRequest; | ||
|
|
||
| const corsHeaders = { | ||
| "Access-Control-Allow-Origin": "*", | ||
| "Access-Control-Allow-Methods": "*", | ||
| "Access-Control-Allow-Headers": "*", | ||
| }; | ||
|
|
||
| if (req.method === "OPTIONS") { | ||
| return HttpServerResponse.empty({ | ||
| status: 204, | ||
| headers: Headers.fromInput(corsHeaders), | ||
| }); | ||
| } | ||
|
|
||
| const response = yield* app; | ||
|
|
||
| return response.pipe(HttpServerResponse.setHeaders(corsHeaders)); | ||
| const Routes = Layer.mergeAll( | ||
| HttpRouter.add("GET", "/api", HttpServerResponse.text("Hello from Effect")), | ||
| HttpRouter.add( | ||
| "*", | ||
| "/api/uploadthing", | ||
| uploadthingHandler.pipe(Effect.orDie), | ||
| ), | ||
| /** | ||
| * Simple CORS middleware that allows everything. | ||
| * Adjust to your needs. | ||
| */ | ||
| HttpRouter.cors({ | ||
| allowedOrigins: ["*"], | ||
| allowedMethods: ["*"], | ||
| allowedHeaders: ["*"], | ||
| }), | ||
| ); | ||
|
|
||
| const router = HttpRouter.empty.pipe( | ||
| HttpRouter.get("/api", HttpServerResponse.text("Hello from Effect")), | ||
| HttpRouter.mountApp("/api/uploadthing", uploadthingRouter), | ||
| const ServerLive = Layer.unwrap( | ||
| Effect.map(Config.port("PORT").pipe(Config.withDefault(3000)), (port) => | ||
| NodeHttpServer.layer(() => createServer(), { port }), | ||
| ), | ||
| ); | ||
|
|
||
| const app = router.pipe( | ||
| cors, | ||
| HttpServer.serve(HttpMiddleware.logger), | ||
| const AppLive = HttpRouter.serve(Routes).pipe( | ||
| HttpServer.withLogAddress, | ||
| Layer.provide(FetchHttpClient.layer), | ||
| Layer.provide(ServerLive), | ||
| Layer.provide(Layer.succeed(References.MinimumLogLevel, "Debug")), | ||
| ); | ||
|
|
||
| const Port = Config.integer("PORT").pipe(Config.withDefault(3000)); | ||
| const ServerLive = Layer.unwrapEffect( | ||
| Effect.map(Port, (port) => | ||
| NodeHttpServer.layer(() => createServer(), { port }), | ||
| ).pipe(Effect.provide(Logger.minimumLogLevel(LogLevel.Debug))), | ||
| ); | ||
|
|
||
| NodeRuntime.runMain(Layer.launch(Layer.provide(app, ServerLive))); | ||
| NodeRuntime.runMain(Layer.launch(AppLive)); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,14 @@ | |
| "compilerOptions": { | ||
| "strict": true, | ||
| "jsx": "react-native", | ||
| /** | ||
| * Effect v4 only exposes its submodules (e.g. `effect/Schema`) through | ||
| * package.json `exports` (no `typesVersions` fallback), which the legacy | ||
| * `node` resolution from expo/tsconfig.base cannot follow. Metro resolves | ||
| * package exports since Expo SDK 53, so `bundler` matches runtime behavior. | ||
|
Comment on lines
+9
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This comment uses Expo SDK 53 to justify matching Metro's behavior, but this example still pins Expo SDK 51. Its Prompt To Fix With AIThis is a comment left during a code review.
Path: examples/minimal-expo/tsconfig.json
Line: 9-10
Comment:
**Expo explanation uses wrong SDK**
This comment uses Expo SDK 53 to justify matching Metro's behavior, but this example still pins Expo SDK 51. Its `metro.config.js` also does not explicitly enable package exports. Correct the explanation and document any Metro setting this example needs. Otherwise, maintainers could mistake a passing type check for proof that Metro resolves the same imports.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. |
||
| */ | ||
| "module": "preserve", | ||
| "moduleResolution": "bundler", | ||
| "paths": { | ||
| "~/*": ["./*"] | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The release note says
effectupgrades to4.0.0-beta.93, but both published packages pin4.0.0-rc.110. Update the version here so users checking compatibility or debugging the upgrade look up the release they will actually install.Prompt To Fix With AI