Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
464 commits
Select commit Hold shift + click to select a range
be6f446
Merge branch 'main' into sample
patroza Mar 21, 2024
821543d
Merge branch 'main' into sample
patroza Mar 26, 2024
3422922
Merge branch 'main' into sample
patroza Mar 29, 2024
cab17b8
DX: play with vite-node HMR
patroza Apr 1, 2024
b77aace
housekeeping: update packages
patroza Apr 3, 2024
8dbf50b
add hot typings
patroza Apr 3, 2024
2966775
update effect-app/vue
patroza Apr 3, 2024
11844f5
cleanup event stream
patroza Apr 3, 2024
555d5b5
housekeeping: update packages
patroza Apr 12, 2024
9f8e3fe
housekeeping: update packages
patroza Apr 13, 2024
1c5077d
housekeeping: update packages
patroza Apr 16, 2024
157652c
housekeeping: update packages
patroza Apr 16, 2024
e0a6174
cleanup
patroza Apr 16, 2024
fd7983a
downgrade eslint
patroza Apr 16, 2024
e94fded
update for effect 3.0
patroza Apr 16, 2024
e7edba1
Merge branch 'main' into sample
patroza Apr 17, 2024
803354c
remove Array as global autoimport in nuxt
patroza Apr 18, 2024
14f50a7
Merge branch 'main' into sample
patroza Apr 18, 2024
039638e
Merge branch 'main' into sample
patroza Apr 24, 2024
69f7d70
fix
patroza Apr 25, 2024
42dff1d
Merge branch 'main' into sample
patroza Apr 25, 2024
750c3d4
cleanup
patroza Apr 25, 2024
8f67d6d
Merge branch 'main' into sample
patroza Apr 26, 2024
47b208c
Merge branch 'main' into sample
patroza Apr 28, 2024
587e92d
Merge branch 'main' into sample
patroza Apr 28, 2024
a5331bc
Merge branch 'main' into sample
patroza Apr 30, 2024
4c244c0
Merge branch 'main' into sample
patroza Apr 30, 2024
f31ebb6
Merge branch 'main' into sample
patroza Apr 30, 2024
8b2cfa9
housekeeping: update packages
patroza May 2, 2024
0e7a9eb
Merge branch 'main' into sample
patroza May 2, 2024
bd2f3b0
add dt
patroza May 2, 2024
9100c6b
housekeeping: update packages
patroza May 4, 2024
f82662c
update
patroza May 4, 2024
d10437f
Merge branch 'main' into sample
patroza May 13, 2024
c83054f
Merge branch 'main' into sample
patroza May 20, 2024
877c2ab
Merge branch 'main' into sample
patroza Sep 4, 2024
2648370
Merge branch 'main' into sample
patroza Sep 4, 2024
029c894
Merge branch 'main' into sample
patroza Sep 4, 2024
141e4be
Merge branch 'main' into sample
patroza Sep 4, 2024
85daa3d
Merge branch 'main' into sample
patroza Sep 4, 2024
d94c6c5
housekeeping: update packages
patroza Sep 6, 2024
3332f84
Merge branch 'main' into sample
patroza Sep 6, 2024
337560d
Merge branch 'main' into sample
patroza Sep 10, 2024
a847836
housekeeping: update packages, opaque actions/handlers, cleanup configs
patroza Sep 14, 2024
9e6c72a
inline
patroza Sep 14, 2024
41255a0
refactor: Opaque actions/handlers.
patroza Sep 14, 2024
cf4cac2
Merge branch 'main' into sample
patroza Sep 14, 2024
91a02ed
fix config
patroza Sep 14, 2024
f6c09cb
fup configs
patroza Sep 14, 2024
6d848c0
Merge branch 'main' into sample
patroza Sep 14, 2024
d4442db
Merge branch 'main' into sample
patroza Sep 14, 2024
44d2bb3
Merge branch 'main' into sample
patroza Sep 16, 2024
8f498e4
improve: opaque requests.
patroza Sep 16, 2024
d6cf0c3
Merge branch 'main' into sample
patroza Sep 16, 2024
6298af5
Merge branch 'main' into sample
patroza Sep 16, 2024
4551d01
update
patroza Sep 16, 2024
676362c
Merge branch 'main' into sample
patroza Sep 16, 2024
a6f29b1
Merge branch 'main' into sample
patroza Sep 16, 2024
a6fbca0
Merge branch 'main' into sample
patroza Sep 16, 2024
6b874d8
Merge branch 'main' into sample
patroza Sep 17, 2024
f42f8cf
Merge branch 'main' into sample
patroza Sep 17, 2024
5d47444
Merge branch 'main' into sample
patroza Sep 19, 2024
3777e48
housekeeping: update packages
patroza Sep 21, 2024
e5855b4
update
patroza Sep 21, 2024
eb69fe8
update packages
patroza Sep 21, 2024
65c11b5
Merge branch 'main' into sample
patroza Sep 21, 2024
6698c48
refactor: improve doc
patroza Sep 22, 2024
bfe502d
Merge branch 'main' into sample
patroza Sep 22, 2024
c414887
Cleanup
patroza Sep 22, 2024
1f382e6
Cleanup
patroza Sep 22, 2024
1cacf63
cleanup
patroza Sep 22, 2024
463c068
Merge branch 'main' into sample
patroza Sep 22, 2024
914f764
Merge branch 'main' into sample
patroza Sep 22, 2024
f7150f0
housekeeping: update packages
patroza Sep 22, 2024
60d4e96
fup
patroza Sep 22, 2024
714ced5
housekeeping: update packages
patroza Sep 28, 2024
aa00410
Merge branch 'main' into sample
patroza Sep 28, 2024
20edc63
Merge branch 'main' into sample
patroza Sep 28, 2024
86e3653
Merge branch 'main' into sample
patroza Sep 28, 2024
1191c4f
refactor: extract all middleware
patroza Sep 28, 2024
b2bfa4d
cleanup
patroza Sep 28, 2024
726e8e9
Merge branch 'main' into sample
patroza Sep 28, 2024
595c502
fup
patroza Sep 28, 2024
252e078
Merge branch 'main' into sample
patroza Sep 28, 2024
22138f9
cleanup
patroza Sep 29, 2024
d47da60
fix
patroza Sep 29, 2024
f686c07
refactor: drop frontend prelude
patroza Sep 29, 2024
8b889b9
fup
patroza Sep 29, 2024
9924755
Merge branch 'main' into sample
patroza Sep 30, 2024
403e01e
Merge branch 'main' into sample
patroza Sep 30, 2024
6c1b7ab
Merge branch 'main' into sample
patroza Sep 30, 2024
4568062
fup
patroza Sep 30, 2024
6f0b7ba
bs
patroza Sep 30, 2024
455310d
bs
patroza Sep 30, 2024
1c1a334
housekeeping: update packages
patroza Oct 2, 2024
dd326c9
chore: create a Develop Task (#26)
peppineddu5 Oct 2, 2024
347f6d0
housekeeping: update packages
patroza Oct 4, 2024
606d2df
feat: WIP: Switch to using @effect/rpc as underlying transport (#27)
patroza Oct 6, 2024
71cc593
update for rpc changes
patroza Oct 6, 2024
714dbf6
disable request caching to fix operations.
patroza Oct 6, 2024
8d7c6fb
doc
patroza Oct 6, 2024
33a6c48
Merge branch 'main' into sample
patroza Oct 7, 2024
1ebada2
bs
patroza Oct 7, 2024
d68a70d
Merge branch 'main' into sample
patroza Oct 7, 2024
8c6f899
Merge branch 'main' into sample
patroza Oct 7, 2024
fd329be
Merge branch 'main' into sample
patroza Oct 7, 2024
7ae2cf6
Merge branch 'main' into sample
patroza Oct 8, 2024
3e536d7
Merge branch 'main' into sample
patroza Oct 8, 2024
bc10cde
housekeeping: update packages
patroza Oct 8, 2024
31aea1a
housekeeping: update packages
patroza Oct 8, 2024
18da0c0
Merge branch 'main' into sample
patroza Oct 8, 2024
721a1c3
fup
patroza Oct 8, 2024
799375d
Merge branch 'main' into sample
patroza Oct 8, 2024
f888e88
Merge branch 'main' into sample
patroza Oct 8, 2024
0a8ef41
Merge branch 'main' into sample
patroza Oct 8, 2024
3d419bd
Merge branch 'main' into sample
patroza Oct 9, 2024
f465efa
fup
patroza Oct 9, 2024
fd8b734
Merge branch 'main' into sample
patroza Oct 11, 2024
d207f39
housekeeping: update packages
patroza Oct 11, 2024
1e3c961
Merge branch 'main' into sample
patroza Oct 12, 2024
9080e62
Merge branch 'main' into sample
patroza Oct 12, 2024
2ee41bb
Merge branch 'main' into sample
patroza Oct 12, 2024
97b1fab
Merge branch 'main' into sample
patroza Oct 12, 2024
9b0b812
Merge branch 'main' into sample
patroza Oct 14, 2024
3fdafd1
housekeeping: update packages
patroza Oct 16, 2024
8ff5036
adopt
patroza Oct 16, 2024
2163521
autofix
patroza Oct 16, 2024
e13b5f8
autofix
patroza Oct 16, 2024
3806810
Merge branch 'main' into sample
patroza Oct 16, 2024
69bccd5
cleanup
patroza Oct 16, 2024
5e1f705
housekeeping: update packages
patroza Oct 16, 2024
d497561
Merge branch 'main' into sample
patroza Oct 16, 2024
c41d56a
Merge branch 'main' into sample
patroza Oct 17, 2024
61af6cc
m
patroza Oct 17, 2024
7b1b2a5
Merge branch 'main' into sample
patroza Oct 17, 2024
acd4cc9
Merge branch 'main' into sample
patroza Oct 17, 2024
58567e4
Merge branch 'main' into sample
patroza Oct 17, 2024
cff0a04
remove remnant
patroza Oct 17, 2024
17c5c0f
revert removal
patroza Oct 17, 2024
86498d9
restore
patroza Oct 17, 2024
3e34239
m
patroza Oct 17, 2024
c570392
Merge branch 'main' into sample
patroza Oct 18, 2024
c09d746
Merge branch 'main' into sample
patroza Oct 18, 2024
5b428b0
feat: switch to effect client helpers.
patroza Oct 18, 2024
aa7c179
m
patroza Oct 18, 2024
a7f1199
Merge branch 'main' into sample
patroza Oct 18, 2024
6b0e02f
add cb
patroza Oct 18, 2024
2588e33
housekeeping: update packages
patroza Oct 19, 2024
9540d40
updates
patroza Oct 19, 2024
5fba7b9
Merge branch 'main' into sample
patroza Oct 20, 2024
bca4f0f
fup
patroza Oct 20, 2024
f28b560
refactor: save the indents!
patroza Oct 20, 2024
964358d
refactor: save the indents!
patroza Oct 20, 2024
22237be
Merge branch 'main' into sample
patroza Oct 21, 2024
10da7f2
Merge branch 'main' into sample
patroza Oct 21, 2024
0136831
Merge branch 'main' into sample
patroza Oct 21, 2024
845bd03
Merge branch 'main' into sample
patroza Oct 21, 2024
7b017c0
fup
patroza Oct 21, 2024
f88b788
housekeeping: update packages
patroza Oct 21, 2024
bd08cb4
refactor: separate events constructor
patroza Oct 21, 2024
1c962c4
housekeeping: update packages
patroza Oct 22, 2024
53d6301
Merge branch 'main' into sample
patroza Oct 22, 2024
ce32bda
Merge branch 'main' into sample
patroza Oct 22, 2024
fde64bf
Merge branch 'main' into sample
patroza Oct 22, 2024
4b75565
Merge branch 'main' into sample
patroza Oct 22, 2024
97a5fe4
housekeeping: update packages
patroza Oct 22, 2024
f0596d6
Merge branch 'main' into sample
patroza Oct 22, 2024
fa02cae
housekeeping: update packages
patroza Oct 23, 2024
ec94c92
refactor: define repo as a standard service.
patroza Oct 23, 2024
b94a8c1
refactor: define repo as a standard service.
patroza Oct 23, 2024
764771e
Merge branch 'main' into sample
patroza Oct 23, 2024
d749b5a
Merge branch 'main' into sample
patroza Oct 23, 2024
bf3433e
housekeeping: update packages
patroza Oct 24, 2024
d3d893e
use Schema.provide
patroza Oct 24, 2024
6b7d197
Merge branch 'main' into sample
patroza Oct 24, 2024
a56c30a
housekeeping: update packages
patroza Oct 24, 2024
1ae2aab
use explicit context instead
patroza Oct 24, 2024
70d0498
housekeeping: update packages
patroza Oct 25, 2024
63071fb
Merge branch 'main' into sample
patroza Oct 25, 2024
21d7c93
r4
patroza Oct 25, 2024
99e9b61
housekeeping: update packages
patroza Oct 26, 2024
0d7ca19
fup
patroza Oct 26, 2024
e9f41ae
Merge branch 'main' into sample
patroza Oct 28, 2024
05a2c84
Merge branch 'main' into sample
patroza Oct 28, 2024
4c3ee84
Merge branch 'main' into sample
patroza Oct 30, 2024
6f12e5e
Update README.md
patroza Oct 31, 2024
924a6ef
update
patroza Oct 31, 2024
e9fdc71
Merge branch 'main' into sample
patroza Oct 31, 2024
d9dd363
Merge branch 'main' into sample
patroza Oct 31, 2024
b70b7a9
Merge branch 'main' into sample
patroza Oct 31, 2024
a625b49
Merge branch 'main' into sample
patroza Nov 1, 2024
959fd3d
cleanup
patroza Nov 1, 2024
821edc7
workaround optimizing deps
patroza Nov 2, 2024
c0072d2
housekeeping: update packages
patroza Nov 3, 2024
144e83c
chore: improve model and service codesnippets.
patroza Nov 3, 2024
846d438
housekeeping: update packages
patroza Nov 3, 2024
6187fd6
housekeeping: update packages
patroza Nov 3, 2024
7d29020
Merge branch 'main' into sample
patroza Nov 3, 2024
2976203
add return
patroza Nov 3, 2024
4b177d4
refactor: routing5
patroza Nov 3, 2024
2d3da5d
routing5
patroza Nov 3, 2024
06ac1e7
Merge branch 'main' into sample
patroza Nov 4, 2024
6cb623b
Merge branch 'main' into sample
patroza Nov 5, 2024
ff9c052
refactor: play with experimental
patroza Nov 5, 2024
e289ef0
fup
patroza Nov 5, 2024
b28ca23
Merge branch 'main' into sample
patroza Nov 5, 2024
0ed96d7
Merge commit 'a96e4527eea1012aea6017bd0e3e5e788cdd8437' into sample
patroza Nov 6, 2024
92622dc
Merge branch 'main' into sample
patroza Nov 6, 2024
946e38d
Merge branch 'main' into sample
patroza Nov 6, 2024
58eca63
refactor: routing6
patroza Nov 6, 2024
6d104f7
fup
patroza Nov 6, 2024
84bf6f8
Merge branch 'main' into sample
patroza Nov 6, 2024
2b96835
housekeeping: update packages
patroza Nov 6, 2024
f2481db
refactor: routing7
patroza Nov 6, 2024
86c7a2c
Merge branch 'main' into sample
patroza Nov 6, 2024
0e06867
Merge branch 'main' into sample
patroza Nov 6, 2024
4a32376
Merge branch 'main' into sample
patroza Nov 6, 2024
7ab9ebe
Merge branch 'main' into sample
patroza Nov 10, 2024
141cd4d
Merge branch 'main' into sample
patroza Nov 10, 2024
72db80f
Merge branch 'main' into sample
patroza Nov 11, 2024
429bc20
Merge branch 'main' into sample
patroza Nov 12, 2024
81e67b7
Merge branch 'main' into sample
patroza Nov 13, 2024
324e146
Merge branch 'main' into sample
patroza Nov 13, 2024
dfc96a1
Merge branch 'main' into sample
patroza Nov 13, 2024
df811df
improve: convenience frontend clientFor wrapper
patroza Nov 13, 2024
f080afa
fup
patroza Nov 13, 2024
2e67612
fup
patroza Nov 13, 2024
da123e9
Merge branch 'main' into sample
patroza Nov 14, 2024
e9ceb86
Merge branch 'main' into sample
patroza Nov 23, 2024
5289532
Merge branch 'main' into sample
patroza Dec 2, 2024
a91e665
update paths
patroza Dec 2, 2024
3bcba48
Merge branch 'main' into sample
patroza Dec 2, 2024
fcb9640
Merge branch 'main' into sample
patroza Dec 2, 2024
998c098
housekeeping: update packages
patroza Dec 3, 2024
d066535
fix events scope
patroza Dec 6, 2024
776a965
housekeeping: update packages
patroza Dec 6, 2024
fd226ff
chore(api): create and use the app logger (#31)
peppineddu5 Dec 11, 2024
84935df
housekeeping: update packages
patroza Dec 14, 2024
f5f92c0
Merge branch 'main' into sample
patroza Jan 5, 2025
5c3f3e3
Merge branch 'main' into sample
patroza Jan 19, 2025
ec4062e
Merge branch 'main' into sample
patroza Mar 12, 2025
d9c0de2
fix: pass cause on request fail
patroza Mar 12, 2025
9f60483
ben dprint (#37)
jfet97 Mar 12, 2025
bbae107
housekeeping: update packages. effect 3.14, rpc2 (#36)
patroza Mar 20, 2025
fd3a665
housekeeping: update packages
patroza Mar 21, 2025
2240f2a
dx: disable otel automatical incoming request instrumentation
patroza Mar 21, 2025
0d5617c
housekeeping: update packages
patroza Mar 28, 2025
f4d21c1
Merge branch 'main' into sample
patroza May 8, 2025
28772c7
cleanup
patroza May 8, 2025
46a6bab
cleanup
patroza May 8, 2025
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
2 changes: 1 addition & 1 deletion .ncurc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"@types/redis",
"eslint-plugin-codegen",
"vue-toastification",
"@sentry/*"
"@opentelemetry/*"
]
}
19 changes: 3 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# @effect-app-boilerplate
# Effect App Sample

Demo basic usage of Models, Resources, Controllers, Clients, long running tasks and some SSE.

## Setup

Expand Down Expand Up @@ -30,21 +32,6 @@ Notes

- Make sure you don't have the old Vue/Vetur vs code plugin installed, but the new ones only: "Vue.volar", "Vue.vscode-typescript-vue-plugin"

### Helpful editor hints

Add to keybinds:

```json
{
"key": "ctrl+shift+i",
"command": "editor.action.sourceAction",
"args": {
"kind": "source.addMissingImports",
"apply": "first"
}
}
```

## Framework documentation

[WIP](https://github.com/effect-ts-app/docs)
86 changes: 86 additions & 0 deletions api/src/Blog.controllers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Router } from "#lib/routing"
import { BlogPost } from "#models/Blog"
import { BlogRsc } from "#resources"
import { BogusEvent } from "#resources/Events"
import { BlogPostRepo, Events, Operations, UserRepo } from "#services"
import { Duration, Effect, Schedule } from "effect"
import { Option } from "effect-app"
import { NonEmptyString2k, NonNegativeInt } from "effect-app/Schema"
import { OperationsDefault } from "./lib/layers.js"

export default Router(BlogRsc)({
dependencies: [
BlogPostRepo.Default,
UserRepo.Default,
OperationsDefault,
Events.Default
],
*effect(match) {
const blogPostRepo = yield* BlogPostRepo
const userRepo = yield* UserRepo
const events = yield* Events
const operations = yield* Operations

return match({
FindPost: (req) =>
blogPostRepo
.find(req.id)
.pipe(Effect.andThen(Option.getOrNull)),
GetPosts: blogPostRepo
.all
.pipe(Effect.andThen((items) => ({ items }))),
CreatePost: (req) =>
userRepo
.getCurrentUser
.pipe(
Effect.andThen((author) => (new BlogPost({ ...req, author }, true))),
Effect.tap(blogPostRepo.save)
),
*PublishPost(req) {
const post = yield* blogPostRepo.get(req.id)

console.log("publishing post", post)

const targets = [
"google",
"twitter",
"facebook"
]

const done: string[] = []

const op = yield* operations.fork(
(opId) =>
operations
.update(opId, {
total: NonNegativeInt(targets.length),
completed: NonNegativeInt(done.length)
})
.pipe(
Effect.andThen(Effect.forEach(targets, (_) =>
Effect
.sync(() => done.push(_))
.pipe(
Effect.tap(() =>
operations.update(opId, {
total: NonNegativeInt(targets.length),
completed: NonNegativeInt(done.length)
})
),
Effect.delay(Duration.seconds(4))
))),
Effect.andThen(() => "the answer to the universe is 41")
),
// while operation is running...
(_opId) =>
Effect
.suspend(() => events.publish(new BogusEvent()))
.pipe(Effect.schedule(Schedule.spaced(Duration.seconds(1)))),
NonEmptyString2k("post publishing")
)

return op.id
}
})
}
})
19 changes: 9 additions & 10 deletions api/src/HelloWorld.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,21 @@ export default Router(HelloWorldRsc)({
return match({
*GetHelloWorld({ echo }) {
const context = yield* getRequestContext
return yield* userRepo
const user = yield* userRepo
.tryGetCurrentUser
.pipe(
Effect.catchTags({
"NotLoggedInError": () => Effect.succeed(null),
"NotFoundError": () => Effect.succeed(null)
}),
Effect.andThen((user) =>
new GetHelloWorld.success({
context,
echo,
currentUser: user,
randomUser: generate(S.A.make(User)).value
})
)
})
)

return new GetHelloWorld.success({
context,
echo,
currentUser: user,
randomUser: generate(S.A.make(User)).value
})
}
})
}
Expand Down
22 changes: 22 additions & 0 deletions api/src/Users.controllers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Router } from "#lib/routing"
import { UsersRsc } from "#resources"
import type { UserView } from "#resources/views"
import { Q, UserRepo } from "#services"
import { Array } from "effect"
import { Effect, Order } from "effect-app"

export default Router(UsersRsc)({
dependencies: [UserRepo.Default],
*effect(match) {
const userRepo = yield* UserRepo

return match({
IndexUsers: (req) =>
userRepo
.query(Q.where("id", "in", req.filterByIds))
.pipe(Effect.andThen((users) => ({
users: Array.sort(users, Order.mapInput(Order.string, (_: UserView) => _.displayName))
})))
})
}
})
4 changes: 3 additions & 1 deletion api/src/controllers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// codegen:start {preset: barrel, include: ./*.controllers.ts, import: default}
import accountsControllers from "./Accounts.controllers.js"
import blogControllers from "./Blog.controllers.js"
import helloWorldControllers from "./HelloWorld.controllers.js"
import operationsControllers from "./Operations.controllers.js"
import usersControllers from "./Users.controllers.js"

export { accountsControllers, helloWorldControllers, operationsControllers }
export { accountsControllers, blogControllers, helloWorldControllers, operationsControllers, usersControllers }
// codegen:end
26 changes: 26 additions & 0 deletions api/src/models/Blog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { S } from "effect-app"
import { UserFromId } from "./User.js"

export const BlogPostId = S.prefixedStringId<BlogPostId>()("post", "BlogPostId")
export interface BlogPostIdBrand {
readonly BlogPostId: unique symbol
}
export type BlogPostId = S.StringId & BlogPostIdBrand & `post-${string}`

export class BlogPost extends S.ExtendedClass<BlogPost, BlogPost.Encoded>()({
id: BlogPostId.withDefault,
title: S.NonEmptyString255,
body: S.NonEmptyString2k,
createdAt: S.Date.withDefault,
author: S.propertySignature(UserFromId).pipe(S.fromKey("authorId"))
}) {}

// codegen:start {preset: model}
//
/* eslint-disable */
export namespace BlogPost {
export interface Encoded extends S.Struct.Encoded<typeof BlogPost["fields"]> {}
}
/* eslint-enable */
//
// codegen:end
2 changes: 2 additions & 0 deletions api/src/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export { ClientEvents } from "./resources/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 AccountsRsc from "./resources/Accounts.js"
export * as BlogRsc from "./resources/Blog.js"
export * as HelloWorldRsc from "./resources/HelloWorld.js"
export * as OperationsRsc from "./resources/Operations.js"
export * as UsersRsc from "./resources/Users.js"
// codegen:end
31 changes: 31 additions & 0 deletions api/src/resources/Blog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { BlogPost, BlogPostId } from "#models/Blog"
import { InvalidStateError, NotFoundError, OptimisticConcurrencyException } from "effect-app/client"
import { OperationId } from "effect-app/Operations"
import { S } from "./lib.js"
import { BlogPostView } from "./views.js"

export class CreatePost extends S.Req<CreatePost>()("CreatePost", BlogPost.pick("title", "body"), {
allowRoles: ["user"],
success: S.Struct({ id: BlogPostId }),
failure: S.Union(NotFoundError, InvalidStateError, OptimisticConcurrencyException)
}) {}

export class FindPost extends S.Req<FindPost>()("FindPost", {
id: BlogPostId
}, { allowAnonymous: true, allowRoles: ["user"], success: S.NullOr(BlogPostView) }) {}

export class GetPosts extends S.Req<GetPosts>()("GetPosts", {}, {
allowAnonymous: true,
allowRoles: ["user"],
success: S.Struct({
items: S.Array(BlogPostView)
})
}) {}

export class PublishPost extends S.Req<PublishPost>()("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:end
17 changes: 17 additions & 0 deletions api/src/resources/Users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { UserId } from "#models/User"
import { S } from "./lib.js"
import { UserView } from "./views/UserView.js"

export class IndexUsers extends S.Req<IndexUsers>()("IndexUsers", {
filterByIds: S.NonEmptyArray(UserId)
}, {
allowAnonymous: true,
allowRoles: ["user"],
success: S.Struct({
users: S.Array(UserView)
})
}) {}

// codegen:start {preset: meta, sourcePrefix: src/resources/}
export const meta = { moduleName: "Users" } as const
// codegen:end
53 changes: 53 additions & 0 deletions api/src/resources/resolvers/UserResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { UserId } from "#models/User"
import { clientFor } from "#resources/lib"
import { Effect, Exit, Request, RequestResolver } from "effect"
import { Array, Option, pipe, S } from "effect-app"
import { ApiClientFactory, NotFoundError } from "effect-app/client"
import { type Schema } from "effect-app/Schema"
import * as UsersRsc from "../Users.js"
import { UserView } from "../views/UserView.js"

interface GetUserViewById extends Request.Request<UserView, NotFoundError<"User">> {
readonly _tag: "GetUserViewById"
readonly id: UserId
}
const GetUserViewById = Request.tagged<GetUserViewById>("GetUserViewById")

const getUserViewByIdResolver = RequestResolver
.makeBatched((requests: GetUserViewById[]) =>
clientFor(UsersRsc).pipe(
Effect.flatMap((client) =>
client
.IndexUsers
.handler({ filterByIds: pipe(requests.map((_) => _.id), Array.toNonEmptyArray, Option.getOrUndefined)! })
),
Effect.andThen(({ users }) =>
Effect.forEach(requests, (r) =>
Request.complete(
r,
Array
.findFirst(users, (_) => _.id === r.id ? Option.some(Exit.succeed(_)) : Option.none())
.pipe(Option.getOrElse(() => Exit.fail(new NotFoundError({ type: "User", id: r.id }))))
), { discard: true })
),
Effect.orDie,
Effect.catchAllCause((cause) =>
Effect.forEach(
requests,
(request) => Request.failCause(request, cause),
{ discard: true }
)
)
)
)
.pipe(RequestResolver.batchN(25), RequestResolver.contextFromServices(ApiClientFactory))

// TODO: How to globally cache - right now we had to move the RequestCache from the runtime to clientFor
export const UserViewFromId: Schema<UserView, string, ApiClientFactory> = S.transformOrFail(
UserId,
S.typeSchema(UserView),
{
decode: (id) => Effect.request(GetUserViewById({ id }), getUserViewByIdResolver).pipe(Effect.orDie),
encode: (u) => Effect.succeed(u.id)
}
)
1 change: 1 addition & 0 deletions api/src/resources/views.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// codegen:start {preset: barrel, include: ./views/*.ts}
export * from "./views/PostView.js"
export * from "./views/UserView.js"
// codegen:end
18 changes: 18 additions & 0 deletions api/src/resources/views/PostView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BlogPost } from "#models/Blog"
import { S } from "#resources/lib"
import { UserViewFromId } from "../resolvers/UserResolver.js"

export class BlogPostView extends S.ExtendedClass<BlogPostView, BlogPostView.Encoded>()({
...BlogPost.omit("author"),
author: S.propertySignature(UserViewFromId).pipe(S.fromKey("authorId"))
}) {}

// codegen:start {preset: model}
//
/* eslint-disable */
export namespace BlogPostView {
export interface Encoded extends S.Struct.Encoded<typeof BlogPostView["fields"]> {}
}
/* eslint-enable */
//
// codegen:end
2 changes: 1 addition & 1 deletion api/src/router.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as MW from "#lib/middleware"
import { Events } from "#services"
import { Router } from "@effect-app/infra/api/routing"
import { reportError } from "@effect-app/infra/errorReporter"
import { RpcSerialization } from "@effect/rpc"
import { FiberRef, flow } from "effect"
import { Console, Effect, Layer } from "effect-app"
import { HttpMiddleware, HttpRouter, HttpServer } from "effect-app/http"
import { BaseConfig, MergedConfig } from "./config.js"
import { Events } from "./services.js"

const prodOrigins: string[] = []
const demoOrigins: string[] = []
Expand Down
1 change: 1 addition & 0 deletions api/src/services/DBContext.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// codegen:start {preset: barrel, include: ./DBContext/* }
export * from "./DBContext/BlogPostRepo.js"
export * from "./DBContext/UserRepo.js"
// codegen:end
Loading