@effect-app/infra 3.10.0 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/_check.sh +3 -0
  3. package/dist/CUPS.d.ts +22 -12
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +28 -29
  6. package/dist/Emailer/Sendgrid.js +13 -12
  7. package/dist/Emailer/service.d.ts +3 -13
  8. package/dist/Emailer/service.d.ts.map +1 -1
  9. package/dist/Emailer/service.js +3 -3
  10. package/dist/MainFiberSet.d.ts +18 -41
  11. package/dist/MainFiberSet.d.ts.map +1 -1
  12. package/dist/MainFiberSet.js +10 -10
  13. package/dist/Model/Repository/ext.d.ts.map +1 -1
  14. package/dist/Model/Repository/ext.js +13 -10
  15. package/dist/Model/Repository/internal/internal.d.ts +5 -5
  16. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  17. package/dist/Model/Repository/internal/internal.js +52 -42
  18. package/dist/Model/Repository/legacy.d.ts +9 -9
  19. package/dist/Model/Repository/legacy.d.ts.map +1 -1
  20. package/dist/Model/Repository/makeRepo.d.ts +4 -4
  21. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  22. package/dist/Model/Repository/makeRepo.js +1 -1
  23. package/dist/Model/Repository/service.d.ts +11 -11
  24. package/dist/Model/Repository/service.d.ts.map +1 -1
  25. package/dist/Model/Repository/validation.d.ts +17 -47
  26. package/dist/Model/Repository/validation.d.ts.map +1 -1
  27. package/dist/Model/Repository/validation.js +2 -2
  28. package/dist/Model/query/dsl.d.ts +22 -22
  29. package/dist/Model/query/dsl.d.ts.map +1 -1
  30. package/dist/Model/query/dsl.js +1 -1
  31. package/dist/Model/query/new-kid-interpreter.d.ts +1 -1
  32. package/dist/Model/query/new-kid-interpreter.js +7 -7
  33. package/dist/Operations.d.ts +22 -63
  34. package/dist/Operations.d.ts.map +1 -1
  35. package/dist/Operations.js +14 -14
  36. package/dist/OperationsRepo.d.ts +23 -7
  37. package/dist/OperationsRepo.d.ts.map +1 -1
  38. package/dist/OperationsRepo.js +4 -5
  39. package/dist/QueueMaker/SQLQueue.d.ts +6 -8
  40. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  41. package/dist/QueueMaker/SQLQueue.js +20 -24
  42. package/dist/QueueMaker/errors.js +1 -1
  43. package/dist/QueueMaker/memQueue.d.ts +2 -5
  44. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  45. package/dist/QueueMaker/memQueue.js +22 -26
  46. package/dist/QueueMaker/sbqueue.d.ts +2 -5
  47. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  48. package/dist/QueueMaker/sbqueue.js +24 -28
  49. package/dist/RequestContext.d.ts +28 -41
  50. package/dist/RequestContext.d.ts.map +1 -1
  51. package/dist/RequestContext.js +4 -4
  52. package/dist/RequestFiberSet.d.ts +23 -50
  53. package/dist/RequestFiberSet.d.ts.map +1 -1
  54. package/dist/RequestFiberSet.js +14 -14
  55. package/dist/Store/ContextMapContainer.d.ts +4 -4
  56. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  57. package/dist/Store/ContextMapContainer.js +5 -5
  58. package/dist/Store/Cosmos.d.ts.map +1 -1
  59. package/dist/Store/Cosmos.js +21 -28
  60. package/dist/Store/Disk.d.ts.map +1 -1
  61. package/dist/Store/Disk.js +12 -16
  62. package/dist/Store/Memory.d.ts +2 -2
  63. package/dist/Store/Memory.d.ts.map +1 -1
  64. package/dist/Store/Memory.js +25 -33
  65. package/dist/Store/index.js +2 -2
  66. package/dist/Store/service.d.ts +9 -34
  67. package/dist/Store/service.d.ts.map +1 -1
  68. package/dist/Store/service.js +4 -4
  69. package/dist/Store/utils.d.ts.map +1 -1
  70. package/dist/Store/utils.js +10 -2
  71. package/dist/adapters/SQL/Model.d.ts +106 -162
  72. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  73. package/dist/adapters/SQL/Model.js +92 -130
  74. package/dist/adapters/ServiceBus.d.ts +13 -44
  75. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  76. package/dist/adapters/ServiceBus.js +13 -15
  77. package/dist/adapters/cosmos-client.d.ts +7 -3
  78. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  79. package/dist/adapters/cosmos-client.js +5 -4
  80. package/dist/adapters/logger.d.ts +1 -1
  81. package/dist/adapters/logger.d.ts.map +1 -1
  82. package/dist/adapters/memQueue.d.ts +8 -21
  83. package/dist/adapters/memQueue.d.ts.map +1 -1
  84. package/dist/adapters/memQueue.js +4 -4
  85. package/dist/adapters/mongo-client.d.ts +6 -6
  86. package/dist/adapters/mongo-client.d.ts.map +1 -1
  87. package/dist/adapters/mongo-client.js +5 -4
  88. package/dist/adapters/redis-client.d.ts +14 -4
  89. package/dist/adapters/redis-client.d.ts.map +1 -1
  90. package/dist/adapters/redis-client.js +19 -18
  91. package/dist/api/ContextProvider.d.ts +10 -15
  92. package/dist/api/ContextProvider.d.ts.map +1 -1
  93. package/dist/api/ContextProvider.js +8 -8
  94. package/dist/api/codec.d.ts +1 -1
  95. package/dist/api/codec.d.ts.map +1 -1
  96. package/dist/api/codec.js +1 -1
  97. package/dist/api/internal/RequestContextMiddleware.d.ts +1 -1
  98. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  99. package/dist/api/internal/auth.d.ts +3 -3
  100. package/dist/api/internal/auth.d.ts.map +1 -1
  101. package/dist/api/internal/auth.js +8 -8
  102. package/dist/api/internal/events.d.ts +2 -2
  103. package/dist/api/internal/events.d.ts.map +1 -1
  104. package/dist/api/internal/events.js +9 -9
  105. package/dist/api/internal/health.d.ts +1 -1
  106. package/dist/api/internal/health.d.ts.map +1 -1
  107. package/dist/api/internal/health.js +2 -2
  108. package/dist/api/layerUtils.d.ts +14 -14
  109. package/dist/api/layerUtils.d.ts.map +1 -1
  110. package/dist/api/layerUtils.js +5 -5
  111. package/dist/api/middlewares.d.ts +0 -75
  112. package/dist/api/middlewares.d.ts.map +1 -1
  113. package/dist/api/middlewares.js +6 -51
  114. package/dist/api/reportError.js +4 -4
  115. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
  116. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  117. package/dist/api/routing/middleware/middleware.d.ts +6 -7
  118. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  119. package/dist/api/routing/middleware/middleware.js +9 -13
  120. package/dist/api/routing/schema/jwt.d.ts +1 -1
  121. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  122. package/dist/api/routing/schema/jwt.js +5 -4
  123. package/dist/api/routing/utils.d.ts +2 -2
  124. package/dist/api/routing/utils.d.ts.map +1 -1
  125. package/dist/api/routing/utils.js +10 -8
  126. package/dist/api/routing.d.ts +39 -37
  127. package/dist/api/routing.d.ts.map +1 -1
  128. package/dist/api/routing.js +17 -21
  129. package/dist/api/setupRequest.d.ts +4 -6
  130. package/dist/api/setupRequest.d.ts.map +1 -1
  131. package/dist/api/setupRequest.js +10 -9
  132. package/dist/arbs.d.ts +3 -3
  133. package/dist/arbs.d.ts.map +1 -1
  134. package/dist/arbs.js +2 -2
  135. package/dist/errorReporter.d.ts +1 -1
  136. package/dist/errorReporter.d.ts.map +1 -1
  137. package/dist/errorReporter.js +12 -12
  138. package/dist/fileUtil.d.ts +6 -6
  139. package/dist/fileUtil.d.ts.map +1 -1
  140. package/dist/logger/jsonLogger.d.ts.map +1 -1
  141. package/dist/logger/jsonLogger.js +19 -18
  142. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  143. package/dist/logger/logFmtLogger.js +11 -13
  144. package/dist/logger/shared.d.ts +2 -2
  145. package/dist/logger/shared.d.ts.map +1 -1
  146. package/dist/logger/shared.js +7 -9
  147. package/dist/logger.d.ts +1 -1
  148. package/dist/logger.d.ts.map +1 -1
  149. package/dist/rateLimit.d.ts +2 -2
  150. package/dist/rateLimit.d.ts.map +1 -1
  151. package/dist/rateLimit.js +5 -5
  152. package/dist/test.d.ts +2 -2
  153. package/dist/test.d.ts.map +1 -1
  154. package/dist/test.js +6 -24
  155. package/package.json +19 -22
  156. package/src/CUPS.ts +15 -14
  157. package/src/Emailer/Sendgrid.ts +15 -13
  158. package/src/Emailer/service.ts +3 -3
  159. package/src/MainFiberSet.ts +16 -12
  160. package/src/Model/Repository/ext.ts +18 -16
  161. package/src/Model/Repository/internal/internal.ts +80 -69
  162. package/src/Model/Repository/legacy.ts +9 -9
  163. package/src/Model/Repository/makeRepo.ts +5 -5
  164. package/src/Model/Repository/service.ts +12 -12
  165. package/src/Model/Repository/validation.ts +1 -1
  166. package/src/Model/query/dsl.ts +13 -13
  167. package/src/Model/query/new-kid-interpreter.ts +8 -8
  168. package/src/Operations.ts +17 -14
  169. package/src/OperationsRepo.ts +3 -4
  170. package/src/QueueMaker/SQLQueue.ts +86 -89
  171. package/src/QueueMaker/errors.ts +1 -1
  172. package/src/QueueMaker/memQueue.ts +90 -91
  173. package/src/QueueMaker/sbqueue.ts +90 -92
  174. package/src/RequestContext.ts +3 -3
  175. package/src/RequestFiberSet.ts +17 -15
  176. package/src/Store/ContextMapContainer.ts +4 -4
  177. package/src/Store/Cosmos.ts +20 -27
  178. package/src/Store/Disk.ts +13 -17
  179. package/src/Store/Memory.ts +28 -34
  180. package/src/Store/index.ts +1 -1
  181. package/src/Store/service.ts +4 -4
  182. package/src/Store/utils.ts +9 -5
  183. package/src/adapters/SQL/Model.ts +255 -268
  184. package/src/adapters/ServiceBus.ts +17 -20
  185. package/src/adapters/cosmos-client.ts +5 -5
  186. package/src/adapters/memQueue.ts +3 -3
  187. package/src/adapters/mongo-client.ts +5 -5
  188. package/src/adapters/redis-client.ts +25 -19
  189. package/src/api/ContextProvider.ts +24 -34
  190. package/src/api/codec.ts +1 -1
  191. package/src/api/internal/auth.ts +11 -13
  192. package/src/api/internal/events.ts +11 -11
  193. package/src/api/internal/health.ts +1 -1
  194. package/src/api/layerUtils.ts +20 -20
  195. package/src/api/middlewares.ts +0 -97
  196. package/src/api/reportError.ts +3 -3
  197. package/src/api/routing/middleware/RouterMiddleware.ts +5 -6
  198. package/src/api/routing/middleware/middleware.ts +13 -25
  199. package/src/api/routing/schema/jwt.ts +9 -7
  200. package/src/api/routing/utils.ts +12 -10
  201. package/src/api/routing.ts +77 -79
  202. package/src/api/setupRequest.ts +9 -8
  203. package/src/arbs.ts +3 -3
  204. package/src/errorReporter.ts +12 -12
  205. package/src/logger/jsonLogger.ts +18 -17
  206. package/src/logger/logFmtLogger.ts +10 -12
  207. package/src/logger/shared.ts +6 -8
  208. package/src/rateLimit.ts +7 -7
  209. package/src/test.ts +7 -29
  210. package/test/contextProvider.test.ts +77 -70
  211. package/test/controller.test.ts +51 -39
  212. package/test/dist/contextProvider.test.d.ts.map +1 -1
  213. package/test/dist/controller.test.d.ts.map +1 -1
  214. package/test/dist/fixtures.d.ts +33 -81
  215. package/test/dist/fixtures.d.ts.map +1 -1
  216. package/test/dist/fixtures.js +9 -8
  217. package/test/dist/query.test.d.ts.map +1 -1
  218. package/test/dist/rawQuery.test.d.ts.map +1 -1
  219. package/test/dist/requires.test.d.ts.map +1 -1
  220. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  221. package/test/fixtures.ts +9 -7
  222. package/test/query.test.ts +49 -41
  223. package/test/rawQuery.test.ts +44 -40
  224. package/test/requires.test.ts +40 -31
  225. package/test/rpc-multi-middleware.test.ts +13 -14
  226. package/test/validateSample.test.ts +2 -2
  227. package/tsconfig.json +1 -27
  228. package/dist/api/internal/middlewares.d.ts +0 -15
  229. package/dist/api/internal/middlewares.d.ts.map +0 -1
  230. package/dist/api/internal/middlewares.js +0 -168
  231. package/src/api/internal/middlewares.ts +0 -279
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */
2
2
  import { type OperationOptionsBase, type ProcessErrorArgs, ServiceBusClient, type ServiceBusMessage, type ServiceBusMessageBatch, type ServiceBusReceivedMessage, type ServiceBusReceiver } from "@azure/service-bus"
