effect-app 4.0.0-beta.30 → 4.0.0-beta.300

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 (365) hide show
  1. package/CHANGELOG.md +1433 -0
  2. package/dist/Array.d.ts +2 -1
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +4 -4
  5. package/dist/Chunk.d.ts.map +1 -1
  6. package/dist/Config/SecretURL.d.ts +3 -1
  7. package/dist/Config/SecretURL.d.ts.map +1 -1
  8. package/dist/Config/SecretURL.js +3 -6
  9. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  10. package/dist/Config/internal/configSecretURL.js +2 -2
  11. package/dist/Config.d.ts +2 -0
  12. package/dist/Config.d.ts.map +1 -0
  13. package/dist/Config.js +8 -0
  14. package/dist/ConfigProvider.d.ts +2 -0
  15. package/dist/ConfigProvider.d.ts.map +1 -0
  16. package/dist/ConfigProvider.js +6 -0
  17. package/dist/{ServiceMap.d.ts → Context.d.ts} +18 -20
  18. package/dist/Context.d.ts.map +1 -0
  19. package/dist/Context.js +67 -0
  20. package/dist/DataDependencies.d.ts +388 -0
  21. package/dist/DataDependencies.d.ts.map +1 -0
  22. package/dist/DataDependencies.js +64 -0
  23. package/dist/Effect.d.ts +10 -9
  24. package/dist/Effect.d.ts.map +1 -1
  25. package/dist/Effect.js +5 -8
  26. package/dist/Emailer.d.ts +51 -0
  27. package/dist/Emailer.d.ts.map +1 -0
  28. package/dist/Emailer.js +7 -0
  29. package/dist/Function.d.ts.map +1 -1
  30. package/dist/Layer.d.ts +10 -6
  31. package/dist/Layer.d.ts.map +1 -1
  32. package/dist/Layer.js +3 -2
  33. package/dist/Model/Repository/Registry.d.ts +22 -0
  34. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  35. package/dist/Model/Repository/Registry.js +18 -0
  36. package/dist/Model/Repository/ext.d.ts +60 -0
  37. package/dist/Model/Repository/ext.d.ts.map +1 -0
  38. package/dist/Model/Repository/ext.js +122 -0
  39. package/dist/Model/Repository/internal/internal.d.ts +63 -0
  40. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  41. package/dist/Model/Repository/internal/internal.js +438 -0
  42. package/dist/Model/Repository/legacy.d.ts +21 -0
  43. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  44. package/dist/Model/Repository/legacy.js +2 -0
  45. package/dist/Model/Repository/makeRepo.d.ts +54 -0
  46. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  47. package/dist/Model/Repository/makeRepo.js +27 -0
  48. package/dist/Model/Repository/service.d.ts +121 -0
  49. package/dist/Model/Repository/service.d.ts.map +1 -0
  50. package/dist/Model/Repository/service.js +2 -0
  51. package/dist/Model/Repository/validation.d.ts +58 -0
  52. package/dist/Model/Repository/validation.d.ts.map +1 -0
  53. package/dist/Model/Repository/validation.js +32 -0
  54. package/dist/Model/Repository.d.ts +7 -0
  55. package/dist/Model/Repository.d.ts.map +1 -0
  56. package/dist/Model/Repository.js +7 -0
  57. package/dist/Model/dsl.d.ts +33 -0
  58. package/dist/Model/dsl.d.ts.map +1 -0
  59. package/dist/Model/dsl.js +43 -0
  60. package/dist/Model/filter/filterApi.d.ts +30 -0
  61. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  62. package/dist/Model/filter/filterApi.js +2 -0
  63. package/dist/Model/filter/types/errors.d.ts +29 -0
  64. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  65. package/dist/Model/filter/types/errors.js +2 -0
  66. package/dist/Model/filter/types/fields.d.ts +15 -0
  67. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  68. package/dist/Model/filter/types/fields.js +2 -0
  69. package/dist/Model/filter/types/path/common.d.ts +316 -0
  70. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  71. package/dist/Model/filter/types/path/common.js +2 -0
  72. package/dist/Model/filter/types/path/eager.d.ts +94 -0
  73. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  74. package/dist/Model/filter/types/path/eager.js +36 -0
  75. package/dist/Model/filter/types/path/index.d.ts +4 -0
  76. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  77. package/dist/Model/filter/types/path/index.js +3 -0
  78. package/dist/Model/filter/types/utils.d.ts +79 -0
  79. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  80. package/dist/Model/filter/types/utils.js +2 -0
  81. package/dist/Model/filter/types/validator.d.ts +30 -0
  82. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  83. package/dist/Model/filter/types/validator.js +2 -0
  84. package/dist/Model/filter/types.d.ts +5 -0
  85. package/dist/Model/filter/types.d.ts.map +1 -0
  86. package/dist/Model/filter/types.js +7 -0
  87. package/dist/Model/query/dsl.d.ts +514 -0
  88. package/dist/Model/query/dsl.d.ts.map +1 -0
  89. package/dist/Model/query/dsl.js +376 -0
  90. package/dist/Model/query/new-kid-interpreter.d.ts +132 -0
  91. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  92. package/dist/Model/query/new-kid-interpreter.js +361 -0
  93. package/dist/Model/query.d.ts +15 -0
  94. package/dist/Model/query.d.ts.map +1 -0
  95. package/dist/Model/query.js +3 -0
  96. package/dist/Model.d.ts +5 -0
  97. package/dist/Model.d.ts.map +1 -0
  98. package/dist/Model.js +5 -0
  99. package/dist/NonEmptySet.d.ts +3 -1
  100. package/dist/NonEmptySet.d.ts.map +1 -1
  101. package/dist/NonEmptySet.js +2 -2
  102. package/dist/Option.d.ts +1 -0
  103. package/dist/Option.d.ts.map +1 -1
  104. package/dist/Option.js +3 -1
  105. package/dist/Pure.d.ts +7 -5
  106. package/dist/Pure.d.ts.map +1 -1
  107. package/dist/Pure.js +7 -4
  108. package/dist/QueueMaker.d.ts +11 -0
  109. package/dist/QueueMaker.d.ts.map +1 -0
  110. package/dist/QueueMaker.js +11 -0
  111. package/dist/RequestContext.d.ts +87 -0
  112. package/dist/RequestContext.d.ts.map +1 -0
  113. package/dist/RequestContext.js +45 -0
  114. package/dist/RequestScopedDependencies.d.ts +21 -0
  115. package/dist/RequestScopedDependencies.d.ts.map +1 -0
  116. package/dist/RequestScopedDependencies.js +16 -0
  117. package/dist/Schema/Class.d.ts +188 -19
  118. package/dist/Schema/Class.d.ts.map +1 -1
  119. package/dist/Schema/Class.js +260 -17
  120. package/dist/Schema/FastCheck.d.ts.map +1 -1
  121. package/dist/Schema/SchemaParser.d.ts +5 -0
  122. package/dist/Schema/SchemaParser.d.ts.map +1 -0
  123. package/dist/Schema/SchemaParser.js +6 -0
  124. package/dist/Schema/SpecialJsonSchema.d.ts +34 -0
  125. package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
  126. package/dist/Schema/SpecialJsonSchema.js +118 -0
  127. package/dist/Schema/SpecialOpenApi.d.ts +32 -0
  128. package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
  129. package/dist/Schema/SpecialOpenApi.js +123 -0
  130. package/dist/Schema/brand.d.ts +4 -2
  131. package/dist/Schema/brand.d.ts.map +1 -1
  132. package/dist/Schema/brand.js +3 -1
  133. package/dist/Schema/email.d.ts.map +1 -1
  134. package/dist/Schema/email.js +7 -4
  135. package/dist/Schema/ext.d.ts +338 -55
  136. package/dist/Schema/ext.d.ts.map +1 -1
  137. package/dist/Schema/ext.js +358 -53
  138. package/dist/Schema/moreStrings.d.ts +82 -36
  139. package/dist/Schema/moreStrings.d.ts.map +1 -1
  140. package/dist/Schema/moreStrings.js +49 -42
  141. package/dist/Schema/numbers.d.ts +34 -21
  142. package/dist/Schema/numbers.d.ts.map +1 -1
  143. package/dist/Schema/numbers.js +55 -12
  144. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  145. package/dist/Schema/phoneNumber.js +6 -3
  146. package/dist/Schema/schema.d.ts +1 -1
  147. package/dist/Schema/schema.d.ts.map +1 -1
  148. package/dist/Schema/schema.js +2 -2
  149. package/dist/Schema/strings.d.ts +18 -4
  150. package/dist/Schema/strings.d.ts.map +1 -1
  151. package/dist/Schema/strings.js +1 -5
  152. package/dist/Schema.d.ts +222 -8
  153. package/dist/Schema.d.ts.map +1 -1
  154. package/dist/Schema.js +191 -12
  155. package/dist/SchemaAST.d.ts +2 -0
  156. package/dist/SchemaAST.d.ts.map +1 -0
  157. package/dist/SchemaAST.js +2 -0
  158. package/dist/Set.d.ts +4 -1
  159. package/dist/Set.d.ts.map +1 -1
  160. package/dist/Set.js +3 -2
  161. package/dist/Store.d.ts +163 -0
  162. package/dist/Store.d.ts.map +1 -0
  163. package/dist/Store.js +113 -0
  164. package/dist/_ext/Array.d.ts +1 -1
  165. package/dist/_ext/Array.d.ts.map +1 -1
  166. package/dist/_ext/Array.js +4 -2
  167. package/dist/_ext/misc.d.ts +4 -1
  168. package/dist/_ext/misc.d.ts.map +1 -1
  169. package/dist/_ext/misc.js +4 -2
  170. package/dist/_ext/ord.ext.d.ts +2 -1
  171. package/dist/_ext/ord.ext.d.ts.map +1 -1
  172. package/dist/_ext/ord.ext.js +2 -2
  173. package/dist/builtin.d.ts +2 -14
  174. package/dist/builtin.d.ts.map +1 -1
  175. package/dist/builtin.js +1 -1
  176. package/dist/client/InvalidationKeys.d.ts +30 -0
  177. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  178. package/dist/client/InvalidationKeys.js +37 -0
  179. package/dist/client/apiClientFactory.d.ts +19 -31
  180. package/dist/client/apiClientFactory.d.ts.map +1 -1
  181. package/dist/client/apiClientFactory.js +155 -35
  182. package/dist/client/clientFor.d.ts +54 -18
  183. package/dist/client/clientFor.d.ts.map +1 -1
  184. package/dist/client/clientFor.js +9 -1
  185. package/dist/client/errors.d.ts +82 -27
  186. package/dist/client/errors.d.ts.map +1 -1
  187. package/dist/client/errors.js +75 -19
  188. package/dist/client/makeClient.d.ts +490 -34
  189. package/dist/client/makeClient.d.ts.map +1 -1
  190. package/dist/client/makeClient.js +62 -28
  191. package/dist/client.d.ts +2 -0
  192. package/dist/client.d.ts.map +1 -1
  193. package/dist/client.js +3 -1
  194. package/dist/faker.d.ts.map +1 -1
  195. package/dist/http/Request.d.ts +1 -1
  196. package/dist/http/Request.d.ts.map +1 -1
  197. package/dist/http/Request.js +2 -2
  198. package/dist/ids.d.ts +42 -14
  199. package/dist/ids.d.ts.map +1 -1
  200. package/dist/ids.js +30 -5
  201. package/dist/index.d.ts +6 -7
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +8 -8
  204. package/dist/middleware.d.ts +13 -7
  205. package/dist/middleware.d.ts.map +1 -1
  206. package/dist/middleware.js +14 -8
  207. package/dist/rpc/Invalidation.d.ts +3140 -0
  208. package/dist/rpc/Invalidation.d.ts.map +1 -0
  209. package/dist/rpc/Invalidation.js +178 -0
  210. package/dist/rpc/MiddlewareMaker.d.ts +11 -7
  211. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  212. package/dist/rpc/MiddlewareMaker.js +59 -38
  213. package/dist/rpc/RpcContextMap.d.ts +3 -3
  214. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  215. package/dist/rpc/RpcContextMap.js +4 -4
  216. package/dist/rpc/RpcMiddleware.d.ts +14 -10
  217. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  218. package/dist/rpc/RpcMiddleware.js +1 -1
  219. package/dist/rpc.d.ts +1 -1
  220. package/dist/rpc.d.ts.map +1 -1
  221. package/dist/rpc.js +2 -2
  222. package/dist/runtime.d.ts +19 -0
  223. package/dist/runtime.d.ts.map +1 -0
  224. package/dist/runtime.js +40 -0
  225. package/dist/setupRequest.d.ts +20 -0
  226. package/dist/setupRequest.d.ts.map +1 -0
  227. package/dist/setupRequest.js +72 -0
  228. package/dist/toast.d.ts +51 -0
  229. package/dist/toast.d.ts.map +1 -0
  230. package/dist/toast.js +34 -0
  231. package/dist/transform.d.ts +1 -1
  232. package/dist/transform.d.ts.map +1 -1
  233. package/dist/transform.js +4 -5
  234. package/dist/utils/effectify.d.ts +1 -1
  235. package/dist/utils/effectify.d.ts.map +1 -1
  236. package/dist/utils/effectify.js +2 -2
  237. package/dist/utils/extend.d.ts.map +1 -1
  238. package/dist/utils/gen.d.ts +4 -4
  239. package/dist/utils/gen.d.ts.map +1 -1
  240. package/dist/utils/logLevel.d.ts +2 -2
  241. package/dist/utils/logLevel.d.ts.map +1 -1
  242. package/dist/utils/logger.d.ts +4 -3
  243. package/dist/utils/logger.d.ts.map +1 -1
  244. package/dist/utils/logger.js +4 -4
  245. package/dist/utils.d.ts +34 -39
  246. package/dist/utils.d.ts.map +1 -1
  247. package/dist/utils.js +33 -37
  248. package/dist/validation/validators.d.ts.map +1 -1
  249. package/dist/validation.d.ts.map +1 -1
  250. package/dist/withToast.d.ts +30 -0
  251. package/dist/withToast.d.ts.map +1 -0
  252. package/dist/withToast.js +64 -0
  253. package/package.json +27 -251
  254. package/src/Array.ts +5 -5
  255. package/src/Chunk.ts +3 -3
  256. package/src/Config/SecretURL.ts +6 -3
  257. package/src/Config/internal/configSecretURL.ts +2 -2
  258. package/src/Config.ts +7 -0
  259. package/src/ConfigProvider.ts +5 -0
  260. package/src/{ServiceMap.ts → Context.ts} +56 -63
  261. package/src/DataDependencies.ts +114 -0
  262. package/src/Effect.ts +14 -16
  263. package/src/Emailer.ts +51 -0
  264. package/src/Inputify.type.ts +1 -1
  265. package/src/Layer.ts +11 -7
  266. package/src/Model/Repository/Registry.ts +35 -0
  267. package/src/Model/Repository/ext.ts +375 -0
  268. package/src/Model/Repository/internal/internal.ts +755 -0
  269. package/src/Model/Repository/legacy.ts +29 -0
  270. package/src/Model/Repository/makeRepo.ts +145 -0
  271. package/src/Model/Repository/service.ts +676 -0
  272. package/src/Model/Repository/validation.ts +31 -0
  273. package/src/Model/Repository.ts +6 -0
  274. package/src/Model/dsl.ts +129 -0
  275. package/src/Model/filter/filterApi.ts +60 -0
  276. package/src/Model/filter/types/errors.ts +47 -0
  277. package/src/Model/filter/types/fields.ts +50 -0
  278. package/src/Model/filter/types/path/common.ts +404 -0
  279. package/src/Model/filter/types/path/eager.ts +329 -0
  280. package/src/Model/filter/types/path/index.ts +4 -0
  281. package/src/Model/filter/types/utils.ts +128 -0
  282. package/src/Model/filter/types/validator.ts +46 -0
  283. package/src/Model/filter/types.ts +6 -0
  284. package/src/Model/query/dsl.ts +2770 -0
  285. package/src/Model/query/new-kid-interpreter.ts +526 -0
  286. package/src/Model/query.ts +13 -0
  287. package/src/Model.ts +4 -0
  288. package/src/NonEmptySet.ts +6 -4
  289. package/src/Option.ts +2 -0
  290. package/src/Pure.ts +10 -7
  291. package/src/QueueMaker.ts +11 -0
  292. package/src/RequestContext.ts +48 -0
  293. package/src/RequestScopedDependencies.ts +45 -0
  294. package/src/Schema/Class.ts +633 -59
  295. package/src/Schema/SchemaParser.ts +12 -0
  296. package/src/Schema/SpecialJsonSchema.ts +139 -0
  297. package/src/Schema/SpecialOpenApi.ts +130 -0
  298. package/src/Schema/brand.ts +22 -2
  299. package/src/Schema/email.ts +9 -4
  300. package/src/Schema/ext.ts +446 -91
  301. package/src/Schema/moreStrings.ts +147 -68
  302. package/src/Schema/numbers.ts +97 -28
  303. package/src/Schema/phoneNumber.ts +9 -5
  304. package/src/Schema/schema.ts +1 -1
  305. package/src/Schema/strings.ts +23 -14
  306. package/src/Schema.ts +397 -26
  307. package/src/SchemaAST.ts +1 -0
  308. package/src/Set.ts +6 -2
  309. package/src/Store.ts +273 -0
  310. package/src/_ext/Array.ts +4 -2
  311. package/src/_ext/misc.ts +4 -1
  312. package/src/_ext/ord.ext.ts +2 -1
  313. package/src/builtin-json.d.ts +24 -0
  314. package/src/builtin.ts +16 -21
  315. package/src/client/InvalidationKeys.ts +55 -0
  316. package/src/client/apiClientFactory.ts +299 -134
  317. package/src/client/clientFor.ts +107 -34
  318. package/src/client/errors.ts +100 -29
  319. package/src/client/makeClient.ts +594 -78
  320. package/src/client.ts +6 -4
  321. package/src/http/Request.ts +3 -3
  322. package/src/http.ts +1 -1
  323. package/src/ids.ts +33 -6
  324. package/src/index.ts +20 -23
  325. package/src/middleware.ts +13 -9
  326. package/src/rpc/Invalidation.ts +278 -0
  327. package/src/rpc/MiddlewareMaker.ts +88 -80
  328. package/src/rpc/README.md +2 -2
  329. package/src/rpc/RpcContextMap.ts +7 -6
  330. package/src/rpc/RpcMiddleware.ts +19 -13
  331. package/src/rpc.ts +4 -4
  332. package/src/runtime.ts +56 -0
  333. package/src/setupRequest.ts +138 -0
  334. package/src/toast.ts +54 -0
  335. package/src/transform.ts +4 -4
  336. package/src/utils/effectify.ts +1 -1
  337. package/src/utils/gen.ts +8 -8
  338. package/src/utils/logLevel.ts +1 -1
  339. package/src/utils/logger.ts +4 -3
  340. package/src/utils.ts +85 -158
  341. package/src/validation.ts +2 -2
  342. package/src/withToast.ts +133 -0
  343. package/test/dist/rpc.test.d.ts.map +1 -1
  344. package/test/dist/rpcMiddlewareContext.test.d.ts.map +1 -0
  345. package/test/dist/secretURL.test.d.ts.map +1 -0
  346. package/test/dist/special.test.d.ts.map +1 -0
  347. package/test/moreStrings.test.ts +1 -1
  348. package/test/rpc.test.ts +42 -13
  349. package/test/rpcMiddlewareContext.test.ts +63 -0
  350. package/test/schema.test.ts +459 -30
  351. package/test/secretURL.test.ts +160 -0
  352. package/test/special.test.ts +1258 -0
  353. package/test/utils.test.ts +7 -7
  354. package/tsconfig.base.json +6 -5
  355. package/tsconfig.json +3 -1
  356. package/tsconfig.src.json +29 -29
  357. package/tsconfig.test.json +2 -2
  358. package/dist/Operations.d.ts +0 -123
  359. package/dist/Operations.d.ts.map +0 -1
  360. package/dist/Operations.js +0 -29
  361. package/dist/ServiceMap.d.ts.map +0 -1
  362. package/dist/ServiceMap.js +0 -91
  363. package/eslint.config.mjs +0 -26
  364. package/src/Operations.ts +0 -55
  365. package/tsconfig.json.bak +0 -12
