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

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 +11 -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,5 +1,5 @@
1
1
  import { describe, expect, it } from "@effect/vitest"
2
- import { Array, Config, Effect, flow, Layer, Logger, LogLevel, ManagedRuntime, Option, Redacted, S } from "effect-app"
2
+ import { Array, Config, Effect, flow, Layer, ManagedRuntime, Redacted, References, Result, S, ServiceMap } from "effect-app"
3
3
  import { LogLevels } from "effect-app/utils"
4
4
  import { setupRequestContextFromCurrent } from "../src/api/setupRequest.js"
5
5
  import { and, or, project, where, whereEvery, whereSome } from "../src/Model/query.js"
@@ -10,13 +10,14 @@ import { MemoryStoreLive } from "../src/Store/Memory.js"
10
10
  export const rt = ManagedRuntime.make(Layer.mergeAll(
11
11
  Layer.effect(
12
12
  LogLevels,
13
- LogLevels.pipe(Effect.map((_) => {
14
- const m = new Map(_)
13
+ Effect.gen(function*() {
14
+ const levels = yield* LogLevels
15
+ const m = new Map(levels)
15
16
  m.set("@effect-app/infra", "debug")
16
17
  return m
17
- }))
18
+ })
18
19
  ),
19
- Logger.minimumLogLevel(LogLevel.Debug)
20
+ Layer.succeed(References.MinimumLogLevel, "Debug")
20
21
  ))
21
22
 
