diff --git a/apps/server/src/api/apis.ts b/apps/server/src/api/apis.ts index dfdb18b..44acd50 100644 --- a/apps/server/src/api/apis.ts +++ b/apps/server/src/api/apis.ts @@ -3,16 +3,17 @@ import { HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, + HttpApiMiddleware, + HttpRouter, OpenApi, } from '@effect/platform' import { Effect, Layer } from 'effect' -import Session from 'supertokens-node/recipe/session' +import SupertokensUserMetadata from 'supertokens-node/recipe/usermetadata' import type { UserContext } from 'supertokens-node/types' -import { AuthMiddleware } from './auth_middleware.js' -import { SupertokensMiddleware } from './middleware_old.js' +import { withAuthMiddleware } from './auth_middleware_custom.js' import { ResponseHello, ResponseProtected, UserMetadata } from './responses.js' -import { SessionService } from './session.js' +import { CurrentUser } from './types.js' // import { UserMetadataService } from './user_metadata.js' // ================================================ @@ -28,7 +29,7 @@ const apiDemo = HttpApiGroup.make('demo') .add( HttpApiEndpoint.get('protected', '/protected') .addSuccess(ResponseProtected) - .middleware(SupertokensMiddleware) + .middleware(withAuthMiddleware) .annotate(OpenApi.Description, 'Returns user ID for authenticated users'), ) .annotateContext( @@ -46,7 +47,8 @@ const apiUsers = HttpApiGroup.make('users') OpenApi.Description, 'Get SuperTokens metadata for authenticated user', ), - ).middlewareEndpoints(AuthMiddleware) + ) + .middleware(withAuthMiddleware) .annotateContext( OpenApi.annotations({ title: 'Users API', @@ -73,33 +75,33 @@ const ApiDemoLive = HttpApiBuilder.group(api, 'demo', handlers => Effect.succeed(new ResponseHello({ message: 'Hello from Effect!' })), ) .handle('protected', () => - // Effect.gen(function* () { - // const session = yield* SessionService - // return new ResponseProtected({ userId: session.getUserId() }) - // }), - { - const session = await Session.getSession(req, res); - Effect.succeed(new ResponseProtected({ userId: session.getUserId() })), - } + Effect.gen(function* () { + const user = yield* CurrentUser + return new ResponseProtected({ userId: user.id }) + }), ), ) const ApiUsersLive = HttpApiBuilder.group(api, 'users', handlers => handlers.handle('metadata', () => Effect.gen(function* () { - const session = yield* SessionService - const userMetadata = yield* UserMetadataService - - const userId = session.getUserId() + const user = yield* CurrentUser const userContext: UserContext = {} as UserContext - const metadata = Effect.tryPromise(() => - userMetadata.getUserMetadata({ userId, userContext }), - ) + // const metadata = Effect.tryPromise(() => + // SupertokensUserMetadata.getUserMetadata(user.id), + // ).pipe(Effect.from, Effect.flatMap(el => Effect.succeed(el))) + + // if (Effect.isSuccess(metadata)) { + // return new UserMetadata({ + // userId: user.id, + // metadata: metadata, + // }) + // } return new UserMetadata({ - userId: session.getUserId(), - metadata: metadata, + userId: user.id, + metadata: {}, }) }), ), diff --git a/apps/server/src/api/auth_middleware_custom.ts b/apps/server/src/api/auth_middleware_custom.ts index 9cc3258..65ac809 100644 --- a/apps/server/src/api/auth_middleware_custom.ts +++ b/apps/server/src/api/auth_middleware_custom.ts @@ -15,7 +15,7 @@ import { CurrentUser, Forbidden, Unauthorized } from './types.js' type NextFunction = (err?: any) => void // Inspired from https://github.com/supertokens/supertokens-node/blob/1896eabb0aac587f8b5f7a9bede8cc4b0a17a229/examples/cloudflare-workers/with-email-password-hono-be-only/middleware.ts -export const authMiddleware = HttpMiddleware.make(app => +export const withAuthMiddleware = HttpMiddleware.make(app => Effect.gen(function* () { const request = yield* ServerRequest.HttpServerRequest diff --git a/apps/server/src/env.ts b/apps/server/src/env.ts index 86520aa..701fe51 100644 --- a/apps/server/src/env.ts +++ b/apps/server/src/env.ts @@ -1,21 +1,25 @@ -import { Config, Effect, Layer } from 'effect' +import { Config, ConfigProvider, Effect, Layer } from 'effect' -// Environment configuration layer -export class Env { - static readonly Live = Layer.mergeAll( - Layer.setConfigProvider( - Effect.succeed({ - load: (path: string) => Effect.succeed(process.env[path]), - }), - ), - ) +export const ConfigProviderLayer = Layer.setConfigProvider( + ConfigProvider.fromJson(process.env), +) - static readonly load = Effect.all({ - NODE_ENV: Config.string('NODE_ENV'), - SERVER_PORT: Config.number('SERVER_PORT'), - SUPERTOKENS_API_KEY: Config.string('SUPERTOKENS_API_KEY'), - SUPERTOKENS_URL: Config.string('SUPERTOKENS_URL'), - SERVER_URL: Config.string('SERVER_URL'), - WEBSITE_URL: Config.string('WEBSITE_URL'), - }) -} +// // Environment configuration layer +// export class Env { +// static readonly Live = Layer.mergeAll( +// Layer.setConfigProvider( +// Effect.succeed({ +// load: (path: string) => Effect.succeed(process.env[path]), +// }), +// ), +// ) + +// static readonly load = Effect.all({ +// NODE_ENV: Config.string('NODE_ENV'), +// SERVER_PORT: Config.number('SERVER_PORT'), +// SUPERTOKENS_API_KEY: Config.string('SUPERTOKENS_API_KEY'), +// SUPERTOKENS_URL: Config.string('SUPERTOKENS_URL'), +// SERVER_URL: Config.string('SERVER_URL'), +// WEBSITE_URL: Config.string('WEBSITE_URL'), +// }) +// } diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 6ffd020..60aede7 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,29 +1,38 @@ import { createServer } from 'node:http' -import { HttpApiBuilder, HttpApiSwagger } from '@effect/platform' +import { + HttpApiBuilder, + HttpApiSwagger, + HttpMiddleware, + HttpServer, +} from '@effect/platform' import { NodeHttpServer, NodeRuntime } from '@effect/platform-node' -import { Effect, Layer } from 'effect' +import { Config, Layer } from 'effect' import { ApiLive } from './api/apis.js' -import { withCorsMiddleware } from './api/cors.js' -import { Env } from './env.js' -import { SuperTokens } from './supertokens.js' +import { MiddlewareCorsLive } from './api/cors.js' +import { SupertokensService } from './supertokens.js' +// import { Env } from './env.js' -// TODO: init SuperTokens +// const ServerConfig = Config.all({ +// SERVER_PORT: Config.number('SERVER_PORT'), +// }) -const program = Effect.gen(function* () { - const config = yield* Env.load +// HTTP server implementation +const ServerLive = NodeHttpServer.layer(() => createServer(), { + port: 4040, +}) - const ServerLive = NodeHttpServer.layer(() => createServer(), { - port: config.SERVER_PORT, - }) - - const HttpLive = HttpApiBuilder.serve(withCorsMiddleware).pipe( - Layer.provide(HttpApiSwagger.layer({ path: '/docs' })), +// Register API with HTTP server +const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger) + .pipe( + Layer.provide(MiddlewareCorsLive), + Layer.provide(SupertokensService.layer), Layer.provide(ApiLive), Layer.provide(ServerLive), + HttpServer.withLogAddress, // Log server address + Layer.provide(HttpApiSwagger.layer({ path: '/docs' })), ) + .pipe(Layer.provide(ServerLive)) - return yield* Layer.launch(HttpLive) -}).pipe(Effect.provide(Env.Live)) - -NodeRuntime.runMain(program) +// Run server +NodeRuntime.runMain(Layer.launch(HttpLive)) diff --git a/apps/server/src/supertokens.ts b/apps/server/src/supertokens.ts index 8303b85..fb4d6ee 100644 --- a/apps/server/src/supertokens.ts +++ b/apps/server/src/supertokens.ts @@ -118,8 +118,8 @@ const make = (config: SuperTokensConfig) => }) }) -export class SuperTokens extends Context.Tag('SuperTokens')< - SuperTokens, +export class SupertokensService extends Context.Tag('SupertokensService')< + SupertokensService, void >() { static readonly Config = Config.all({