@@ -0,0 +1,114 @@
1
+ import * as Ref from "effect/Ref"
2
+ import * as Stream from "effect/Stream"
3
+ import * as Effect from "./Effect.ts"
4
+ import * as RequestScopedDependencies from "./RequestScopedDependencies.ts"
5
+ import * as S from "./Schema.ts"
6
+
7
+ export const DataDependency = S.Struct({
8
+ type: S.Literals(["repo", "signal"]),
9
+ name: S.String
10
+ })
11
+ export type DataDependency = S.Schema.Type<typeof DataDependency>
12
+
13
+ export const DataDependencies = S.ReadonlySet(DataDependency)
14
+ export type DataDependencies = S.Schema.Type<typeof DataDependencies>
15
+
16
+ export const empty = (): DataDependencies => new Set()
17
+
18
+ export const DataDependencySet = S.Struct({
19
+ reads: DataDependencies,
20
+ writes: DataDependencies
21
+ })
22
+ export type DataDependencySet = S.Schema.Type<typeof DataDependencySet>
23
+
24
+ export interface DataDependencyRecorderService {
25
+ readonly read: (dependency: DataDependency) => Effect.Effect<void>
26
+ readonly write: (dependency: DataDependency) => Effect.Effect<void>
27
+ readonly get: Effect.Effect<DataDependencySet>
28
+ readonly drain: Effect.Effect<DataDependencySet>
29
+ readonly drainWrites: Effect.Effect<DataDependencies>
30
+ }
31
+
32
+ const containsDependency = (dependencies: ReadonlySet<DataDependency>, dependency: DataDependency) => {
33
+ for (const _ of dependencies) {
34
+ if (_.type === dependency.type && _.name === dependency.name) return true
35
+ }
36
+ return false
37
+ }
38
+
39
+ const appendDependency = (dependency: DataDependency) => (dependencies: DataDependencies): DataDependencies =>
40
+ containsDependency(dependencies, dependency) ? dependencies : new Set([...dependencies, dependency])
41
+
42
+ export const DataDependencyRecorder = RequestScopedDependencies.make(
43
+ "effect-app/DataDependencyRecorder",
44
+ Effect.gen(function*() {
45
+ const readsRef = yield* Ref.make(empty())
46
+ const writesRef = yield* Ref.make(empty())
47
+ return makeDataDependencyRecorder(readsRef, writesRef)
48
+ })
49
+ )
50
+ export type DataDependencyRecorder = typeof DataDependencyRecorder
51
+
52
+ export type DataDependencyRecorderNotStartedError = RequestScopedDependencies.RequestScopedDependencyNotStartedError
53
+
54
+ export const getDataDependencyRecorder = DataDependencyRecorder.current
55
+
56
+ /**
57
+ * Guarantee a recorder is in scope for `self`, providing a fresh one per request when none is
58
+ * (e.g. a top-level client call with no parent query/command tracking its dependencies). An
59
+ * existing recorder is inherited, so nested calls forward into their parent rather than shadow it.
60
+ */
61
+ export const ensureDataDependencyRecorder = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
62
+ Effect.flatMap(
63
+ DataDependencyRecorder,
64
+ (current) => current === "root" ? Effect.provide(self, DataDependencyRecorder.layer) : self
65
+ )
66
+
67
+ /** Stream variant of {@link ensureDataDependencyRecorder}. */
68
+ export const ensureDataDependencyRecorderStream = <A, E, R>(self: Stream.Stream<A, E, R>): Stream.Stream<A, E, R> =>
69
+ Stream.unwrap(
70
+ Effect.map(
71
+ DataDependencyRecorder,
72
+ (current) => current === "root" ? Stream.provide(self, DataDependencyRecorder.layer) : self
73
+ )
74
+ )
75
+
76
+ export const makeDataDependencyRecorder = (
77
+ readsRef: Ref.Ref<DataDependencies>,
78
+ writesRef: Ref.Ref<DataDependencies>
79
+ ): DataDependencyRecorderService => ({
80
+ read: (dependency) => Ref.update(readsRef, appendDependency(dependency)),
81
+ write: (dependency) => Ref.update(writesRef, appendDependency(dependency)),
82
+ get: Effect.all({
83
+ reads: Ref.get(readsRef),
84
+ writes: Ref.get(writesRef)
85
+ }),
86
+ drain: Effect.all({
87
+ reads: Ref.getAndSet(readsRef, empty()),
88
+ writes: Ref.getAndSet(writesRef, empty())
89
+ }),
90
+ drainWrites: Ref.getAndSet(writesRef, empty())
91
+ })
92
+
93
+ export const repo = (name: string): DataDependency => ({ type: "repo", name })
94
+ export const signal = (name: string): DataDependency => ({ type: "signal", name })
95
+
96
+ export const QueryReadDependenciesMetaKey = "effect-app.query.readDependencies"
97
+
98
+ export const read = (dependency: DataDependency) =>
99
+ getDataDependencyRecorder.pipe(Effect.flatMap((_) => _.read(dependency)))
100
+
101
+ export const write = (dependency: DataDependency) =>
102
+ getDataDependencyRecorder.pipe(Effect.flatMap((_) => _.write(dependency)))
103
+
104
+ export const intersects = (
105
+ a: ReadonlySet<DataDependency>,
106
+ b: ReadonlySet<DataDependency>
107
+ ) => {
108
+ for (const dependency of a) {
109
+ if (containsDependency(b, dependency)) return true
110
+ }
111
+ return false
112
+ }
113
+
114
+ export const isNonEmpty = (dependencies: DataDependencies) => dependencies.size > 0
package/src/Effect.ts CHANGED
@@ -2,13 +2,15 @@
2
2
  /* eslint-disable prefer-destructuring */