3
- import { Cause, Context, Effect, Exit, FiberSet, Layer, type Scope } from "effect-app"
3
+ import { Cause, Effect, Exit, FiberSet, Layer, type Scope, ServiceMap } from "effect-app"
4
4
  import { InfraLogger } from "../logger.js"
5
5
 
6
6
  const withSpanAndLog = (name: string) => <A, E, R>(self: Effect.Effect<A, E, R>) =>
7
7
  Effect.logInfo(name).pipe(
8
- Effect.zipRight(self),
8
+ Effect.andThen(self),
9
9
  Effect.tap(Effect.logInfo(name + " done")),
10
10
  Effect.withLogSpan(name),
11
11
  Effect.withSpan(name)
@@ -18,9 +18,10 @@ function makeClient(url: string) {
18
18
  )
19
19
  }
20
20
 
21
- export class ServiceBusClientTag extends Context.Tag("@services/Client")<ServiceBusClientTag, ServiceBusClient>() {
22
- static readonly make = makeClient
23
- static readonly layer = (url: string) => Layer.scoped(this, makeClient(url))
21
+ export class ServiceBusClientTag
22
+ extends ServiceMap.Opaque<ServiceBusClientTag, ServiceBusClient>()("@services/Client", { make: makeClient })
23
+ {
24
+ static readonly layer = (url: string) => this.toLayer(this.make(url))
24
25
  }
25
26
 
26
27
  function makeSender_(queueName: string) {
@@ -49,27 +50,23 @@ const makeSender = (name: string) =>
49
50
  return { name, sendMessages }
50
51
  })
