From 6dbdd5b24abefeadb18e9069a06fd9c63f577911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 16 Sep 2025 04:21:28 +0200 Subject: [PATCH] RPC work --- .vscode/settings.json | 3 ++ bun.lock | 26 +++++++++++++++ package.json | 2 ++ packages/common/.gitignore | 34 ++++++++++++++++++++ packages/common/package.json | 14 ++++++++ packages/common/src/config/CommonConfig.ts | 4 +++ packages/common/src/config/index.ts | 1 + packages/common/src/webrpc/WebRpc.ts | 4 +++ packages/common/src/webrpc/WebRpcTest.ts | 11 +++++++ packages/common/src/webrpc/index.ts | 2 ++ packages/common/tsconfig.json | 32 ++++++++++++++++++ packages/server/package.json | 1 + packages/server/src/http.ts | 3 +- packages/server/src/webrpc/WebRpcLive.ts | 8 +++++ packages/server/src/webrpc/WebRpcTestLive.ts | 9 ++++++ packages/server/src/webrpc/index.ts | 2 ++ packages/server/tsconfig.json | 6 +++- packages/webapp/package.json | 5 +++ packages/webapp/tsconfig.app.json | 7 +++- 19 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 packages/common/.gitignore create mode 100644 packages/common/package.json create mode 100644 packages/common/src/config/CommonConfig.ts create mode 100644 packages/common/src/config/index.ts create mode 100644 packages/common/src/webrpc/WebRpc.ts create mode 100644 packages/common/src/webrpc/WebRpcTest.ts create mode 100644 packages/common/src/webrpc/index.ts create mode 100644 packages/common/tsconfig.json create mode 100644 packages/server/src/webrpc/WebRpcLive.ts create mode 100644 packages/server/src/webrpc/WebRpcTestLive.ts create mode 100644 packages/server/src/webrpc/index.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..72446f4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/bun.lock b/bun.lock index b6ff218..d387f03 100644 --- a/bun.lock +++ b/bun.lock @@ -4,10 +4,19 @@ "": { "name": "website", "devDependencies": { + "@effect/language-service": "^0.40.0", "@types/bun": "latest", + "npm-sort": "^0.0.4", "typescript": "^5.9.2", }, }, + "packages/common": { + "name": "@website/common", + "dependencies": { + "@effect/rpc": "^0.69.2", + "effect": "^3.17.13", + }, + }, "packages/server": { "name": "@website/server", "dependencies": { @@ -19,6 +28,11 @@ "packages/webapp": { "name": "@website/webapp", "dependencies": { + "@effect/platform": "^0.90.9", + "@effect/platform-browser": "^0.70.0", + "@effect/rpc": "^0.69.2", + "effect": "^3.17.13", + "effect-fc": "^0.1.3", "react": "^19.1.1", "react-dom": "^19.1.1", }, @@ -79,8 +93,12 @@ "@effect/experimental": ["@effect/experimental@0.54.6", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.90.2", "effect": "^3.17.7", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-UqHMvCQmrZT6kUVoUC0lqyno4Yad+j9hBGCdUjW84zkLwAq08tPqySiZUKRwY+Ae5B2Ab8rISYJH7nQvct9DMQ=="], + "@effect/language-service": ["@effect/language-service@0.40.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-VHikOhYXm+ECy+mLSszHgCfP9YyKQyB9GLFGBKY2nbnru9xwgCnar8pBLA0AkSUjAgn3hc/mdcFdb/XL9uywLQ=="], + "@effect/platform": ["@effect/platform@0.90.8", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.17.13" } }, "sha512-lQejPI2VbUAwPIU6oG12sAhqMar8+KkBjxgBVqQTERzHz4vnG9zaiDDytJM+IGWE40MKbCG3pc2wK6nw2Ugk8A=="], + "@effect/platform-browser": ["@effect/platform-browser@0.70.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.90.0", "effect": "^3.17.0" } }, "sha512-dq2ukUralavQIipSsQVuIOLLxBlFWL5Mkg1Fnr8esYPuPv0BXAI39nwNNi75X2tPAgak8OCSD0qh9qhmNj2gPA=="], + "@effect/platform-bun": ["@effect/platform-bun@0.79.0", "", { "dependencies": { "@effect/platform-node-shared": "^0.49.0", "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/cluster": "^0.48.0", "@effect/platform": "^0.90.2", "@effect/rpc": "^0.69.0", "@effect/sql": "^0.44.1", "effect": "^3.17.7" } }, "sha512-oWUUV7bgPmrCCdmIeE1osfpIOnwNFkBhqSxcI26/SX36nODGyg401xl9Fk51nDT9vBI+JxpZ7eoqY0wxKaThvA=="], "@effect/platform-node-shared": ["@effect/platform-node-shared@0.49.1", "", { "dependencies": { "@parcel/watcher": "^2.5.1", "multipasta": "^0.2.7", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.48.4", "@effect/platform": "^0.90.8", "@effect/rpc": "^0.69.2", "@effect/sql": "^0.44.2", "effect": "^3.17.13" } }, "sha512-equU2iDott0MgXEADzmBQySBeYysZFyxVqxo58ped9U/6f519SHlTnu5mHpGeQTE/Bz0DOqD8/I+om5DvFxjIw=="], @@ -313,6 +331,8 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@5.0.2", "", { "dependencies": { "@babel/core": "^7.28.3", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.34", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw=="], + "@website/common": ["@website/common@workspace:packages/common"], + "@website/server": ["@website/server@workspace:packages/server"], "@website/webapp": ["@website/webapp@workspace:packages/webapp"], @@ -363,6 +383,8 @@ "effect": ["effect@3.17.13", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-JMz5oBxs/6mu4FP9Csjub4jYMUwMLrp+IzUmSDVIzn2NoeoyOXMl7x1lghfr3dLKWffWrdnv/d8nFFdgrHXPqw=="], + "effect-fc": ["effect-fc@0.1.3", "", { "peerDependencies": { "@types/react": "^19.0.0", "effect": "^3.15.0", "react": "^19.0.0" } }, "sha512-0xBA4Q6gZY61/kC/D2dgoppFB1HrlI++bWKpdSLltbO3y45D5niRv49MkSZSQ98jEbB9VCM8MDd43qf+vY0biQ=="], + "electron-to-chromium": ["electron-to-chromium@1.5.215", "", {}, "sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ=="], "esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="], @@ -491,6 +513,8 @@ "node-releases": ["node-releases@2.0.20", "", {}, "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA=="], + "npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="], + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], @@ -587,6 +611,8 @@ "@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "@website/webapp/@effect/platform": ["@effect/platform@0.90.9", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.17.13" } }, "sha512-ZLyGMenOXGERsaJ7urioWwugkluWjhrcQgr0/vfgxqe/TCumL3CK93YZKSlJtohDrFSfWjaXCbXyhqz3iypFUg=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], diff --git a/package.json b/package.json index 884d21d..d6f24d0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "private": true, "workspaces": ["./packages/*"], "devDependencies": { + "@effect/language-service": "^0.40.0", "@types/bun": "latest", + "npm-sort": "^0.0.4", "typescript": "^5.9.2" } } diff --git a/packages/common/.gitignore b/packages/common/.gitignore new file mode 100644 index 0000000..a14702c --- /dev/null +++ b/packages/common/.gitignore @@ -0,0 +1,34 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/packages/common/package.json b/packages/common/package.json new file mode 100644 index 0000000..5ba4905 --- /dev/null +++ b/packages/common/package.json @@ -0,0 +1,14 @@ +{ + "name": "@website/common", + "private": true, + "type": "module", + "exports": { + "./config": "./src/config/index.ts", + "./webrpc": "./src/webrpc/index.ts", + "./*": "./src/*.ts" + }, + "dependencies": { + "@effect/rpc": "^0.69.2", + "effect": "^3.17.13" + } +} diff --git a/packages/common/src/config/CommonConfig.ts b/packages/common/src/config/CommonConfig.ts new file mode 100644 index 0000000..4e4dcbc --- /dev/null +++ b/packages/common/src/config/CommonConfig.ts @@ -0,0 +1,4 @@ +import { Config } from "effect" + + +export const webRpcHttpPath = Config.succeed("/rpc/web" as const) diff --git a/packages/common/src/config/index.ts b/packages/common/src/config/index.ts new file mode 100644 index 0000000..cbe5e5f --- /dev/null +++ b/packages/common/src/config/index.ts @@ -0,0 +1 @@ +export * as CommonConfig from "./CommonConfig" diff --git a/packages/common/src/webrpc/WebRpc.ts b/packages/common/src/webrpc/WebRpc.ts new file mode 100644 index 0000000..0dd6d6a --- /dev/null +++ b/packages/common/src/webrpc/WebRpc.ts @@ -0,0 +1,4 @@ +import * as WebRpcTest from "./WebRpcTest" + + +export class WebRpc extends WebRpcTest.WebRpcTest {} diff --git a/packages/common/src/webrpc/WebRpcTest.ts b/packages/common/src/webrpc/WebRpcTest.ts new file mode 100644 index 0000000..0154c80 --- /dev/null +++ b/packages/common/src/webrpc/WebRpcTest.ts @@ -0,0 +1,11 @@ +import { Rpc, RpcGroup } from "@effect/rpc" +import { Schema } from "effect" + + +export class PingV1 extends Rpc.make("Test.PingV1", { + success: Schema.Literal("pong"), +}) {} + +export class WebRpcTest extends RpcGroup.make( + PingV1, +) {} diff --git a/packages/common/src/webrpc/index.ts b/packages/common/src/webrpc/index.ts new file mode 100644 index 0000000..b9d6bc2 --- /dev/null +++ b/packages/common/src/webrpc/index.ts @@ -0,0 +1,2 @@ +export * as WebRpc from "./WebRpc" +export * as WebRpcTest from "./WebRpcTest" diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json new file mode 100644 index 0000000..694b114 --- /dev/null +++ b/packages/common/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false, + + "plugins": [ + { "name": "@effect/language-service" } + ] + } +} diff --git a/packages/server/package.json b/packages/server/package.json index 046646a..955c9a2 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -6,6 +6,7 @@ "dependencies": { "@effect/platform": "^0.90.8", "@effect/platform-bun": "^0.79.0", + "@website/common": "workspace:*", "effect": "^3.17.13" } } diff --git a/packages/server/src/http.ts b/packages/server/src/http.ts index 76e80f6..55153ce 100644 --- a/packages/server/src/http.ts +++ b/packages/server/src/http.ts @@ -2,8 +2,7 @@ import { FileSystem, HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, import { Duration, Effect, flow } from "effect" -const router = HttpRouter.empty.pipe( -) +const router = HttpRouter.empty export const HttpAppDevelopment = router.pipe( HttpServer.serve(flow( diff --git a/packages/server/src/webrpc/WebRpcLive.ts b/packages/server/src/webrpc/WebRpcLive.ts new file mode 100644 index 0000000..c3d2d7c --- /dev/null +++ b/packages/server/src/webrpc/WebRpcLive.ts @@ -0,0 +1,8 @@ +import { Layer } from "effect" +import * as WebRpcTestLive from "./WebRpcTestLive" +import type { WebRpc } from "@website/common/webrpc" + + +export const WebRpcLive = Layer.mergeAll( + WebRpcTestLive.WebRpcTestLive, +) satisfies ReturnType diff --git a/packages/server/src/webrpc/WebRpcTestLive.ts b/packages/server/src/webrpc/WebRpcTestLive.ts new file mode 100644 index 0000000..e872d57 --- /dev/null +++ b/packages/server/src/webrpc/WebRpcTestLive.ts @@ -0,0 +1,9 @@ +import { WebRpcTest } from "@website/common/webrpc" +import { Effect, Layer } from "effect" + + +export const PingV1Live = WebRpcTest.WebRpcTest.toLayerHandler("Test.PingV1", Effect.succeed(() => Effect.succeed("pong" as const))) + +export const WebRpcTestLive = Layer.mergeAll( + PingV1Live, +) satisfies ReturnType diff --git a/packages/server/src/webrpc/index.ts b/packages/server/src/webrpc/index.ts new file mode 100644 index 0000000..916d1c9 --- /dev/null +++ b/packages/server/src/webrpc/index.ts @@ -0,0 +1,2 @@ +export * as WebRpcLive from "./WebRpcLive" +export * as WebRpcTestLive from "./WebRpcTestLive" diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 9c62f74..694b114 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -23,6 +23,10 @@ // Some stricter flags (disabled by default) "noUnusedLocals": false, "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false + "noPropertyAccessFromIndexSignature": false, + + "plugins": [ + { "name": "@effect/language-service" } + ] } } diff --git a/packages/webapp/package.json b/packages/webapp/package.json index 100abf2..0a5dc6a 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -10,6 +10,11 @@ "preview": "vite preview" }, "dependencies": { + "@effect/platform": "^0.90.9", + "@effect/platform-browser": "^0.70.0", + "@effect/rpc": "^0.69.2", + "effect": "^3.17.13", + "effect-fc": "^0.1.3", "react": "^19.1.1", "react-dom": "^19.1.1" }, diff --git a/packages/webapp/tsconfig.app.json b/packages/webapp/tsconfig.app.json index 227a6c6..42e9e2c 100644 --- a/packages/webapp/tsconfig.app.json +++ b/packages/webapp/tsconfig.app.json @@ -21,7 +21,12 @@ "noUnusedParameters": true, "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true + "noUncheckedSideEffectImports": true, + + "plugins": [ + { "name": "@effect/language-service" } + ] }, + "include": ["src"] }