22
23
  class Something extends S.Class<Something>("Something")({
@@ -48,18 +49,21 @@ const items = [
48
49
  ]
49
50
 
50
51
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
51
- class SomethingRepo extends Effect.Service<SomethingRepo>()("SomethingRepo", {
52
- effect: Effect.gen(function*() {
53
- const partitionKey = "test-" + new Date().getTime()
54
- return yield* makeRepo("Something", Something, { config: { partitionValue: () => partitionKey } })
55
- })
56
- }) {
52
+ class SomethingRepo extends ServiceMap.Service<SomethingRepo>()(
53
+ "SomethingRepo",
54
+ {
55
+ make: Effect.gen(function*() {
56
+ const partitionKey = "test-" + new Date().getTime()
57
+ return yield* makeRepo("Something", Something, { config: { partitionValue: () => partitionKey } })
58
+ })
59
+ }
60
+ ) {
57
61
  static readonly layer = Layer
58
62
  .effect(
59
63
  SomethingRepo,
60
64
  Effect.gen(function*() {
61
65
  const partitionKey = "test-" + new Date().getTime()
62
- const repo = SomethingRepo.make(
66
+ const repo = SomethingRepo.of(
63
67
  yield* makeRepo("Something", Something, {
64
68
  config: { partitionValue: () => partitionKey }
65
69
  })
@@ -79,21 +83,21 @@ class SomethingRepo extends Effect.Service<SomethingRepo>()("SomethingRepo", {
79
83
  .layer
80
84
  .pipe(
81
85
  Layer.provide(
82
- Config.redacted("STORAGE_URL").pipe(
83
- Config.withDefault(Redacted
84
- .make(
85
- // the emulator doesn't implement array projections :/ so you need an actual cloud instance!
86
- "AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
87
- )),
88
- Effect.map((url) =>
89
- CosmosStoreLayer({
90
- dbName: "test",
91
- prefix: "",
92
- url
93
- })
94
- ),
95
- Layer.unwrapEffect
96
- )
86
+ Effect.gen(function*() {
87
+ const url = yield* Config.redacted("STORAGE_URL").pipe(
88
+ Config.withDefault(
89
+ Redacted.make(
90
+ // the emulator doesn't implement array projections :/ so you need an actual cloud instance!
91
+ "AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
92
+ )
93
+ )
94
+ )
95
+ return CosmosStoreLayer({
96
+ dbName: "test",
97
+ prefix: "",
98
+ url
99
+ })
100
+ }).pipe(Layer.unwrap)
97
101
  )
98
102
  )
99
103
  }
@@ -115,7 +119,7 @@ describe("select first-level array fields", () => {
115
119
  FROM Somethings f`,
116
120
  parameters: []
117
121
  }),
118
- memory: (items) =>
122
+ memory: (items: readonly Something[]) =>
119
123
  items.map(({ items, name }) => ({
120
124
  name,
121
125
  items: items.map(({ id, value }) => ({ id, value }))
@@ -205,13 +209,13 @@ describe("filter first-level array fields as groups", () => {
205
209
  WHERE (items["value"] > @v1 AND CONTAINS(items["description"], @v2, true))`,
206
210
  parameters: [{ name: "@v1", value: 20 }, { name: "@v2", value: "d item" }]
207
211
  }),
208
- memory: Array.filterMap(({ items, name }) =>
209
- items.some((_) => _.value > 20 && _.description.includes("d item"))
210
- ? Option.some({
211
- name,
212
- items: items.map(({ id, value }) => ({ id, value }))
212
+ memory: Array.filterMap((item: Something) =>
213
+ item.items.some((_) => _.value > 20 && _.description.includes("d item"))
214
+ ? Result.succeed({
215
+ name: item.name,
216
+ items: item.items.map(({ id, value }) => ({ id, value }))
213
217
  })
214
- : Option.none()
218
+ : Result.fail(item)
215
219
  )
216
220
  })
217
221
 
@@ -226,13 +230,13 @@ describe("filter first-level array fields as groups", () => {
226
230
  WHERE EXISTS(SELECT VALUE item FROM item IN f.items WHERE item["value"] > @v1 AND CONTAINS(item.description, @v2, true))`,
227
231
  parameters: [{ name: "@v1", value: 20 }, { name: "@v2", value: "d item" }]
228
232
  }),
229
- memory: Array.filterMap(({ items, name }) =>
230
- items.some((_) => _.value > 20 && _.description.includes("d item"))
231
- ? Option.some({
232
- name,
233
- items: items.map(({ id, value }) => ({ id, value }))
233
+ memory: Array.filterMap((item: Something) =>
234
+ item.items.some((_) => _.value > 20 && _.description.includes("d item"))
235
+ ? Result.succeed({
236
+ name: item.name,
237
+ items: item.items.map(({ id, value }) => ({ id, value }))
234
238
  })
235
- : Option.none()
239
+ : Result.fail(item)
236
240
  )
237
241
  })
238
242
 
@@ -1,11 +1,12 @@
1
- import { Rpc } from "@effect/rpc"
2
- import { type SuccessValue } from "@effect/rpc/RpcMiddleware"
3
1
  import { describe, expect, expectTypeOf, it } from "@effect/vitest"
4
- import { Context, Effect, Either, Layer, S } from "effect-app"
2
+ import { Effect, Layer, Result, S, ServiceMap } from "effect-app"
5
3
  import { NotLoggedInError, UnauthorizedError } from "effect-app/client"
6
4
  import { HttpHeaders } from "effect-app/http"
7
5
  import * as RpcX from "effect-app/rpc"
8
6
  import { MiddlewareMaker } from "effect-app/rpc"
7
+ import type { unhandled } from "effect-app/Types"
8
+ import { Rpc } from "effect/unstable/rpc"
9
+ import { type SuccessValue } from "effect/unstable/rpc/RpcMiddleware"
9
10
  import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElseMiddleware, SomeElseMiddlewareLive, SomeMiddleware, SomeMiddlewareLive, SomeService, Test, TestLive } from "./fixtures.js"
10
11
 
11
12
  export class RequiresSomeMiddleware
@@ -54,29 +55,26 @@ expectTypeOf(_middlewareSideways).toEqualTypeOf<typeof middleware3>()
54
55
  expectTypeOf(_middlewareSidewaysFully).toEqualTypeOf<typeof _middlewareSideways>()
55
56
  expectTypeOf(_middleware3Bis).toEqualTypeOf<typeof middleware3>()
56
57
 
57
- class TestRequest extends S.TaggedRequest<TestRequest>("Test")("Test", {
58
- payload: {},
59
- success: S.Void,
60
- failure: S.Never
61
- }) {}
58
+ const TestRpc = Rpc.make("Test", { success: S.Void })
62
59
 
63
60
  const testSuite = (_mw: typeof middleware3) =>
64
61
  describe("middleware" + _mw, () => {
65
62
  it.effect(
66
63
  "works",
67
64
  Effect.fn(function*() {
68
- const defaultReq = {
69
- headers: HttpHeaders.unsafeFromRecord({}),
65
+ const defaultOpts = {
66
+ headers: HttpHeaders.fromRecordUnsafe({}),
70
67
  payload: { _tag: "Test" },
71
68
  clientId: 0,
72
- rpc: { ...Rpc.fromTaggedRequest(TestRequest), annotations: Context.make(_mw.requestContext, {}) },
73
- next: Effect.void as unknown as Effect.Effect<SuccessValue, never, any>
69
+ requestId: "test-id" as any,
70
+ rpc: { ...TestRpc, annotations: ServiceMap.make(_mw.requestContext, {}) }
74
71
  }
72
+ const next = Effect.void as unknown as Effect.Effect<SuccessValue, unhandled, never>
75
73
  const layer = _mw.layer.pipe(
76
74
  Layer.provide([
77
75
  RequiresSomeMiddleware.Default,
78
76
  SomeMiddlewareLive,
79
- RequireRolesLive.pipe(Layer.provide(SomeService.toLayer())),
77
+ RequireRolesLive.pipe(Layer.provide(SomeService.toLayer(SomeService.make))),
80
78
  AllowAnonymousLive,
81
79
  TestLive,
82
80
  SomeElseMiddlewareLive
@@ -86,9 +84,13 @@ const testSuite = (_mw: typeof middleware3) =>
86
84
  .gen(function*() {
87
85
  const mw = yield* _mw
88
86
  const mwM = mw(
89
- Object.assign({ ...defaultReq }, {
90
- headers: { "x-user": "test-user", "x-is-manager": "true" },
91
- rpc: { ...defaultReq.rpc, annotations: Context.make(_mw.requestContext, { requireRoles: ["manager"] }) }
87
+ next,
88
+ Object.assign({ ...defaultOpts }, {
89
+ headers: HttpHeaders.fromRecordUnsafe({ "x-user": "test-user", "x-is-manager": "true" }),
90
+ rpc: {
91
+ ...defaultOpts.rpc,
92
+ annotations: ServiceMap.make(_mw.requestContext, { requireRoles: ["manager"] })
93
+ }
92
94
  })
93
95
  )
94
96
  yield* mwM
@@ -103,27 +105,29 @@ const testSuite = (_mw: typeof middleware3) =>
103
105
  .gen(function*() {
104
106
  const mw = yield* _mw
105
107
  const mwM = mw(
106
- Object.assign({ ...defaultReq }, {})
108
+ next,
109
+ Object.assign({ ...defaultOpts }, {})
107
110
  )
108
111
  yield* mwM
109
112
  })
110
113
  .pipe(
111
114
  Effect.scoped,
112
115
  Effect.provide(layer),
113
- Effect.either
116
+ Effect.result
114
117
  )
115
118
  )
116
- .toEqual(Either.left(new NotLoggedInError()))
119
+ .toEqual(Result.fail(new NotLoggedInError()))
117
120
 
118
121
  expect(
119
122
  yield* Effect
120
123
  .gen(function*() {
121
124
  const mw = yield* _mw
122
125
  const mwM = mw(
123
- Object.assign({ ...defaultReq }, {
126
+ next,
127
+ Object.assign({ ...defaultOpts }, {
124
128
  rpc: {
125
- ...defaultReq.rpc,
126
- annotations: Context.make(_mw.requestContext, { requireRoles: ["manager"] })
129
+ ...defaultOpts.rpc,
130
+ annotations: ServiceMap.make(_mw.requestContext, { requireRoles: ["manager"] })
127
131
  }
128
132
  })
129
133
  )
@@ -132,32 +136,37 @@ const testSuite = (_mw: typeof middleware3) =>
132
136
  .pipe(
133
137
  Effect.scoped,
134
138
  Effect.provide(layer),
135
- Effect.either
139
+ Effect.result
136
140
  )
137
141
  )
138
- .toEqual(Either.left(new NotLoggedInError()))
142
+ .toEqual(Result.fail(new NotLoggedInError()))
139
143
 
140
144
  expect(
141
145
  yield* Effect
142
146
  .gen(function*() {
143
147
  const mw = yield* _mw
144
148
  const mwM = mw(
145
- Object.assign({ ...defaultReq }, { headers: { "x-user": "test-user" } }, {
146
- rpc: {
147
- ...defaultReq.rpc,
148
- annotations: Context.make(_mw.requestContext, { requireRoles: ["manager"] })
149
+ next,
150
+ Object.assign(
151
+ { ...defaultOpts },
152
+ { headers: HttpHeaders.fromRecordUnsafe({ "x-user": "test-user" }) },
153
+ {
154
+ rpc: {
155
+ ...defaultOpts.rpc,
156
+ annotations: ServiceMap.make(_mw.requestContext, { requireRoles: ["manager"] })
157
+ }
149
158
  }
150
- })
159
+ )
151
160
  )
152
161
  yield* mwM
153
162
  })
154
163
  .pipe(
155
164
  Effect.scoped,
156
165
  Effect.provide(layer),
157
- Effect.either
166
+ Effect.result
158
167
  )
159
168
  )
160
- .toEqual(Either.left(new UnauthorizedError({ message: "don't have the right roles" })))
169
+ .toEqual(Result.fail(new UnauthorizedError({ message: "don't have the right roles" })))
161
170
  })
162
171
  )
163
172
  })
@@ -1,14 +1,14 @@
1
- import { FetchHttpClient } from "@effect/platform"
2
1
  import { NodeHttpServer } from "@effect/platform-node"
3
- import { RpcClient, RpcGroup, RpcSerialization, RpcServer, RpcTest } from "@effect/rpc"
4
2
  import { expect, expectTypeOf, it } from "@effect/vitest"
5
- import { Console, Effect, Either, Layer } from "effect"
3
+ import { Console, Effect, Layer, Result } from "effect"
6
4
  import { S } from "effect-app"
7
5
  import { NotLoggedInError } from "effect-app/client"
8
- import { HttpLayerRouter } from "effect-app/http"
6
+ import { HttpRouter } from "effect-app/http"
9
7
  import { DefaultGenericMiddlewares } from "effect-app/middleware"
10
8
  import { MiddlewareMaker } from "effect-app/rpc"
11
9
  import { middlewareGroup } from "effect-app/rpc/MiddlewareMaker"
10
+ import { FetchHttpClient } from "effect/unstable/http"
11
+ import { RpcClient, RpcGroup, RpcSerialization, RpcServer, RpcTest } from "effect/unstable/rpc"
12
12
  import { createServer } from "http"
13
13
  import { DefaultGenericMiddlewaresLive } from "../src/api/routing.js"
14
14
  import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElseMiddleware, SomeElseMiddlewareLive, SomeMiddleware, SomeMiddlewareLive, SomeService, Test, TestLive, UserProfile } from "./fixtures.js"
@@ -54,7 +54,7 @@ const impl = UserRpcs
54
54
  })
55
55
  })
56
56
 
57
- expectTypeOf<Layer.Layer.Context<typeof impl>>().toEqualTypeOf<never>()
57
+ expectTypeOf<Layer.Services<typeof impl>>().toEqualTypeOf<never>()
58
58
 
59
59
  const UserRpcsBad = middlewareGroup(middleware)(
60
60
  RpcGroup.make(
@@ -72,8 +72,7 @@ export const badImpl = UserRpcsBad
72
72
  return "also-awesome2" as const
73
73
  })
74
74
  })
75
-
76
- expectTypeOf<Layer.Layer.Context<typeof badImpl>>().toEqualTypeOf<UserProfile>()
75
+ expectTypeOf<Layer.Services<typeof badImpl>>().toEqualTypeOf<UserProfile>()
77
76
 
78
77
  const middlwareLayer = middleware
79
78
  .layer
@@ -83,7 +82,7 @@ const middlwareLayer = middleware
83
82
  SomeElseMiddlewareLive,
84
83
  SomeMiddlewareLive,
85
84
  TestLive,
86
- RequireRolesLive.pipe(Layer.provide(SomeService.toLayer())),
85
+ RequireRolesLive.pipe(Layer.provide(SomeService.Default)),
87
86
  AllowAnonymousLive
88
87
  ])
89
88
  )
@@ -96,10 +95,10 @@ export const RpcTestLayer = Layer
96
95
 
97
96
  export const RpcRealLayer = Layer
98
97
  .mergeAll(
99
- HttpLayerRouter
98
+ HttpRouter
100
99
  .serve(
101
100
  RpcServer
102
- .layerHttpRouter({ group: UserRpcs, path: "/rpc", protocol: "http" })
101
+ .layerHttp({ group: UserRpcs, path: "/rpc", protocol: "http" })
103
102
  .pipe(Layer.provide(impl))
104
103
  .pipe(Layer.provide(middlwareLayer))
105
104
  )
@@ -112,20 +111,20 @@ export const RpcRealLayer = Layer
112
111
  )
113
112
  .pipe(Layer.provide(RpcSerialization.layerJson))
114
113
 
115
- it.scopedLive(
114
+ it.live(
116
115
  "require login",
117
116
  Effect.fnUntraced(
118
117
  function*() {
119
118
  const userClient = yield* RpcTest.makeClient(UserRpcs) // RpcTest.makeClient(UserRpcs) // RpcClient.make(UserRpcs)
120
119
 
121
- const user = yield* Effect.either(userClient.getUser().pipe(Effect.onExit((_) => Console.dir(_, { depth: 10 }))))
122
- expect(user).toStrictEqual(Either.left(new NotLoggedInError("Not logged in")))
120
+ const user = yield* Effect.result(userClient.getUser().pipe(Effect.onExit((_) => Console.dir(_, { depth: 10 }))))
121
+ expect(user).toStrictEqual(Result.fail(new NotLoggedInError("Not logged in")))
123
122
  },
124
123
  Effect.provide(RpcTestLayer)
125
124
  )
126
125
  )
127
126
 
128
- it.scopedLive(
127
+ it.live(
129
128
  "allow anonymous, optional UserProfile",
130
129
  Effect.fnUntraced(
131
130
  function*() {
@@ -203,9 +203,9 @@ describe("validateSample", () => {
203
203
  count: -999
204
204
  })
205
205
 
206
- // error should be a ParseError
206
+ // error should be a SchemaError
207
207
  expect(error.error).toBeDefined()
208
- expect((error.error as any)._tag).toBe("ParseError")
208
+ expect((error.error as any)._tag).toBe("SchemaError")
209
209
  })
210
210
  .pipe(
211
211
  Effect.provide(MemoryStoreLive),
package/tsconfig.json CHANGED
@@ -14,33 +14,7 @@
14
14
  "isolatedModules": true,
15
15
  "esModuleInterop": true,
16
16
  "skipLibCheck": true,
17
- "plugins": [
18
- {
19
- "name": "ts-plugin-sort-import-suggestions",
20
- "moveUpPatterns": [
21
- "\\.{1,2}/",
22
- "^(?:\\.\\./)+",
23
- "^#",
24
- "^@/",
25
- "effect",
26
- "^@effect/"
27
- ],
28
- "moveDownPatterns": [
29
- "^node_modules/"
30
- ],
31
- "overrides": {
32
- "effect-app": []
33
- }
34
- },
35
- {
36
- "name": "@effect/language-service",
37
- "diagnosticSeverity": {
38
- "missingEffectServiceDependency": "error",
39
- "effectFnOpportunity": "warning",
40
- "globalErrorInEffectFailure": "warning"
41
- }
42
- }
43
- ],
17
+ "plugins": [],
44
18
  "module": "Node16",
45
19
  "lib": [
46
20
  "ES2023"
@@ -1,15 +0,0 @@
1
- import { NotLoggedInError } from "@effect-app/infra/errors";
2
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
3
- import * as ServerResponse from "@effect/platform/HttpServerResponse";
4
- import { Effect } from "effect-app";
5
- import type * as Middlewares from "../middlewares.js";
6
- export declare const accessLog: (level?: "Info" | "Warning" | "Debug") => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
7
- export declare const uuidLogAnnotation: (logAnnotationKey?: string) => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
8
- export declare const endpointCallsMetric: () => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
9
- export declare const errorLog: <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
10
- export declare const basicAuth: <_, R>(checkCredentials: (credentials: Middlewares.BasicAuthCredentials) => Effect.Effect<_, NotLoggedInError, R>, options?: Partial<{
11
- headerName: string;
12
- skipPaths: readonly string[];
13
- }>) => <E, R_1>(app: import("@effect/platform/HttpApp").Default<E, R_1>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R | R_1>;
14
- export declare const cors: (_options?: Partial<Middlewares.CorsOptions>) => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
15
- //# sourceMappingURL=middlewares.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"middlewares.d.ts","sourceRoot":"","sources":["../../../src/api/internal/middlewares.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,iBAAiB,MAAM,oCAAoC,CAAA;AACvE,OAAO,KAAK,cAAc,MAAM,qCAAqC,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AASnC,OAAO,KAAK,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAErD,eAAO,MAAM,SAAS,GAAI,QAAO,MAAM,GAAG,SAAS,GAAG,OAAgB,kKAOnE,CAAA;AAEH,eAAO,MAAM,iBAAiB,GAAI,yBAA8B,kKAY7D,CAAA;AAEH,eAAO,MAAM,mBAAmB,qKAe/B,CAAA;AAED,eAAO,MAAM,QAAQ,+JAkBpB,CAAA;AAQD,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,EAC5B,kBAAkB,CAChB,WAAW,EAAE,WAAW,CAAC,oBAAoB,KAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,EAC1C,UAAU,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B,CAAC,4KA+DD,CAAA;AAEH,eAAO,MAAM,IAAI,GAAI,WAAW,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,kKAsH/D,CAAA"}
@@ -1,168 +0,0 @@
1
- /**
2
- * Mechanism for extendning behaviour of all handlers on the server.
3
- *
4
- * @since 1.0.0
5
- */
6
- import * as crypto from "crypto";
7
- import { NotLoggedInError } from "@effect-app/infra/errors";
8
- import * as Middleware from "@effect/platform/HttpMiddleware";
9
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
10
- import * as ServerResponse from "@effect/platform/HttpServerResponse";
11
- import { Effect } from "effect-app";
12
- import { HttpBody, HttpHeaders, HttpServerResponse } from "effect-app/http";
13
- import { dropUndefined } from "effect-app/utils";
14
- import * as Either from "effect/Either";
15
- import * as FiberRef from "effect/FiberRef";
16
- import { pipe } from "effect/Function";
17
- import * as HashMap from "effect/HashMap";
18
- import * as Metric from "effect/Metric";
19
- import { InfraLogger } from "../../logger.js";
20
- export const accessLog = (level = "Info") => Middleware.make((app) => pipe(HttpServerRequest.HttpServerRequest, Effect.flatMap((request) => Effect[`log${level}`](`${request.method} ${request.url}`)), Effect.flatMap(() => app)));
21
- export const uuidLogAnnotation = (logAnnotationKey = "requestId") => Middleware.make((app) => pipe(Effect.sync(() => crypto.randomUUID()), Effect.flatMap((uuid) => FiberRef.update(FiberRef.currentLogAnnotations, HashMap.set(logAnnotationKey, uuid))), Effect.flatMap(() => app)));
22
- export const endpointCallsMetric = () => {
23
- const endpointCalledCounter = Metric.counter("server.endpoint_calls");
24
- return Middleware.make((app) => Effect.gen(function* () {
25
- const request = yield* (HttpServerRequest.HttpServerRequest);
26
- yield* pipe(Metric.increment(endpointCalledCounter), Effect.tagMetrics("path", request.url));
27
- return yield* app;
28
- }));
29
- };
30
- export const errorLog = Middleware.make((app) => Effect.gen(function* () {
31
- const request = yield* HttpServerRequest.HttpServerRequest;
32
- const response = yield* app;
33
- if (response.status >= 400 && response.status < 500) {
34
- yield* InfraLogger.logWarning(`${request.method.toUpperCase()} ${request.url} client error ${response.status}`);
35
- }
36
- else if (response.status >= 500) {
37
- yield* InfraLogger.logError(`${request.method.toUpperCase()} ${request.url} server error ${response.status}`);
38
- }
39
- return response;
40
- }));
41
- const toServerResponse = (err) => HttpServerResponse.empty().pipe(HttpServerResponse.setStatus(401), HttpServerResponse.setBody(HttpBody.unsafeJson({ message: err.message })));
42
- export const basicAuth = (checkCredentials, options) => Middleware.make((app) => Effect.gen(function* () {
43
- const headerName = options?.headerName ?? "Authorization";
44
- const skippedPaths = options?.skipPaths ?? [];
45
- const request = yield* HttpServerRequest.HttpServerRequest;
46
- if (skippedPaths.includes(request.url)) {
47
- return yield* app;
48
- }
49
- const authHeader = request.headers[headerName.toLowerCase()];
50
- if (authHeader === undefined) {
51
- return toServerResponse(new NotLoggedInError(`Expected header ${headerName}`));
52
- }
53
- const authorizationParts = authHeader.split(" ");
54
- if (authorizationParts.length !== 2) {
55
- return toServerResponse(new NotLoggedInError("Incorrect auhorization scheme. Expected \"Basic <credentials>\""));
56
- }
57
- if (authorizationParts[0] !== "Basic") {
58
- return toServerResponse(new NotLoggedInError(`Incorrect auhorization type. Expected "Basic", got "${authorizationParts[0]}"`));
59
- }
60
- const credentialsBuffer = Buffer.from(authorizationParts[1], "base64");
61
- const credentialsText = credentialsBuffer.toString("utf-8");
62
- const credentialsParts = credentialsText.split(":");
63
- if (credentialsParts.length !== 2) {
64
- return toServerResponse(new NotLoggedInError("Incorrect basic auth credentials format. Expected base64 encoded \"<user>:<pass>\"."));
65
- }
66
- const check = yield* Effect.either(checkCredentials({
67
- user: credentialsParts[0],
68
- password: credentialsParts[1]
69
- }));
70
- if (Either.isLeft(check)) {
71
- return toServerResponse(check.left);
72
- }
73
- return yield* app;
74
- }));
75
- export const cors = (_options) => {
76
- const DEFAULTS = {
77
- allowedOrigins: ["*"],
78
- allowedMethods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
79
- allowedHeaders: [],
80
- exposedHeaders: [],
81
- credentials: false
82
- };
83
- const options = { ...DEFAULTS, ..._options };
84
- const isAllowedOrigin = (origin) => {
85
- return options.allowedOrigins.includes(origin);
86
- };
87
- const allowOrigin = (originHeader) => {
88
- if (options.allowedOrigins.includes("*")) {
89
- return { "Access-Control-Allow-Origin": "*" };
90
- }
91
- if (options.allowedOrigins.length === 0) {
92
- return { "Access-Control-Allow-Origin": "*" };
93
- }
94
- if (isAllowedOrigin(originHeader)) {
95
- return {
96
- "Access-Control-Allow-Origin": originHeader,
97
- Vary: "Origin"
98
- };
99
- }
100
- return undefined;
101
- };
102
- const allowMethods = (() => {
103
- if (options.allowedMethods.length > 0) {
104
- return {
105
- "Access-Control-Allow-Methods": options.allowedMethods.join(", ")
106
- };
107
- }
108
- return undefined;
109
- })();
110
- const allowCredentials = (() => {
111
- if (options.credentials) {
112
- return { "Access-Control-Allow-Credentials": "true" };
113
- }
114
- return undefined;
115
- })();
116
- const allowHeaders = (accessControlRequestHeaders) => {
117
- if (!options.allowedOrigins)
118
- return undefined;
119
- if (options.allowedHeaders.length === 0 && accessControlRequestHeaders) {
120
- return {
121
- Vary: "Access-Control-Request-Headers",
122
- "Access-Control-Allow-Headers": accessControlRequestHeaders
123
- };
124
- }
125
- if (options.allowedHeaders.length) {
126
- return {
127
- "Access-Control-Allow-Headers": options.allowedHeaders.join(",")
128
- };
129
- }
130
- return undefined;
131
- };
132
- const exposeHeaders = (() => {
133
- if (options.exposedHeaders.length > 0) {
134
- return {
135
- "Access-Control-Expose-Headers": options.exposedHeaders.join(",")
136
- };
137
- }
138
- return undefined;
139
- })();
140
- const maxAge = (() => {
141
- if (options.maxAge) {
142
- return { "Access-Control-Max-Age": options.maxAge.toString() };
143
- }
144
- return undefined;
145
- })();
146
- return Middleware.make((app) => Effect.gen(function* () {
147
- const request = yield* HttpServerRequest.HttpServerRequest;
148
- const origin = request.headers["origin"];
149
- const accessControlRequestHeaders = request.headers["access-control-request-headers"];
150
- let corsHeaders = {
151
- ...allowOrigin(origin ?? ""),
152
- ...allowCredentials,
153
- ...exposeHeaders
154
- };
155
- if (request.method === "OPTIONS") {
156
- corsHeaders = {
157
- ...corsHeaders,
158
- ...allowMethods,
159
- ...allowHeaders(accessControlRequestHeaders),
160
- ...maxAge
161
- };
162
- return ServerResponse.empty({ status: 204, headers: HttpHeaders.fromInput(dropUndefined(corsHeaders)) });
163
- }
164
- const response = yield* app;
165
- return response.pipe(ServerResponse.setHeaders(dropUndefined(corsHeaders)));
166
- }));
167
- };
168
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL2ludGVybmFsL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQTtBQUVoQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQTtBQUMzRCxPQUFPLEtBQUssVUFBVSxNQUFNLGlDQUFpQyxDQUFBO0FBQzdELE9BQU8sS0FBSyxpQkFBaUIsTUFBTSxvQ0FBb0MsQ0FBQTtBQUN2RSxPQUFPLEtBQUssY0FBYyxNQUFNLHFDQUFxQyxDQUFBO0FBQ3JFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbkMsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUMzRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDaEQsT0FBTyxLQUFLLE1BQU0sTUFBTSxlQUFlLENBQUE7QUFDdkMsT0FBTyxLQUFLLFFBQVEsTUFBTSxpQkFBaUIsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDdEMsT0FBTyxLQUFLLE9BQU8sTUFBTSxnQkFBZ0IsQ0FBQTtBQUN6QyxPQUFPLEtBQUssTUFBTSxNQUFNLGVBQWUsQ0FBQTtBQUN2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFHN0MsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLENBQUMsUUFBc0MsTUFBTSxFQUFFLEVBQUUsQ0FDeEUsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQ3RCLElBQUksQ0FDRixpQkFBaUIsQ0FBQyxpQkFBaUIsRUFDbkMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFB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