3
3
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
4
 
5
- import { Effect, Option, Ref, type ServiceMap } from "effect"
6
5
  import * as Def from "effect/Deferred"
7
- import * as Fiber from "effect/Fiber"
6
+ import * as Effect from "effect/Effect"
7
+ import * as Option from "effect/Option"
8
+ import * as Ref from "effect/Ref"
8
9
  import type { Scope } from "effect/Scope"
9
10
  import type { Semaphore } from "effect/Semaphore"
10
- import { curry } from "./Function.js"
11
- import { typedKeysOf } from "./utils.js"
11
+ import type * as Context from "./Context.ts"
12
+ import { curry } from "./Function.ts"
13
+ import { typedKeysOf } from "./utils.ts"
12
14
 
13
15
  export * from "effect/Effect"
14
16
  // v4: Effect interface not re-exported by `export *` due to local binding collision
@@ -111,15 +113,11 @@ export function modifyWithPermitWithEffect<A>(ref: Ref.Ref<A>, semaphore: Semaph
111
113
  )
112
114
  }
113
115
 
114
- export function joinAll<E, A>(fibers: Iterable<Fiber.Fiber<A, E>>): Effect.Effect<readonly A[], E> {
115
- return Fiber.joinAll(fibers) as any
116
- }
117
-
118
116
  type ServiceA<T> = T extends Effect.Effect<infer S, any, any> ? S