51
52
 
52
- export class Sender extends Context.TagId("Sender")<Sender, {
53
+ export class Sender extends ServiceMap.Opaque<Sender, {
53
54
  name: string
54
55
  sendMessages: (
55
56
  messages: ServiceBusMessage | ServiceBusMessage[] | ServiceBusMessageBatch,
56
57
  options?: Omit<OperationOptionsBase, "abortSignal">
57
58
  ) => Effect.Effect<void, never, never>
58
- }>() {
59
- static readonly make = makeSender
60
- static readonly layer = (name: string) => this.toLayerScoped(makeSender(name))
59
+ }>()("Sender", { make: makeSender }) {
60
+ static readonly layer = (name: string) => this.toLayer(this.make(name))
61
61
  }
62
62
 
63
63
  export const SenderTag = <Id>() => <Key extends string>(queueName: Key) => {
64
- const tag = Context.Tag(`ServiceBus.Sender.${queueName}`)<
65
- Id,
66
- Sender
67
- >()
64
+ const tag = ServiceMap.Service<Id, Sender>(`ServiceBus.Sender.${queueName}`)
68
65
 
69
66
  return Object.assign(tag, {
70
- layer: Layer.scoped(
67
+ layer: Layer.effect(
71
68
  tag,
72
- makeSender(queueName).pipe(Effect.map((_) => Sender.of(_)))
69
+ Sender.make(queueName).pipe(Effect.map((_) => Sender.of(_)))
73
70
  )
74
71
  })
75
72
  }
@@ -133,7 +130,7 @@ const makeReceiver = (name: string) =>
133
130
  resolve(exit.value)
134
131
  } else {
135
132
  // disable @typescript-eslint/prefer-promise-reject-errors
136
- reject(Cause.pretty(exit.cause, { renderErrorCause: true }))
133
+ reject(Cause.pretty(exit.cause))
137
134
  }
138
135
  })
139
136
  )
@@ -148,7 +145,7 @@ const makeReceiver = (name: string) =>
148
145
  hndlr
149
146
  .processError(err)
150
147
  .pipe(
151
- Effect.catchAllCause((cause) => Effect.logError(`ServiceBus Error ${sessionId}`, cause))
148
+ Effect.catchCause((cause) => Effect.logError(`ServiceBus Error ${sessionId}`, cause))
152
149
  )
153
150
  ),
154
151
  processMessage: (msg) => runEffect(hndlr.processMessage(msg))
@@ -166,7 +163,7 @@ const makeReceiver = (name: string) =>
166
163
  }
167
164
  })
168
165
 
