This commit is contained in:
@@ -83,9 +83,11 @@
|
|||||||
"@effect/schema": "^0.72.0",
|
"@effect/schema": "^0.72.0",
|
||||||
"@prisma/studio-server": "^0.502.0",
|
"@prisma/studio-server": "^0.502.0",
|
||||||
"@tanstack/form-core": "^0.30.0",
|
"@tanstack/form-core": "^0.30.0",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
"@types/jsonwebtoken": "^9.0.6",
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
"bun-types": "^1.1.26",
|
"bun-types": "^1.1.26",
|
||||||
"effect": "^3.7.0",
|
"effect": "^3.7.0",
|
||||||
|
"express": "^4.19.2",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"mobx": "^6.13.1",
|
"mobx": "^6.13.1",
|
||||||
"npm-check-updates": "^17.1.1",
|
"npm-check-updates": "^17.1.1",
|
||||||
|
|||||||
19
src/Layers/express/ExpressApp.ts
Normal file
19
src/Layers/express/ExpressApp.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Config, Context, Effect, Layer } from "effect"
|
||||||
|
import type { Express } from "express"
|
||||||
|
|
||||||
|
|
||||||
|
export class ExpressApp extends Context.Tag("ExpressApp")<ExpressApp, Express>() {}
|
||||||
|
|
||||||
|
|
||||||
|
const importExpress = Effect.tryPromise({
|
||||||
|
try: () => import("express"),
|
||||||
|
catch: cause => new Error("Could not import 'express'. Make sure it is installed.", { cause }),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const ExpressAppLive = (config: {
|
||||||
|
readonly trustProxy?: Config.Config<boolean>
|
||||||
|
}) => Layer.effect(ExpressApp, Effect.gen(function*() {
|
||||||
|
const app = (yield* importExpress).default()
|
||||||
|
app.set("trust proxy", yield* config.trustProxy || Config.succeed(false))
|
||||||
|
return app
|
||||||
|
}))
|
||||||
67
src/Layers/express/ExpressNodeHTTPServer.ts
Normal file
67
src/Layers/express/ExpressNodeHTTPServer.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { Config, Context, Effect, Layer, Match } from "effect"
|
||||||
|
import type { Server } from "node:http"
|
||||||
|
import type { AddressInfo } from "node:net"
|
||||||
|
import { ExpressApp } from "./ExpressApp"
|
||||||
|
|
||||||
|
|
||||||
|
export class ExpressNodeHTTPServer extends Context.Tag("ExpressNodeHTTPServer")<ExpressNodeHTTPServer, Server>() {}
|
||||||
|
|
||||||
|
|
||||||
|
const importNodeHTTP = Effect.tryPromise({
|
||||||
|
try: () => import("node:http"),
|
||||||
|
catch: cause => new Error("Could not import 'node:http'. Make sure you are using a runtime that implements Node APIs.", { cause }),
|
||||||
|
})
|
||||||
|
|
||||||
|
const serverListeningMessage = Match.type<AddressInfo | string | null>().pipe(
|
||||||
|
Match.when(Match.null, () => "HTTP server listening"),
|
||||||
|
Match.when(Match.string, v => `HTTP server listening on ${ v }`),
|
||||||
|
Match.orElse(v => `HTTP server listening on ${ v.address }:${ v.port }`),
|
||||||
|
)
|
||||||
|
|
||||||
|
export const ExpressNodeHTTPServerLive = (config: {
|
||||||
|
readonly backlog?: Config.Config<number | undefined>
|
||||||
|
readonly exclusive?: Config.Config<boolean | undefined>
|
||||||
|
readonly host?: Config.Config<string | undefined>
|
||||||
|
readonly ipv6Only?: Config.Config<boolean | undefined>
|
||||||
|
readonly path?: Config.Config<string | undefined>
|
||||||
|
readonly port?: Config.Config<number | undefined>
|
||||||
|
readonly readableAll?: Config.Config<boolean | undefined>
|
||||||
|
readonly signal?: AbortSignal
|
||||||
|
readonly writableAll?: Config.Config<boolean | undefined>
|
||||||
|
}) => Layer.effect(ExpressNodeHTTPServer, Effect.acquireRelease(
|
||||||
|
Effect.gen(function*() {
|
||||||
|
const app = yield* ExpressApp
|
||||||
|
const http = yield* importNodeHTTP
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
backlog: yield* config.backlog || Config.succeed(undefined),
|
||||||
|
exclusive: yield* config.exclusive || Config.succeed(undefined),
|
||||||
|
host: yield* config.host || Config.succeed(undefined),
|
||||||
|
ipv6Only: yield* config.ipv6Only || Config.succeed(undefined),
|
||||||
|
path: yield* config.path || Config.succeed(undefined),
|
||||||
|
port: yield* config.port || Config.succeed(undefined),
|
||||||
|
readableAll: yield* config.readableAll || Config.succeed(undefined),
|
||||||
|
signal: config.signal,
|
||||||
|
writableAll: yield* config.writableAll || Config.succeed(undefined),
|
||||||
|
} as const
|
||||||
|
|
||||||
|
return yield* Effect.async<Server>(resume => {
|
||||||
|
const server = http.createServer(app).listen(options,
|
||||||
|
() => resume(
|
||||||
|
Effect.succeed(server).pipe(
|
||||||
|
Effect.tap(Effect.logInfo(
|
||||||
|
serverListeningMessage(server.address())
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
server => Effect.gen(function*() {
|
||||||
|
yield* Effect.logInfo("HTTP server is stopping. Waiting for existing connections to end...")
|
||||||
|
yield* Effect.async(resume => {
|
||||||
|
server.close(() => resume(Effect.logInfo("HTTP server closed")))
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
))
|
||||||
2
src/Layers/express/index.ts
Normal file
2
src/Layers/express/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./ExpressApp"
|
||||||
|
export * from "./ExpressNodeHTTPServer"
|
||||||
Reference in New Issue
Block a user