119
- : T extends ServiceMap.Service<any, infer S> ? S
117
+ : T extends Context.Service<any, infer S> ? S
120
118
  : never
121
119
  type ServiceR<T> = T extends Effect.Effect<any, any, infer R> ? R
122
- : T extends ServiceMap.Service<infer I, any> ? I
120
+ : T extends Context.Service<infer I, any> ? I
123
121
  : never
124
122
  type ServiceE<T> = T extends Effect.Effect<any, infer E, any> ? E : never
125
123
  // type Values<T> = T extends { [s: string]: infer S } ? ServiceA<S> : never
@@ -140,29 +138,29 @@ type ValuesE<T> = T extends { [s: string]: infer S } ? ServiceE<S> : never
140
138
  * const b = a({ str: "" }) // valid, but shouldn't be!
141
139
  * ```
142
140
  */
141
+ // eslint-disable-next-line import/namespace
143
142
  export interface EffectUnunified<R, E, A> extends Effect.Effect<R, E, A> {}
144
143
 
145
144
  export type LowerFirst<S extends PropertyKey> = S extends `${infer First}${infer Rest}` ? `${Lowercase<First>}${Rest}`
146
145
  : S
147
- export type LowerServices<T extends Record<string, ServiceMap.Service<any, any> | Effect.Effect<any, any, any>>> = {
146
+ export type LowerServices<T extends Record<string, Context.Service<any, any> | Effect.Effect<any, any, any>>> = {
148
147
  [key in keyof T as LowerFirst<key>]: ServiceA<T[key]>
149
148
  }
150
149
 
151
- export function allLower<T extends Record<string, ServiceMap.Service<any, any> | Effect.Effect<any, any, any>>>(
150
+ export function allLower<T extends Record<string, Context.Service<any, any> | Effect.Effect<any, any, any>>>(
152
151
  services: T
153
152
  ) {
154
153
  return Effect.all(
155
154
  typedKeysOf(services).reduce((prev, cur) => {
156
155
  const svc = services[cur]!
157
- prev[((cur as string)[0]!.toLowerCase() + (cur as string).slice(1)) as unknown as LowerFirst<typeof cur>] =
158
- "asEffect" in svc ? svc.asEffect() : svc
156
+ prev[((cur as string)[0]!.toLowerCase() + (cur as string).slice(1)) as unknown as LowerFirst<typeof cur>] = svc
159
157
  return prev
160
158
  }, {} as any),
161
159
  { concurrency: "inherit" }
162
160
  ) as any as Effect.Effect<LowerServices<T>, ValuesE<T>, ValuesR<T>>
163
161
  }
164
162
 
165
- export function allLowerWith<T extends Record<string, ServiceMap.Service<any, any> | Effect.Effect<any, any, any>>, A>(
163
+ export function allLowerWith<T extends Record<string, Context.Service<any, any> | Effect.Effect<any, any, any>>, A>(
166
164
  services: T,
167
165
  fn: (services: LowerServices<T>) => A
168
166
  ) {
@@ -170,7 +168,7 @@ export function allLowerWith<T extends Record<string, ServiceMap.Service<any, an
170
168
  }
171
169
 
172
170
  export function allLowerWithEffect<
173
- T extends Record<string, ServiceMap.Service<any, any> | Effect.Effect<any, any, any>>,
171
+ T extends Record<string, Context.Service<any, any> | Effect.Effect<any, any, any>>,
174
172
  R,
175
173
  E,
176
174
  A
package/src/Emailer.ts ADDED
@@ -0,0 +1,51 @@
1
+ import * as Data from "effect/Data"
2
+ import type { NonEmptyReadonlyArray } from "./Array.ts"
3
+ import * as Context from "./Context.ts"
4
+ import type * as Effect from "./Effect.ts"
5
+ import type { Email } from "./Schema.ts"
6
+
7
+ export class SendMailError extends Data.TaggedError("SendMailError")<{
8
+ readonly raw: Error
9
+ }> {}
10
+
11
+ export class Emailer extends Context.Opaque<Emailer, {
12
+ sendMail: (msg: EmailMsgOptionalFrom) => Effect.Effect<void, SendMailError>
13
+ }>()("effect-app/Emailer") {}
14
+
15
+ export type EmailData = Email | {
16
+ name?: string
17
+ email: Email
18
+ }
19
+
20
+ export interface EmailContentPart {
21
+ type: string
22
+ value: string
23
+ }
24
+
25
+ export type EmailRecipients = EmailData | NonEmptyReadonlyArray<EmailData>
26
+
27
+ export interface EmailMsgBase {
28
+ readonly to: EmailRecipients
29
+ readonly cc?: EmailRecipients
30
+ readonly bcc?: EmailRecipients
31
+ readonly from: EmailData
32
+ readonly replyTo?: EmailData
33
+ readonly subject?: string
34
+ /**
35
+ * should multiple `to` addresess be considered multiple emails?
36
+ * defaults to `true`, not to leak email addresses
37
+ */
38
+ readonly isMultiple?: boolean
39
+ }
40
+
41
+ export type EmailContent =
42
+ | { text: string }
43
+ | { html: string }
44
+ | { templateId: string }
45
+ | { content: NonEmptyReadonlyArray<EmailContentPart> }
46
+
47
+ export type EmailMsg =
48
+ & EmailMsgBase
49
+ & EmailContent
50
+
51
+ export type EmailMsgOptionalFrom = Omit<EmailMsgBase, "from"> & Partial<Pick<EmailMsg, "from">> & EmailContent
@@ -1,6 +1,6 @@
1
1
  import type { BuiltInObject } from "effect-app/utils"
2
2
 
3
- import type { Primitive } from "./Widen.type.js"
3
+ import type { Primitive } from "./Widen.type.ts"
4
4
 
5
5
  // Get rid of Date | string, and replace with Date | null
6
6
  export type Inputify<T> = Date extends T ? string extends T ? Date | null
package/src/Layer.ts CHANGED
@@ -1,7 +1,11 @@
1
- import { type Array, Effect, Layer, type Scope, type ServiceMap, type Types } from "effect"
2
- import { type Yieldable } from "effect/Effect"
1
+ import type * as Array from "effect/Array"
2
+ import * as Effect from "effect/Effect"
3
3
  import { dual } from "effect/Function"
4
- import { type EffectGenUtils } from "./utils/gen.js"
4
+ import * as Layer from "effect/Layer"
5
+ import type * as Scope from "effect/Scope"
6
+ import type * as Types from "effect/Types"
7
+ import type * as Context from "./Context.ts"
8
+ import { type EffectGenUtils } from "./utils/gen.ts"
5
9
 
6
10
  export * from "effect/Layer"
7
11
 
@@ -11,13 +15,13 @@ type MakeEff<S, E, R> = {
11
15
  readonly make: Effect.Effect<S, E, R>
12
16
  }
13
17
  type MakeGen<S, E = never, R = never> = {
14
- readonly make: () => Generator<Yieldable<any, any, E, R>, S, any>
18
+ readonly make: () => Generator<Effect.Effect<any, E, R>, S>
15
19
  }
16
20
  type MakeGenNo<S> = {
17
21
  readonly make: () => Generator<unknown, S>
18
22
  }
19
23
  type MakeErr<Opts> = Opts extends { make: () => any } ? EffectGenUtils.Error<Opts["make"]> : never
20
- type MakeContext<Opts> = Opts extends { make: () => any } ? EffectGenUtils.ServiceMap<Opts["make"]> : never
24
+ type MakeContext<Opts> = Opts extends { make: () => any } ? EffectGenUtils.Context<Opts["make"]> : never
21
25
 
22
26
  type DependenciesOpt = { dependencies?: Array.NonEmptyReadonlyArray<Layer.Any> }
23
27
  type Dependencies = { dependencies: Array.NonEmptyReadonlyArray<Layer.Any> }
@@ -41,12 +45,12 @@ type PackedOrUnpackedLayer<I, Opts> = Opts extends Dependencies ? PackedLayers<I
41
45
 
42
46
  export const make: {
43
47
  <I, S>(
44
- tag: ServiceMap.Service<I, S>
48
+ tag: Context.Service<I, S>
45
49
  ): <Opts extends Make<Types.NoInfer<S>, any, any>>(
46
50
  options: Opts
47
51
  ) => PackedOrUnpackedLayer<I, Opts>
48
52
  <I, S, Opts extends Make<Types.NoInfer<S>, any, any>>(
49
- tag: ServiceMap.Service<I, S>,
53
+ tag: Context.Service<I, S>,
50
54
  options: Opts
51
55
  ): PackedOrUnpackedLayer<I, Opts>
52
56
  } = dual(2, (tag, options) => {
@@ -0,0 +1,35 @@
1
+ import type { DatabaseError } from "../../client/errors.ts"
2
+ import * as Context from "../../Context.ts"
3
+ import * as Effect from "../../Effect.ts"
4
+
5
+ export interface RegisteredRepository {
6
+ readonly seedNamespace: (namespace: string) => Effect.Effect<void, DatabaseError>
7
+ }
8
+
9
+ const make = Effect.sync(() => {
10
+ const repos = new Map<string, RegisteredRepository>()
11
+ return {
12
+ register(modelName: string, repo: RegisteredRepository) {
13
+ repos.set(modelName, repo)
14
+ },
15
+ seedNamespace: (namespace: string) =>
16
+ Effect.suspend(() =>
17
+ Effect.forEach(
18
+ repos.values(),
19
+ (r) => r.seedNamespace(namespace),
20
+ { concurrency: "unbounded", discard: true }
21
+ )
22
+ ),
23
+ get entries(): ReadonlyMap<string, RegisteredRepository> {
24
+ return repos
25
+ }
26
+ }
27
+ })
28
+
29
+ export class RepositoryRegistry extends Context.Opaque<RepositoryRegistry, {
30
+ readonly register: (modelName: string, repo: RegisteredRepository) => void
31
+ readonly seedNamespace: (namespace: string) => Effect.Effect<void, DatabaseError>
32
+ readonly entries: ReadonlyMap<string, RegisteredRepository>
33
+ }>()("effect-app/RepositoryRegistry", { make }) {}
34
+
35
+ export const RepositoryRegistryLive = RepositoryRegistry.toLayer(RepositoryRegistry.make)