169
- export class Receiver extends Context.TagId("Receiver")<Receiver, {
166
+ export class Receiver extends ServiceMap.Opaque<Receiver, {
170
167
  name: string
171
168
  make: (waitTillEmpty: Effect.Effect<void>) => Effect.Effect<ServiceBusReceiver, never, Scope.Scope>
172
169
  makeSession: (
@@ -177,13 +174,13 @@ export class Receiver extends Context.TagId("Receiver")<Receiver, {
177
174
  hndlr: MessageHandlers<RMsg, RErr>,
178
175
  sessionId?: string
179
176
  ): Effect.Effect<void, never, Scope.Scope | RMsg | RErr>
180
- }>() {
177
+ }>()("Receiver") {
181
178
  static readonly make = makeReceiver
182
179
  static readonly layer = (name: string) => this.toLayer(makeReceiver(name))
183
180
  }
184
181
 
185
182
  export const ReceiverTag = <Id>() => <Key extends string>(queueName: Key) => {
186
- const tag = Context.Tag(`ServiceBus.Receiver.${queueName}`)<Id, Receiver>()
183
+ const tag = ServiceMap.Service<Id, Receiver>(`ServiceBus.Receiver.${queueName}`)
187
184
 
188
185
  return Object.assign(tag, {
189
186
  layer: Layer.effect(
@@ -1,16 +1,16 @@
1
1
  import { CosmosClient as ComosClient_ } from "@azure/cosmos"
2
- import { Context, Effect, Layer } from "effect-app"
2
+ import { Effect, Layer, ServiceMap } from "effect-app"
3
3
 
4
4
  const withClient = (url: string) => Effect.sync(() => new ComosClient_(url))
5
5
 
6
6
  export const makeCosmosClient = (url: string, dbName: string) =>
7
7
  Effect.map(withClient(url), (x) => ({ db: x.database(dbName) }))
8
8
 
9
- export interface CosmosClient extends Effect.Effect.Success<ReturnType<typeof makeCosmosClient>> {}
9
+ export class CosmosClient extends ServiceMap.Service<CosmosClient, {
10
+ readonly db: ReturnType<InstanceType<typeof ComosClient_>["database"]>
11
+ }>()("@services/CosmosClient") {}
10
12
 
11
- export const CosmosClient = Context.GenericTag<CosmosClient>("@services/CosmosClient")
12
-
13
- export const db = Effect.map(CosmosClient, (_) => _.db)
13
+ export const db = CosmosClient.asEffect().pipe(Effect.map((_) => _.db))
14
14
 
15
15
  export const CosmosClientLayer = (cosmosUrl: string, dbName: string) =>
16
16
  Layer.effect(CosmosClient, makeCosmosClient(cosmosUrl, dbName))
@@ -1,4 +1,4 @@
1
- import { Context, Effect, type Queue } from "effect-app"
1
+ import { Effect, type Queue, ServiceMap } from "effect-app"
2
2
  import * as Q from "effect/Queue"
3
3
 
4
4
  const make = Effect
@@ -16,6 +16,6 @@ const make = Effect
16
16
  }
17
17
  })
18
18
 
19
- export class MemQueue extends Context.TagMakeId("effect-app/MemQueue", make)<MemQueue>() {
20
- static readonly Live = this.toLayer()
19
+ export class MemQueue extends ServiceMap.Opaque<MemQueue>()("effect-app/MemQueue", { make }) {
20
+ static readonly Live = this.toLayer(this.make)
21
21
  }
@@ -1,4 +1,4 @@
1
- import { Context, Effect, Layer } from "effect-app"
1
+ import { Effect, Layer, ServiceMap } from "effect-app"
2
2
  import { MongoClient as MongoClient_ } from "mongodb"
3
3
 
4
4
  // TODO: we should probably share a single client...
@@ -15,9 +15,9 @@ const withClient = (url: string) =>
15
15
 
16
16
  const makeMongoClient = (url: string, dbName?: string) => Effect.map(withClient(url), (x) => ({ db: x.db(dbName) }))
17
17
 
18
- export interface MongoClient extends Effect.Effect.Success<ReturnType<typeof makeMongoClient>> {}
19
-
20
- export const MongoClient = Context.GenericTag<MongoClient>("@services/MongoClient")
18
+ export class MongoClient extends ServiceMap.Service<MongoClient, {
19
+ readonly db: ReturnType<InstanceType<typeof MongoClient_>["db"]>
20
+ }>()("@services/MongoClient") {}
21
21
 
22
22
  export const MongoClientLive = (mongoUrl: string, dbName?: string) =>
23
- Layer.scoped(MongoClient, makeMongoClient(mongoUrl, dbName))
23
+ Layer.effect(MongoClient, makeMongoClient(mongoUrl, dbName))
@@ -1,4 +1,4 @@
1
- import { Context, Data, Effect, Layer, Option } from "effect-app"
1
+ import { Data, Effect, Layer, Option, ServiceMap } from "effect-app"
2
2
  import type { RedisClient as Client } from "redis"
3
3
  import Redlock from "redlock"
4
4
 
@@ -17,21 +17,21 @@ export const makeRedisClient = (makeClient: () => Client) =>
17
17
 
18
18
  function get(key: string) {
19
19
  return Effect
20
- .async<Option.Option<string>, ConnectionException>((res) => {
20
+ .callback<Option.Option<string>, ConnectionException>((res) => {
21
21
  client.get(key, (err, v) =>
22
22
  err
23
- ? res(new ConnectionException(err))
24
- : res(Effect.sync(() => Option.fromNullable(v))))
23
+ ? res(Effect.fail(new ConnectionException(err)))
24
+ : res(Effect.sync(() => Option.fromNullishOr(v))))
25
25
  })
26
26
  .pipe(Effect.uninterruptible)
27
27
  }
28
28
 
29
29
  function set(key: string, val: string) {
30
30
  return Effect
31
- .async<void, ConnectionException>((res) => {
31
+ .callback<void, ConnectionException>((res) => {
32
32
  client.set(key, val, (err) =>
33
33
  err
34
- ? res(new ConnectionException(err))
34
+ ? res(Effect.fail(new ConnectionException(err)))
35
35
  : res(Effect.sync(() => void 0)))
36
36
  })
37
37
  .pipe(Effect.uninterruptible)
@@ -39,10 +39,10 @@ export const makeRedisClient = (makeClient: () => Client) =>
39
39
 
40
40
  function hset(key: string, field: string, value: string) {
41
41
  return Effect
42
- .async<void, ConnectionException>((res) => {
42
+ .callback<void, ConnectionException>((res) => {
43
43
  client.hset(key, field, value, (err) =>
44
44
  err
45
- ? res(new ConnectionException(err))
45
+ ? res(Effect.fail(new ConnectionException(err)))
46
46
  : res(Effect.sync(() => void 0)))
47
47
  })
48
48
  .pipe(Effect.uninterruptible)
@@ -50,22 +50,22 @@ export const makeRedisClient = (makeClient: () => Client) =>
50
50
 
51
51
  function hget(key: string, field: string) {
52
52
  return Effect
53
- .async<Option.Option<string>, ConnectionException>((res) => {
53
+ .callback<Option.Option<string>, ConnectionException>((res) => {
54
54
  client.hget(key, field, (err, v) =>
55
55
  err
56
- ? res(new ConnectionException(err))
57
- : res(Effect.sync(() => Option.fromNullable(v))))
56
+ ? res(Effect.fail(new ConnectionException(err)))
57
+ : res(Effect.sync(() => Option.fromNullishOr(v))))
58
58
  })
59
59
  .pipe(Effect.uninterruptible)
60
60
  }
61
61
  function hmgetAll(key: string) {
62
62
  return Effect
63
- .async<Option.Option<{ [key: string]: string }>, ConnectionException>(
63
+ .callback<Option.Option<{ [key: string]: string }>, ConnectionException>(
64
64
  (res) => {
65
65
  client.hgetall(key, (err, v) =>
66
66
  err
67
- ? res(new ConnectionException(err))
68
- : res(Effect.sync(() => Option.fromNullable(v))))
67
+ ? res(Effect.fail(new ConnectionException(err)))
68
+ : res(Effect.sync(() => Option.fromNullishOr(v))))
69
69
  }
70
70
  )
71
71
  .pipe(Effect.uninterruptible)
@@ -84,18 +84,24 @@ export const makeRedisClient = (makeClient: () => Client) =>
84
84
  }),
85
85
  (cl) =>
86
86
  Effect
87
- .async<void, Error>((res) => {
87
+ .callback<void, Error>((res) => {
88
88
  cl.client.quit((err) => res(err ? Effect.fail(err) : Effect.void))
89
89
  })
90
90
  .pipe(Effect.uninterruptible, Effect.orDie)
91
91
  )
92
92
 
93
- export interface RedisClient extends Effect.Effect.Success<ReturnType<typeof makeRedisClient>> {}
94
-
95
- export const RedisClient = Context.GenericTag<RedisClient>("@services/RedisClient")
93
+ export class RedisClient extends ServiceMap.Service<RedisClient, {
94
+ readonly client: Client
95
+ readonly lock: Redlock
96
+ readonly get: (key: string) => Effect.Effect<Option.Option<string>, ConnectionException>
97
+ readonly hget: (key: string, field: string) => Effect.Effect<Option.Option<string>, ConnectionException>
98
+ readonly hset: (key: string, field: string, value: string) => Effect.Effect<void, ConnectionException>
99
+ readonly hmgetAll: (key: string) => Effect.Effect<Option.Option<{ [key: string]: string }>, ConnectionException>
100
+ readonly set: (key: string, val: string) => Effect.Effect<void, ConnectionException>
101
+ }>()("@services/RedisClient") {}
96
102
 
97
103
  export const RedisClientLayer = (storageUrl: string) =>
98
- Layer.scoped(RedisClient, makeRedisClient(makeRedis(storageUrl)))
104
+ Layer.effect(RedisClient, makeRedisClient(makeRedis(storageUrl)))
99
105
 
100
106
  function createClient(makeClient: () => Client) {
101
107
  const client = makeClient()
@@ -1,25 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Context, Effect, Layer, type NonEmptyReadonlyArray, pipe, type Scope } from "effect-app"
2
+ import { Effect, Layer, type NonEmptyReadonlyArray, pipe, type Scope, ServiceMap } from "effect-app"
3
3
 
4
- import { type HttpLayerRouter } from "effect-app/http"
4
+ import { type HttpRouter } from "effect-app/http"
5
5
  import { type EffectGenUtils } from "effect-app/utils/gen"
6
- import { type Tag } from "effect/Context"
7
- import { type YieldWrap } from "effect/Utils"
6
+ import { type Yieldable } from "effect/Effect"
8
7
  import { type ContextTagWithDefault, type GetContext, type LayerUtils, mergeContexts } from "./layerUtils.js"
9
8
 
10
- // // the context provider provides additional stuff
11
- // export type ContextProviderShape<ContextProviderA, ContextProviderR> = Effect.Effect<
12
- // Context.Context<ContextProviderA>,
13
- // never, // no errors are allowed
14
- // ContextProviderR
15
- // >
16
-
17
9
  export interface ContextProviderId {
18
10
  _tag: "ContextProvider"
19
11
  }
20
12
 
21
- // ContextTagWithDefault.Base<Effect.Effect<Context.Context<infer _1>, never, infer _R> & { _tag: infer _2 }>
22
-
23
13
  /**
24
14
  * TDeps is an array of services with Default implementation
25
15
  * each service is an effect which builds some context for each request
@@ -33,25 +23,22 @@ type TDepsArr<TDeps extends ReadonlyArray<any>> = {
33
23
  // E = never => the context provided cannot trigger errors
34
24
  // TODO: remove HttpLayerRouter.Provided - it's not even relevant outside of Http context, while ContextProviders are for anywhere. Only support Scope.Scope?
35
25
  // _R extends HttpLayerRouter.Provided => the context provided can only have what HttpLayerRouter.Provided provides as requirements
36
- (
37
- ContextTagWithDefault.Base<Effect.Effect<Context.Context<infer _1>, never, infer _R> & { _tag: infer _2 }>
38
- ) ? [_R] extends [HttpLayerRouter.Provided] ? TDeps[K]
26
+ ContextTagWithDefault.Base<Effect.Effect<ServiceMap.ServiceMap<infer _1>, never, infer _R>> // & { _tag: infer _2 }>
27
+ ? [_R] extends [HttpRouter.Provided] ? TDeps[K]
39
28
  : `HttpLayerRouter.Provided is the only requirement ${TDeps[K]["Service"][
40
29
  "_tag"
41
30
  ]}'s returned effect can have`
42
31
  : TDeps[K] extends (
43
32
  ContextTagWithDefault.Base<
44
- & (() => Generator<
33
+ (() => Generator<
45
34
  infer _YW,
46
35
  infer _1,
47
36
  infer _2
48
37
  >)
49
- & { _tag: infer _3 }
50
- >
38
+ > // & { _tag: infer _3 }
51
39
  ) // [_YW] extends [never] if no yield* is used and just some context is returned
52
40
  ? [_YW] extends [never] ? TDeps[K]
53
- : [_YW] extends [YieldWrap<Effect.Effect<infer _2, never, infer _R>>]
54
- ? [_R] extends [HttpLayerRouter.Provided] ? TDeps[K]
41
+ : [_YW] extends [Yieldable<any, infer _2, never, infer _R>] ? [_R] extends [HttpRouter.Provided] ? TDeps[K]
55
42
  : `HttpLayerRouter.Provided is the only requirement ${TDeps[K]["Service"][
56
43
  "_tag"
57
44
  ]}'s returned effect can have`
@@ -70,9 +57,10 @@ export const mergeContextProviders = <
70
57
  effect: Effect.Effect<
71
58
  Effect.Effect<
72
59
  // we need to merge all contexts into one
73
- Context.Context<GetContext<EffectGenUtils.Success<Tag.Identifier<TDeps[number]>>>>,
60
+ // v4: Service.Shape extracts the service value type (v3's Tag.Identifier)
61
+ ServiceMap.ServiceMap<GetContext<EffectGenUtils.Success<ServiceMap.Service.Shape<TDeps[number]>>>>,
74
62
  never,
75
- EffectGenUtils.Context<Tag.Identifier<TDeps[number]>>
63
+ EffectGenUtils.ServiceMap<ServiceMap.Service.Shape<TDeps[number]>>
76
64
  >,
77
65
  LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
78
66
  LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
@@ -90,26 +78,26 @@ export const mergeContextProviders = <
90
78
  handle: handle[Symbol.toStringTag] === "GeneratorFunction" ? Effect.fnUntraced(handle)() : handle
91
79
  }
92
80
  ))
93
- // services are effects which return some Context.Context<...>
81
+ // services are effects which return some ServiceMap.ServiceMap<...>
94
82
  const context = yield* mergeContexts(services as any)
95
83
  return context
96
84
  })
97
85
  }) as any
98
86
  })
99
87
 
100
- // Effect Rpc Middleware: for single tag providing, we could use Provides, for providing Context or Layer (bad boy) we could use Wrap..
88
+ // Effect Rpc Middleware: for single tag providing, we could use Provides, for providing ServiceMap or Layer (bad boy) we could use Wrap..
101
89
  export const ContextProvider = <
102
90
  ContextProviderA,
103
91
  MakeContextProviderE,
104
92
  MakeContextProviderR,
105
93
  ContextProviderR extends Scope.Scope,
106
- Dependencies extends NonEmptyReadonlyArray<Layer.Layer.Any>
94
+ Dependencies extends NonEmptyReadonlyArray<Layer.Any>
107
95
  >(
108
96
  input: {
109
97
  effect: Effect.Effect<
110
98
  | Effect.Effect<ContextProviderA, never, ContextProviderR>
111
99
  | (() => Generator<
112
- YieldWrap<Effect.Effect<any, never, ContextProviderR>>,
100
+ Yieldable<any, any, never, ContextProviderR>,
113
101
  ContextProviderA,
114
102
  any
115
103
  >),
@@ -119,7 +107,7 @@ export const ContextProvider = <
119
107
  dependencies?: Dependencies
120
108
  }
121
109
  ) => {
122
- const ctx = Context.GenericTag<
110
+ const ctx = ServiceMap.Service<
123
111
  ContextProviderId,
124
112
  Effect.Effect<ContextProviderA, never, ContextProviderR>
125
113
  >(
@@ -128,10 +116,10 @@ export const ContextProvider = <
128
116
  const e = input.effect.pipe(
129
117
  Effect.map((eg) => (eg as any)[Symbol.toStringTag] === "GeneratorFunction" ? Effect.fnUntraced(eg as any)() : eg)
130
118
  )
131
- const l = Layer.scoped(ctx, e as any)
119
+ const l = Layer.effect(ctx, e as any)
132
120
  return Object.assign(ctx, {
133
121
  Default: l.pipe(
134
- input.dependencies ? Layer.provide(input.dependencies) as any : (_) => _
122
+ input.dependencies ? Layer.provide([...input.dependencies] as [Layer.Any, ...Layer.Any[]]) as any : (_: any) => _
135
123
  ) satisfies Layer.Layer<
136
124
  ContextProviderId,
137
125
  | MakeContextProviderE
@@ -157,16 +145,18 @@ export const MergedContextProvider = <
157
145
  ContextProviderId,
158
146
  Effect.Effect<
159
147
  // we need to merge all contexts into one
160
- Context.Context<GetContext<EffectGenUtils.Success<Tag.Identifier<TDeps[number]>>>>,
148
+ // v4: Service.Shape extracts the service value type (v3's Tag.Identifier)
149
+ ServiceMap.ServiceMap<GetContext<EffectGenUtils.Success<ServiceMap.Service.Shape<TDeps[number]>>>>,
161
150
  never,
162
- EffectGenUtils.Context<Tag.Identifier<TDeps[number]>>
151
+ EffectGenUtils.ServiceMap<ServiceMap.Service.Shape<TDeps[number]>>
163
152
  >,
164
153
  LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
154
+ // v4: Identifier here is correct — it's the nominal service identity for layer provide/exclude
165
155
  | Exclude<
166
- Tag.Identifier<TDeps[number]>,
156
+ ServiceMap.Service.Identifier<TDeps[number]>,
167
157
  LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
168
158
  >
169
159
  | LayerUtils.GetLayersContext<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
170
160
  >
171
161
 
172
- export const EmptyContextProvider = ContextProvider({ effect: Effect.succeed(Effect.succeed(Context.empty())) })
162
+ export const EmptyContextProvider = ContextProvider({ effect: Effect.succeed(Effect.succeed(ServiceMap.empty())) })
package/src/api/codec.ts CHANGED
@@ -4,6 +4,6 @@ export function makeCodec<
4
4
  From,
5
5
  To extends { id: Id },
6
6
  Id
7
- >(self: S.Schema<To, From>) {
7
+ >(self: S.Codec<To, From>) {
8
8
  return [S.decodeSync(self), S.encodeSync(self)] as const
9
9
  }
@@ -12,28 +12,28 @@ type Config = Parameters<typeof auth>[0]
12
12
  export const checkJWTI = (config: Config) => {
13
13
  const mw = auth(config)
14
14
  return Effect.fnUntraced(function*(headers: HttpHeaders.Headers) {
15
- return yield* Effect.async<
15
+ return yield* Effect.callback<
16
16
  void,
17
17
  InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError
18
18
  >(
19
- (cb) => {
19
+ (resume) => {
20
20
  const next = (err?: unknown) => {
21
- if (!err) return cb(Effect.void)
21
+ if (!err) return resume(Effect.void)
22
22
  if (
23
23
  err instanceof InsufficientScopeError
24
24
  || err instanceof InvalidRequestError
25
25
  || err instanceof InvalidTokenError
26
26
  || err instanceof UnauthorizedError
27
27
  ) {
28
- return cb(Effect.fail(err))
28
+ return resume(Effect.fail(err))
29
29
  }
30
- return cb(Effect.die(err))
30
+ return resume(Effect.die(err))
31
31
  }
32
32
  const r = { headers, query: {}, body: {}, is: () => false, method: "POST" } // is("urlencoded")
33
33
  try {
34
34
  mw(r as any, {} as any, next)
35
35
  } catch (e) {
36
- return cb(Effect.die(e))
36
+ return resume(Effect.die(e))
37
37
  }
38
38
  }
39
39
  )
@@ -45,13 +45,11 @@ export const checkJwt = (config: Config) => {
45
45
  return HttpMiddleware.make((app) =>
46
46
  Effect.gen(function*() {
47
47
  const req = yield* HttpServerRequest.HttpServerRequest
48
- const response = yield* check(req.headers).pipe(Effect.catchAll((e) =>
49
- Effect.succeed(
50
- HttpServerResponse.unsafeJson({ message: e.message }, {
51
- status: e.status,
52
- headers: HttpHeaders.fromInput(e.headers)
53
- })
54
- )
48
+ const response = yield* check(req.headers).pipe(Effect.catch((e) =>
49
+ HttpServerResponse.json({ message: e.message }, {
50
+ status: e.status,
51
+ headers: HttpHeaders.fromInput(e.headers)
52
+ })
55
53
  ))
56
54
  if (response) {
57
55
  return response
@@ -5,18 +5,18 @@ import { setupRequestContextFromCurrent } from "../setupRequest.js"
5
5
 
6
6
  // Tell the client to retry every 10 seconds if connectivity is lost
7
7
  const setRetry = Stream.succeed("retry: 10000")
8
- const keepAlive = Stream.repeat(Effect.succeed(":keep-alive"), Schedule.fixed(Duration.seconds(15)))
8
+ const keepAlive = Stream.fromEffectSchedule(Effect.succeed(":keep-alive"), Schedule.fixed(Duration.seconds(15)))
9
9
 
10
10
  let connId = BigInt(0)
11
11
 
12
12
  export const makeSSE = <A extends { id: any }, SI, SR>(
13
- schema: S.Schema<A, SI, SR>
13
+ schema: S.Codec<A, SI, SR>
14
14
  ) =>
15
15
  <E, R>(events: Stream.Stream<{ evt: A; namespace: string }, E, R>) =>
16
16
  Effect
17
17
  .gen(function*() {
18
18
  const id = connId++
19
- const ctx = yield* Effect.context<R | SR>()
19
+ const ctx = yield* Effect.services<R | SR>()
20
20
  const res = HttpServerResponse.stream(
21
21
  // workaround for different scoped behaviour for streams in Bun
22
22
  // https://discord.com/channels/795981131316985866/1098177242598756412/1389646879675125861
@@ -28,29 +28,29 @@ export const makeSSE = <A extends { id: any }, SI, SR>(
28
28
 
29
29
  const enc = new TextEncoder()
30
30
 
31
- const encode = S.encode(schema)
31
+ const encode = S.encodeEffect(schema)
32
32
 
33
- const eventStream = Stream.flatMap(
33
+ const eventStream = Stream.mapEffect(
34
34
  events,
35
35
  (_) =>
36
36
  encode(_.evt)
37
- .pipe(Effect.andThen((evt) => `id: ${_.evt.id}\ndata: ${JSON.stringify(evt)}`))
37
+ .pipe(Effect.map((evt) => `id: ${_.evt.id}\ndata: ${JSON.stringify(evt)}`))
38
38
  )
39
39
 
40
40
  const stream = pipe(
41
41
  setRetry,
42
42
  Stream.merge(keepAlive),
43
43
  Stream.merge(eventStream, { haltStrategy: "either" }),
44
- Stream.tapErrorCause((cause) => Effect.logError("SSE error", cause)),
44
+ Stream.tapCause((cause) => Effect.logError("SSE error", cause)),
45
45
  Stream.map((_) => enc.encode(_ + "\n\n"))
46
46
  )
47
47
 
48
48
  return stream
49
49
  })
50
50
  .pipe(
51
- Stream.unwrapScoped,
52
- Stream.tapErrorCause(reportError("Request")),
53
- Stream.provideContext(ctx)
51
+ Stream.unwrap,
52
+ Stream.tapCause(reportError("Request")),
53
+ Stream.provide(ctx)
54
54
  ),
55
55
  {
56
56
  contentType: "text/event-stream",
@@ -64,4 +64,4 @@ export const makeSSE = <A extends { id: any }, SI, SR>(
64
64
  )
65
65
  return res
66
66
  })
67
- .pipe(Effect.tapErrorCause(reportError("Request")), setupRequestContextFromCurrent("events"))
67
+ .pipe(Effect.tapCause(reportError("Request")), setupRequestContextFromCurrent("events"))
@@ -1,5 +1,5 @@
1
1
  import { HttpMiddleware, HttpServerResponse } from "effect-app/http"
2
2
 
3
3
  export function serverHealth(version: string) {
4
- return HttpServerResponse.unsafeJson({ version }).pipe(HttpMiddleware.withLoggerDisabled)
4
+ return HttpServerResponse.json({ version }).pipe(HttpMiddleware.withLoggerDisabled)
5
5
  }
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Context, Effect, type Layer, type NonEmptyReadonlyArray, Option } from "effect-app"
2
+ import { Effect, type Layer, type NonEmptyReadonlyArray, Option, ServiceMap } from "effect-app"
3
3
  import { InfraLogger } from "../logger.js"
4
4
 
5
5
  // TODO: These LayerUtils are flaky, like in dependencies as a readonly array, it breaks when there are two entries
@@ -7,27 +7,27 @@ import { InfraLogger } from "../logger.js"
7
7
  // and in general make sure `dependencies` are NonEmptyReadonlyArrays, so they infer to consts.
8
8
 
9
9
  export namespace LayerUtils {
10
- export type GetLayersSuccess<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
11
- NonEmptyReadonlyArray<Layer.Layer.Any> ? {
12
- [k in keyof Layers]: Layer.Layer.Success<Layers[k]>
10
+ export type GetLayersSuccess<Layers extends ReadonlyArray<Layer.Any>> = Layers extends
11
+ NonEmptyReadonlyArray<Layer.Any> ? {
12
+ [k in keyof Layers]: Layer.Success<Layers[k]>
13
13
  }[number]
14
- : Layer.Layer.Success<Layers[number]>
14
+ : Layer.Success<Layers[number]>
15
15
 
16
- export type GetLayersContext<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
17
- NonEmptyReadonlyArray<Layer.Layer.Any> ? {
18
- [k in keyof Layers]: Layer.Layer.Context<Layers[k]>
16
+ export type GetLayersContext<Layers extends ReadonlyArray<Layer.Any>> = Layers extends
17
+ NonEmptyReadonlyArray<Layer.Any> ? {
18
+ [k in keyof Layers]: Layer.Services<Layers[k]>
19
19
  }[number]
20
- : Layer.Layer.Context<Layers[number]>
20
+ : Layer.Services<Layers[number]>
21
21
 
22
- export type GetLayersError<Layers extends ReadonlyArray<Layer.Layer.Any>> = Layers extends
23
- NonEmptyReadonlyArray<Layer.Layer.Any> ? {
24
- [k in keyof Layers]: Layer.Layer.Error<Layers[k]>
22
+ export type GetLayersError<Layers extends ReadonlyArray<Layer.Any>> = Layers extends NonEmptyReadonlyArray<Layer.Any>
23
+ ? {
24
+ [k in keyof Layers]: Layer.Error<Layers[k]>
25
25
  }[number]
26
- : Layer.Layer.Error<Layers[number]>
26
+ : Layer.Error<Layers[number]>
27
27
  }
28
28
 
29
29
  export type ContextTagWithDefault<Id, A, LayerE, LayerR> =
30
- & Context.Tag<Id, A>
30
+ & ServiceMap.Service<Id, A>
31
31
  & {
32
32
  Default: Layer.Layer<Id, LayerE, LayerR>
33
33
  }
@@ -36,29 +36,29 @@ export namespace ContextTagWithDefault {
36
36
  export type Base<A> = ContextTagWithDefault<any, A, any, any>
37
37
  }
38
38
 
39
- export type GetContext<T> = T extends Context.Context<infer Y> ? Y : never
39
+ export type GetContext<T> = T extends ServiceMap.ServiceMap<infer Y> ? Y : never
40
40
 
41
41
  export const mergeContexts = Effect.fnUntraced(
42
42
  function*<
43
43
  T extends readonly {
44
44
  maker: any
45
- handle: Effect.Effect<Context.Context<any> | Option.Option<Context.Context<any>>>
45
+ handle: Effect.Effect<ServiceMap.ServiceMap<any> | Option.Option<ServiceMap.ServiceMap<any>>>
46
46
  }[]
47
47
  >(
48
48
  makers: T
49
49
  ) {
50
- let context = Context.empty()
50
+ let context = ServiceMap.empty()
51
51
  for (const mw of makers) {
52
52
  const ctx = yield* mw.handle.pipe(Effect.provide(context))
53
- const moreContext = Context.isContext(ctx) ? Option.some(ctx) : ctx
53
+ const moreContext = ServiceMap.isServiceMap(ctx) ? Option.some(ctx) : ctx
54
54
  yield* InfraLogger.logDebug(
55
55
  "Built dynamic context for middleware" + (mw.maker.key ?? mw.maker),
56
56
  Option.map(moreContext, (c) => (c as any).toJSON().services)
57
57
  )
58
58
  if (moreContext.value) {
59
- context = Context.merge(context, moreContext.value)
59
+ context = ServiceMap.merge(context, moreContext.value)
60
60
  }
61
61
  }
62
- return context as Context.Context<Effect.Effect.Success<T[number]["handle"]>>
62
+ return context as ServiceMap.ServiceMap<Effect.Success<T[number]["handle"]>>
63
63
  }
64
64
  )