diff --git a/api/src/Blog.controllers.ts b/api/src/Blog/Blog.controllers.ts similarity index 87% rename from api/src/Blog.controllers.ts rename to api/src/Blog/Blog.controllers.ts index 57ac255ed..365e65c87 100644 --- a/api/src/Blog.controllers.ts +++ b/api/src/Blog/Blog.controllers.ts @@ -1,14 +1,16 @@ +import { BogusEvent } from "api/Events.js" +import { OperationsDefault } from "api/lib/layers.js" import { matchFor } from "api/lib/routing.js" -import { BlogPostRepo, Events, Operations, UserRepo } from "api/services.js" +import { Events, Operations } from "api/services.js" +import { UserRepo } from "api/User/UserRepo.js" import { Duration, Effect, Schedule } from "effect" import { Option } from "effect-app" import { NonEmptyString2k, NonNegativeInt } from "effect-app/Schema" -import { BlogPost } from "models/Blog.js" -import { BlogRsc } from "resources.js" -import { BogusEvent } from "resources/Events.js" -import { OperationsDefault } from "./lib/layers.js" +import { BlogResources } from "resources.js" +import { BlogPost } from "./Blog.js" +import { BlogPostRepo } from "./BlogPostRepo.js" -export default matchFor(BlogRsc)([ +export default matchFor(BlogResources)([ BlogPostRepo.Default, UserRepo.Default, OperationsDefault, diff --git a/api/src/resources/Blog.ts b/api/src/Blog/Blog.resources.ts similarity index 79% rename from api/src/resources/Blog.ts rename to api/src/Blog/Blog.resources.ts index 01078c2d7..7316f6e79 100644 --- a/api/src/resources/Blog.ts +++ b/api/src/Blog/Blog.resources.ts @@ -1,8 +1,8 @@ +import { S } from "api/lib.js" import { InvalidStateError, NotFoundError, OptimisticConcurrencyException } from "effect-app/client" import { OperationId } from "effect-app/Operations" -import { BlogPost, BlogPostId } from "models/Blog.js" -import { S } from "./lib.js" -import { BlogPostView } from "./views.js" +import { BlogPost, BlogPostId } from "./Blog.js" +import { BlogPostView } from "./PostView.js" export class CreatePost extends S.Req()("CreatePost", BlogPost.pick("title", "body"), { allowRoles: ["user"], @@ -26,6 +26,6 @@ export class PublishPost extends S.Req()("PublishPost", { id: BlogPostId }, { allowRoles: ["user"], success: OperationId, failure: S.Union(NotFoundError) }) {} -// codegen:start {preset: meta, sourcePrefix: src/resources/} -export const meta = { moduleName: "Blog" } as const +// codegen:start {preset: meta, sourcePrefix: src/Blog/} +export const meta = { moduleName: "Blog.resources" } as const // codegen:end diff --git a/api/src/models/Blog.ts b/api/src/Blog/Blog.ts similarity index 94% rename from api/src/models/Blog.ts rename to api/src/Blog/Blog.ts index ffb31e216..61791f2a1 100644 --- a/api/src/models/Blog.ts +++ b/api/src/Blog/Blog.ts @@ -1,5 +1,5 @@ +import { UserFromId } from "api/User/User.js" import { S } from "effect-app" -import { UserFromId } from "./User.js" export const BlogPostId = S.prefixedStringId()("post", "BlogPostId") export interface BlogPostIdBrand { diff --git a/api/src/services/DBContext/BlogPostRepo.ts b/api/src/Blog/BlogPostRepo.ts similarity index 90% rename from api/src/services/DBContext/BlogPostRepo.ts rename to api/src/Blog/BlogPostRepo.ts index 33a76d384..2cc7ff5e0 100644 --- a/api/src/services/DBContext/BlogPostRepo.ts +++ b/api/src/Blog/BlogPostRepo.ts @@ -1,11 +1,11 @@ import { Model } from "@effect-app/infra" import { RepoDefault } from "api/lib/layers.js" +import { UserFromIdResolver } from "api/User/User.js" +import { UserRepo } from "api/User/UserRepo.js" import { Effect } from "effect" import { Context } from "effect-app" import { NonEmptyString255, NonEmptyString2k } from "effect-app/Schema" -import { BlogPost } from "models/Blog.js" -import { UserFromIdResolver } from "models/User.js" -import { UserRepo } from "./UserRepo.js" +import { BlogPost } from "./Blog.js" export type BlogPostSeed = "sample" | "" diff --git a/api/src/resources/views/PostView.ts b/api/src/Blog/PostView.ts similarity index 74% rename from api/src/resources/views/PostView.ts rename to api/src/Blog/PostView.ts index c313a0be5..67ee27b60 100644 --- a/api/src/resources/views/PostView.ts +++ b/api/src/Blog/PostView.ts @@ -1,6 +1,6 @@ -import { BlogPost } from "models/Blog.js" -import { S } from "resources/lib.js" -import { UserViewFromId } from "../resolvers/UserResolver.js" +import { S } from "api/lib.js" +import { UserViewFromId } from "api/User/UserResolver.js" +import { BlogPost } from "./Blog.js" export class BlogPostView extends S.ExtendedClass()({ ...BlogPost.omit("author"), diff --git a/api/src/resources/Events.ts b/api/src/Events.ts similarity index 93% rename from api/src/resources/Events.ts rename to api/src/Events.ts index 7775dc776..201a867e2 100644 --- a/api/src/resources/Events.ts +++ b/api/src/Events.ts @@ -1,5 +1,5 @@ +import { S } from "api/lib.js" import type { Schema } from "effect-app/Schema" -import { S } from "resources/lib.js" export class BogusEvent extends S.ExtendedTaggedClass()("BogusEvent", { id: S.StringId.withDefault, diff --git a/api/src/HelloWorld.controllers.ts b/api/src/HelloWorld.controllers.ts index fdefb1ad8..90a29ff49 100644 --- a/api/src/HelloWorld.controllers.ts +++ b/api/src/HelloWorld.controllers.ts @@ -1,12 +1,12 @@ import { getRequestContext } from "@effect-app/infra/api/setupRequest" import { generate } from "@effect-app/infra/test" import { matchFor } from "api/lib/routing.js" -import { UserRepo } from "api/services.js" import { Effect, S } from "effect-app" -import { User } from "models/User.js" -import { HelloWorldRsc } from "resources.js" +import { HelloWorldResources } from "resources.js" +import { User } from "./User/User.js" +import { UserRepo } from "./User/UserRepo.js" -export default matchFor(HelloWorldRsc)([ +export default matchFor(HelloWorldResources)([ UserRepo.Default ], ({ GetHelloWorld }) => Effect.gen(function*() { diff --git a/api/src/resources/HelloWorld.ts b/api/src/HelloWorld.resources.ts similarity index 68% rename from api/src/resources/HelloWorld.ts rename to api/src/HelloWorld.resources.ts index 3f5cb5211..b8acc98ab 100644 --- a/api/src/resources/HelloWorld.ts +++ b/api/src/HelloWorld.resources.ts @@ -1,6 +1,6 @@ import { RequestContext } from "@effect-app/infra/RequestContext" -import { S } from "./lib.js" -import { UserView } from "./views.js" +import { S } from "api/lib.js" +import { UserView } from "./User/UserView.js" class Response extends S.Class()({ now: S.Date.withDefault, @@ -14,6 +14,6 @@ export class GetHelloWorld extends S.Req()("GetHelloWorld", { echo: S.String }, { allowAnonymous: true, allowRoles: ["user"], success: Response }) {} -// codegen:start {preset: meta, sourcePrefix: src/resources/} -export const meta = { moduleName: "HelloWorld" } as const +// codegen:start {preset: meta, sourcePrefix: src/} +export const meta = { moduleName: "HelloWorld.resources" } as const // codegen:end diff --git a/api/src/Operations.controllers.ts b/api/src/Operations.controllers.ts index 11e54b94a..9060bcf99 100644 --- a/api/src/Operations.controllers.ts +++ b/api/src/Operations.controllers.ts @@ -1,10 +1,10 @@ import { matchFor } from "api/lib/routing.js" import { Operations } from "api/services.js" import { Effect } from "effect-app" -import { OperationsRsc } from "resources.js" +import { OperationsResources } from "resources.js" import { OperationsDefault } from "./lib/layers.js" -export default matchFor(OperationsRsc)([ +export default matchFor(OperationsResources)([ OperationsDefault ], ({ FindOperation }) => Effect.gen(function*() { diff --git a/api/src/resources/Operations.ts b/api/src/Operations.resources.ts similarity index 92% rename from api/src/resources/Operations.ts rename to api/src/Operations.resources.ts index ca301f991..37e3dc578 100644 --- a/api/src/resources/Operations.ts +++ b/api/src/Operations.resources.ts @@ -1,15 +1,14 @@ +import { clientFor, S } from "api/lib.js" import { Duration, Effect } from "effect-app" import { NotFoundError } from "effect-app/client" import { Operation, OperationFailure, OperationId } from "effect-app/Operations" -import { clientFor } from "./lib.js" -import * as S from "./lib/schema.js" export class FindOperation extends S.Req()("FindOperation", { id: OperationId }, { allowAnonymous: true, allowRoles: ["user"], success: S.NullOr(Operation) }) {} -// codegen:start {preset: meta, sourcePrefix: src/resources/} -export const meta = { moduleName: "Operations" } as const +// codegen:start {preset: meta, sourcePrefix: src/} +export const meta = { moduleName: "Operations.resources" } as const // codegen:end // Extensions diff --git a/api/src/Me.controllers.ts b/api/src/User/Me.controllers.ts similarity index 67% rename from api/src/Me.controllers.ts rename to api/src/User/Me.controllers.ts index 948e4df11..db98dbe44 100644 --- a/api/src/Me.controllers.ts +++ b/api/src/User/Me.controllers.ts @@ -1,9 +1,9 @@ import { matchFor } from "api/lib/routing.js" -import { UserRepo } from "api/services.js" import { Effect } from "effect-app" -import { MeRsc } from "resources.js" +import { MeResources } from "resources.js" +import { UserRepo } from "./UserRepo.js" -export default matchFor(MeRsc)([ +export default matchFor(MeResources)([ UserRepo.Default ], ({ GetMe }) => Effect.gen(function*() { diff --git a/api/src/User/Me.resources.ts b/api/src/User/Me.resources.ts new file mode 100644 index 000000000..cd5080e6e --- /dev/null +++ b/api/src/User/Me.resources.ts @@ -0,0 +1,9 @@ +import { S } from "api/lib.js" +import { NotFoundError } from "effect-app/client" +import { User } from "./User.js" + +export class GetMe extends S.Req()("GetMe", {}, { success: User, failure: NotFoundError }) {} + +// codegen:start {preset: meta, sourcePrefix: src/User/} +export const meta = { moduleName: "Me.resources" } as const +// codegen:end diff --git a/api/src/models/User.ts b/api/src/User/User.ts similarity index 100% rename from api/src/models/User.ts rename to api/src/User/User.ts diff --git a/api/src/services/DBContext/UserRepo.ts b/api/src/User/UserRepo.ts similarity index 95% rename from api/src/services/DBContext/UserRepo.ts rename to api/src/User/UserRepo.ts index 942584331..64ae8689f 100644 --- a/api/src/services/DBContext/UserRepo.ts +++ b/api/src/User/UserRepo.ts @@ -3,14 +3,13 @@ import { NotFoundError, NotLoggedInError } from "@effect-app/infra/errors" import { generate } from "@effect-app/infra/test" import { RepoConfig } from "api/config.js" import { RepoDefault } from "api/lib/layers.js" +import { Q, UserProfile } from "api/services.js" import { Array, Effect, Exit, Layer, Option, pipe, Request, RequestResolver, S } from "effect-app" import { fakerArb } from "effect-app/faker" import { Email } from "effect-app/Schema" import fc from "fast-check" -import type { UserId } from "models/User.js" -import { User } from "models/User.js" -import { Q } from "../lib.js" -import { UserProfile } from "../UserProfile.js" +import type { UserId } from "./User.js" +import { User } from "./User.js" export type UserSeed = "sample" | "" diff --git a/api/src/resources/resolvers/UserResolver.ts b/api/src/User/UserResolver.ts similarity index 90% rename from api/src/resources/resolvers/UserResolver.ts rename to api/src/User/UserResolver.ts index f40c38b8d..ec2469e56 100644 --- a/api/src/resources/resolvers/UserResolver.ts +++ b/api/src/User/UserResolver.ts @@ -1,12 +1,12 @@ +import { clientFor } from "api/lib.js" import { Effect, Exit, Request, RequestResolver } from "effect" import { Array, Option, pipe, S } from "effect-app" import { ApiConfig, NotFoundError } from "effect-app/client" import { HttpClient } from "effect-app/http" import { type Schema } from "effect-app/Schema" -import { UserId } from "models/User.js" -import { clientFor } from "resources/lib.js" -import * as UsersRsc from "../Users.js" -import { UserView } from "../views/UserView.js" +import { UserId } from "./User.js" +import * as UsersRsc from "./Users.resources.js" +import { UserView } from "./UserView.js" interface GetUserViewById extends Request.Request> { readonly _tag: "GetUserViewById" diff --git a/api/src/resources/views/UserView.ts b/api/src/User/UserView.ts similarity index 82% rename from api/src/resources/views/UserView.ts rename to api/src/User/UserView.ts index 3e6d16cf5..f60c21176 100644 --- a/api/src/resources/views/UserView.ts +++ b/api/src/User/UserView.ts @@ -1,5 +1,5 @@ -import { User } from "models/User.js" -import { S } from "resources/lib.js" +import { S } from "api/lib.js" +import { User } from "./User.js" export class UserView extends S.ExtendedClass()({ ...User.pick("id", "role"), diff --git a/api/src/Users.controllers.ts b/api/src/User/Users.controllers.ts similarity index 71% rename from api/src/Users.controllers.ts rename to api/src/User/Users.controllers.ts index 20d5b6860..2f5a06c62 100644 --- a/api/src/Users.controllers.ts +++ b/api/src/User/Users.controllers.ts @@ -1,11 +1,12 @@ import { matchFor } from "api/lib/routing.js" -import { Q, UserRepo } from "api/services.js" +import { Q } from "api/services.js" import { Array } from "effect" import { Effect, Order } from "effect-app" -import { UsersRsc } from "resources.js" -import type { UserView } from "resources/views.js" +import { UsersResources } from "resources.js" +import { UserRepo } from "./UserRepo.js" +import type { UserView } from "./UserView.js" -export default matchFor(UsersRsc)([ +export default matchFor(UsersResources)([ UserRepo.Default ], ({ IndexUsers }) => Effect.gen(function*() { diff --git a/api/src/resources/Users.ts b/api/src/User/Users.resources.ts similarity index 50% rename from api/src/resources/Users.ts rename to api/src/User/Users.resources.ts index 024a2e813..47305eba6 100644 --- a/api/src/resources/Users.ts +++ b/api/src/User/Users.resources.ts @@ -1,6 +1,6 @@ -import { UserId } from "models/User.js" -import { S } from "./lib.js" -import { UserView } from "./views/UserView.js" +import { S } from "api/lib.js" +import { UserId } from "./User.js" +import { UserView } from "./UserView.js" export class IndexUsers extends S.Req()("IndexUsers", { filterByIds: S.NonEmptyArray(UserId) @@ -12,6 +12,6 @@ export class IndexUsers extends S.Req()("IndexUsers", { }) }) {} -// codegen:start {preset: meta, sourcePrefix: src/resources/} -export const meta = { moduleName: "Users" } as const +// codegen:start {preset: meta, sourcePrefix: src/User/} +export const meta = { moduleName: "Users.resources" } as const // codegen:end diff --git a/api/src/controllers.ts b/api/src/controllers.ts index ca2e26754..121215332 100644 --- a/api/src/controllers.ts +++ b/api/src/controllers.ts @@ -1,9 +1,6 @@ // codegen:start {preset: barrel, include: ./*.controllers.ts, import: default} -import blogControllers from "./Blog.controllers.js" import helloWorldControllers from "./HelloWorld.controllers.js" -import meControllers from "./Me.controllers.js" import operationsControllers from "./Operations.controllers.js" -import usersControllers from "./Users.controllers.js" -export { blogControllers, helloWorldControllers, meControllers, operationsControllers, usersControllers } +export { helloWorldControllers, operationsControllers } // codegen:end diff --git a/api/src/lib.ts b/api/src/lib.ts new file mode 100644 index 000000000..5e932f4a8 --- /dev/null +++ b/api/src/lib.ts @@ -0,0 +1,10 @@ +// codegen:start {preset: barrel, include: ./lib/*.ts, exclude: ./lib/schema.ts} +export * from "./lib/basicRuntime.js" +export * from "./lib/layers.js" +export * from "./lib/middleware.js" +export * from "./lib/observability.js" +export * from "./lib/req.js" +export * from "./lib/routing.js" +// codegen:end + +export * as S from "./lib/schema.js" diff --git a/api/src/resources/lib/req.ts b/api/src/lib/req.ts similarity index 75% rename from api/src/resources/lib/req.ts rename to api/src/lib/req.ts index 854a110c4..0a0b5d29a 100644 --- a/api/src/resources/lib/req.ts +++ b/api/src/lib/req.ts @@ -1,10 +1,9 @@ import { NotLoggedInError, UnauthorizedError } from "@effect-app/infra/errors" -import { Duration, Layer, Request as EffectRequest } from "effect-app" +import type { Role } from "api/User/User.js" import type { RPCContextMap } from "effect-app/client" import { makeRpcClient } from "effect-app/client" -import type { Role } from "models/User.js" - import { makeClientFor } from "effect-app/client/clientFor" +import { RequestCacheLayers } from "./routing.js" type CTXMap = { // we put `never`, because we can't access this service here in the client, and we also don't need to @@ -26,11 +25,4 @@ export const { TaggedRequest: Req } = makeRpcClient({ requireRoles: UnauthorizedError }) -export const RequestCacheLayers = Layer.mergeAll( - Layer.setRequestCache( - EffectRequest.makeCache({ capacity: 500, timeToLive: Duration.hours(8) }) - ), - Layer.setRequestCaching(true), - Layer.setRequestBatching(true) -) export const clientFor = makeClientFor(RequestCacheLayers) diff --git a/api/src/resources/lib/schema.ts b/api/src/lib/schema.ts similarity index 100% rename from api/src/resources/lib/schema.ts rename to api/src/lib/schema.ts diff --git a/api/src/resources.ts b/api/src/resources.ts index 5426feae9..826f53253 100644 --- a/api/src/resources.ts +++ b/api/src/resources.ts @@ -1,11 +1,11 @@ import type {} from "@effect/platform/HttpClient" -export { ClientEvents } from "./resources/Events.js" +export { ClientEvents } from "./Events.js" -// codegen:start {preset: barrel, include: ./resources/*.ts, exclude: [./resources/index.ts, ./resources/lib.ts, ./resources/integrationEvents.ts, ./resources/Messages.ts, ./resources/views.ts, ./resources/Events.ts], export: { as: 'PascalCase', postfix: 'Rsc' }} -export * as BlogRsc from "./resources/Blog.js" -export * as HelloWorldRsc from "./resources/HelloWorld.js" -export * as MeRsc from "./resources/Me.js" -export * as OperationsRsc from "./resources/Operations.js" -export * as UsersRsc from "./resources/Users.js" +// codegen:start {preset: barrel, include: ./**/*.resources.ts, exclude: [./resources/index.ts, ./resources/lib.ts, ./resources/integrationEvents.ts, ./resources/Messages.ts, ./resources/views.ts, ./resources/Events.ts], export: { as: 'PascalCase' }} +export * as BlogResources from "./Blog/Blog.resources.js" +export * as HelloWorldResources from "./HelloWorld.resources.js" +export * as OperationsResources from "./Operations.resources.js" +export * as MeResources from "./User/Me.resources.js" +export * as UsersResources from "./User/Users.resources.js" // codegen:end diff --git a/api/src/resources/Me.ts b/api/src/resources/Me.ts deleted file mode 100644 index d18c32df4..000000000 --- a/api/src/resources/Me.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NotFoundError } from "effect-app/client" -import { User } from "models/User.js" -import { S } from "./lib.js" - -export class GetMe extends S.Req()("GetMe", {}, { success: User, failure: NotFoundError }) {} - -// codegen:start {preset: meta, sourcePrefix: src/resources/} -export const meta = { moduleName: "Me" } as const -// codegen:end diff --git a/api/src/resources/lib.ts b/api/src/resources/lib.ts deleted file mode 100644 index 61d4ddce7..000000000 --- a/api/src/resources/lib.ts +++ /dev/null @@ -1,5 +0,0 @@ -// codegen:start {preset: barrel, include: ./lib/*.ts, exclude: ./lib/schema.ts} -export * from "./lib/req.js" -// codegen:end - -export * as S from "./lib/schema.js" diff --git a/api/src/resources/views.ts b/api/src/resources/views.ts deleted file mode 100644 index b09859be2..000000000 --- a/api/src/resources/views.ts +++ /dev/null @@ -1,4 +0,0 @@ -// codegen:start {preset: barrel, include: ./views/*.ts} -export * from "./views/PostView.js" -export * from "./views/UserView.js" -// codegen:end diff --git a/api/src/services.ts b/api/src/services.ts index eb74b1bc2..692fe6fb7 100644 --- a/api/src/services.ts +++ b/api/src/services.ts @@ -1,5 +1,4 @@ // codegen:start {preset: barrel, include: services/*.ts } -export * from "./services/DBContext.js" export * from "./services/Events.js" export * from "./services/lib.js" export * from "./services/UserProfile.js" diff --git a/api/src/services/DBContext.ts b/api/src/services/DBContext.ts deleted file mode 100644 index f3dec88d7..000000000 --- a/api/src/services/DBContext.ts +++ /dev/null @@ -1,4 +0,0 @@ -// codegen:start {preset: barrel, include: ./DBContext/* } -export * from "./DBContext/BlogPostRepo.js" -export * from "./DBContext/UserRepo.js" -// codegen:end diff --git a/api/src/services/UserProfile.ts b/api/src/services/UserProfile.ts index bcf26a9e2..7edd9c6ed 100644 --- a/api/src/services/UserProfile.ts +++ b/api/src/services/UserProfile.ts @@ -1,7 +1,7 @@ import { parseJwt } from "@effect-app/infra/api/routing/schema/jwt" +import { Role } from "api/User/User.js" import { Context, S } from "effect-app" import { UserProfileId } from "effect-app/ids" -import { Role } from "models/User.js" export class UserProfile extends Context.assignTag()( S.Class()({