effect-app 4.0.0-beta.25 → 4.0.0-beta.251

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 +1137 -0
  2. package/dist/Array.d.ts +3 -2
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +4 -4
  5. package/dist/Chunk.d.ts +1 -1
  6. package/dist/Chunk.d.ts.map +1 -1
  7. package/dist/Config/SecretURL.d.ts +4 -2
  8. package/dist/Config/SecretURL.d.ts.map +1 -1
  9. package/dist/Config/SecretURL.js +3 -6
  10. package/dist/Config/internal/configSecretURL.d.ts +1 -1
  11. package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
  12. package/dist/Config/internal/configSecretURL.js +2 -2
  13. package/dist/Config.d.ts +7 -0
  14. package/dist/Config.d.ts.map +1 -0
  15. package/dist/Config.js +6 -0
  16. package/dist/ConfigProvider.d.ts +39 -0
  17. package/dist/ConfigProvider.d.ts.map +1 -0
  18. package/dist/ConfigProvider.js +42 -0
  19. package/dist/Context.d.ts +42 -0
  20. package/dist/Context.d.ts.map +1 -0
  21. package/dist/Context.js +67 -0
  22. package/dist/Effect.d.ts +13 -12
  23. package/dist/Effect.d.ts.map +1 -1
  24. package/dist/Effect.js +5 -8
  25. package/dist/Emailer.d.ts +51 -0
  26. package/dist/Emailer.d.ts.map +1 -0
  27. package/dist/Emailer.js +7 -0
  28. package/dist/Function.d.ts +1 -1
  29. package/dist/Function.d.ts.map +1 -1
  30. package/dist/Inputify.type.d.ts +1 -1
  31. package/dist/Layer.d.ts +11 -7
  32. package/dist/Layer.d.ts.map +1 -1
  33. package/dist/Layer.js +3 -2
  34. package/dist/Model/Repository/Registry.d.ts +21 -0
  35. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  36. package/dist/Model/Repository/Registry.js +18 -0
  37. package/dist/Model/Repository/ext.d.ts +60 -0
  38. package/dist/Model/Repository/ext.d.ts.map +1 -0
  39. package/dist/Model/Repository/ext.js +122 -0
  40. package/dist/Model/Repository/internal/internal.d.ts +62 -0
  41. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  42. package/dist/Model/Repository/internal/internal.js +397 -0
  43. package/dist/Model/Repository/legacy.d.ts +21 -0
  44. package/dist/Model/Repository/legacy.d.ts.map +1 -0
  45. package/dist/Model/Repository/legacy.js +2 -0
  46. package/dist/Model/Repository/makeRepo.d.ts +53 -0
  47. package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
  48. package/dist/Model/Repository/makeRepo.js +27 -0
  49. package/dist/Model/Repository/service.d.ts +97 -0
  50. package/dist/Model/Repository/service.d.ts.map +1 -0
  51. package/dist/Model/Repository/service.js +2 -0
  52. package/dist/Model/Repository/validation.d.ts +71 -0
  53. package/dist/Model/Repository/validation.d.ts.map +1 -0
  54. package/dist/Model/Repository/validation.js +32 -0
  55. package/dist/Model/Repository.d.ts +7 -0
  56. package/dist/Model/Repository.d.ts.map +1 -0
  57. package/dist/Model/Repository.js +7 -0
  58. package/dist/Model/dsl.d.ts +33 -0
  59. package/dist/Model/dsl.d.ts.map +1 -0
  60. package/dist/Model/dsl.js +43 -0
  61. package/dist/Model/filter/filterApi.d.ts +30 -0
  62. package/dist/Model/filter/filterApi.d.ts.map +1 -0
  63. package/dist/Model/filter/filterApi.js +2 -0
  64. package/dist/Model/filter/types/errors.d.ts +29 -0
  65. package/dist/Model/filter/types/errors.d.ts.map +1 -0
  66. package/dist/Model/filter/types/errors.js +2 -0
  67. package/dist/Model/filter/types/fields.d.ts +15 -0
  68. package/dist/Model/filter/types/fields.d.ts.map +1 -0
  69. package/dist/Model/filter/types/fields.js +2 -0
  70. package/dist/Model/filter/types/path/common.d.ts +316 -0
  71. package/dist/Model/filter/types/path/common.d.ts.map +1 -0
  72. package/dist/Model/filter/types/path/common.js +2 -0
  73. package/dist/Model/filter/types/path/eager.d.ts +95 -0
  74. package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
  75. package/dist/Model/filter/types/path/eager.js +31 -0
  76. package/dist/Model/filter/types/path/index.d.ts +4 -0
  77. package/dist/Model/filter/types/path/index.d.ts.map +1 -0
  78. package/dist/Model/filter/types/path/index.js +3 -0
  79. package/dist/Model/filter/types/utils.d.ts +79 -0
  80. package/dist/Model/filter/types/utils.d.ts.map +1 -0
  81. package/dist/Model/filter/types/utils.js +2 -0
  82. package/dist/Model/filter/types/validator.d.ts +30 -0
  83. package/dist/Model/filter/types/validator.d.ts.map +1 -0
  84. package/dist/Model/filter/types/validator.js +2 -0
  85. package/dist/Model/filter/types.d.ts +5 -0
  86. package/dist/Model/filter/types.d.ts.map +1 -0
  87. package/dist/Model/filter/types.js +7 -0
  88. package/dist/Model/query/dsl.d.ts +446 -0
  89. package/dist/Model/query/dsl.d.ts.map +1 -0
  90. package/dist/Model/query/dsl.js +342 -0
  91. package/dist/Model/query/new-kid-interpreter.d.ts +136 -0
  92. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
  93. package/dist/Model/query/new-kid-interpreter.js +336 -0
  94. package/dist/Model/query.d.ts +15 -0
  95. package/dist/Model/query.d.ts.map +1 -0
  96. package/dist/Model/query.js +3 -0
  97. package/dist/Model.d.ts +5 -0
  98. package/dist/Model.d.ts.map +1 -0
  99. package/dist/Model.js +5 -0
  100. package/dist/NonEmptySet.d.ts +4 -2
  101. package/dist/NonEmptySet.d.ts.map +1 -1
  102. package/dist/NonEmptySet.js +2 -2
  103. package/dist/Option.d.ts +2 -1
  104. package/dist/Option.d.ts.map +1 -1
  105. package/dist/Option.js +3 -1
  106. package/dist/Pure.d.ts +8 -6
  107. package/dist/Pure.d.ts.map +1 -1
  108. package/dist/Pure.js +17 -14
  109. package/dist/QueueMaker.d.ts +13 -0
  110. package/dist/QueueMaker.d.ts.map +1 -0
  111. package/dist/QueueMaker.js +4 -0
  112. package/dist/RequestContext.d.ts +103 -0
  113. package/dist/RequestContext.d.ts.map +1 -0
  114. package/dist/RequestContext.js +49 -0
  115. package/dist/Schema/Class.d.ts +66 -20
  116. package/dist/Schema/Class.d.ts.map +1 -1
  117. package/dist/Schema/Class.js +192 -23
  118. package/dist/Schema/FastCheck.d.ts +1 -1
  119. package/dist/Schema/FastCheck.d.ts.map +1 -1
  120. package/dist/Schema/Methods.d.ts +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 +5 -3
  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 +1 -1
  134. package/dist/Schema/email.d.ts.map +1 -1
  135. package/dist/Schema/email.js +7 -4
  136. package/dist/Schema/ext.d.ts +339 -56
  137. package/dist/Schema/ext.d.ts.map +1 -1
  138. package/dist/Schema/ext.js +358 -53
  139. package/dist/Schema/moreStrings.d.ts +108 -26
  140. package/dist/Schema/moreStrings.d.ts.map +1 -1
  141. package/dist/Schema/moreStrings.js +45 -16
  142. package/dist/Schema/numbers.d.ts +55 -15
  143. package/dist/Schema/numbers.d.ts.map +1 -1
  144. package/dist/Schema/numbers.js +60 -12
  145. package/dist/Schema/phoneNumber.d.ts +1 -1
  146. package/dist/Schema/phoneNumber.d.ts.map +1 -1
  147. package/dist/Schema/phoneNumber.js +6 -3
  148. package/dist/Schema/schema.d.ts +1 -1
  149. package/dist/Schema/strings.d.ts +5 -5
  150. package/dist/Schema/strings.d.ts.map +1 -1
  151. package/dist/Schema/strings.js +1 -5
  152. package/dist/Schema.d.ts +214 -8
  153. package/dist/Schema.d.ts.map +1 -1
  154. package/dist/Schema.js +190 -11
  155. package/dist/Set.d.ts +5 -2
  156. package/dist/Set.d.ts.map +1 -1
  157. package/dist/Set.js +3 -2
  158. package/dist/Store.d.ts +170 -0
  159. package/dist/Store.d.ts.map +1 -0
  160. package/dist/Store.js +121 -0
  161. package/dist/TypeTest.d.ts +1 -1
  162. package/dist/Types.d.ts +1 -1
  163. package/dist/Widen.type.d.ts +1 -1
  164. package/dist/_ext/Array.d.ts +2 -2
  165. package/dist/_ext/Array.d.ts.map +1 -1
  166. package/dist/_ext/Array.js +4 -2
  167. package/dist/_ext/date.d.ts +1 -1
  168. package/dist/_ext/misc.d.ts +5 -2
  169. package/dist/_ext/misc.d.ts.map +1 -1
  170. package/dist/_ext/misc.js +4 -2
  171. package/dist/_ext/ord.ext.d.ts +3 -2
  172. package/dist/_ext/ord.ext.d.ts.map +1 -1
  173. package/dist/_ext/ord.ext.js +2 -2
  174. package/dist/builtin.d.ts +1 -1
  175. package/dist/builtin.d.ts.map +1 -1
  176. package/dist/client/InvalidationKeys.d.ts +29 -0
  177. package/dist/client/InvalidationKeys.d.ts.map +1 -0
  178. package/dist/client/InvalidationKeys.js +33 -0
  179. package/dist/client/apiClientFactory.d.ts +20 -32
  180. package/dist/client/apiClientFactory.d.ts.map +1 -1
  181. package/dist/client/apiClientFactory.js +104 -34
  182. package/dist/client/clientFor.d.ts +53 -19
  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 +49 -25
  186. package/dist/client/errors.d.ts.map +1 -1
  187. package/dist/client/errors.js +43 -17
  188. package/dist/client/makeClient.d.ts +495 -33
  189. package/dist/client/makeClient.d.ts.map +1 -1
  190. package/dist/client/makeClient.js +66 -24
  191. package/dist/client.d.ts +6 -5
  192. package/dist/client.d.ts.map +1 -1
  193. package/dist/client.js +2 -1
  194. package/dist/faker.d.ts +1 -1
  195. package/dist/faker.d.ts.map +1 -1
  196. package/dist/http/Request.d.ts +2 -2
  197. package/dist/http/Request.d.ts.map +1 -1
  198. package/dist/http/Request.js +2 -2
  199. package/dist/http/internal/lib.d.ts +1 -1
  200. package/dist/http.d.ts +1 -1
  201. package/dist/ids.d.ts +40 -12
  202. package/dist/ids.d.ts.map +1 -1
  203. package/dist/ids.js +25 -3
  204. package/dist/index.d.ts +7 -8
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +8 -8
  207. package/dist/logger.d.ts +1 -1
  208. package/dist/middleware.d.ts +14 -8
  209. package/dist/middleware.d.ts.map +1 -1
  210. package/dist/middleware.js +14 -8
  211. package/dist/rpc/Invalidation.d.ts +420 -0
  212. package/dist/rpc/Invalidation.d.ts.map +1 -0
  213. package/dist/rpc/Invalidation.js +168 -0
  214. package/dist/rpc/MiddlewareMaker.d.ts +12 -8
  215. package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
  216. package/dist/rpc/MiddlewareMaker.js +59 -38
  217. package/dist/rpc/RpcContextMap.d.ts +4 -4
  218. package/dist/rpc/RpcContextMap.d.ts.map +1 -1
  219. package/dist/rpc/RpcContextMap.js +4 -4
  220. package/dist/rpc/RpcMiddleware.d.ts +15 -11
  221. package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
  222. package/dist/rpc/RpcMiddleware.js +1 -1
  223. package/dist/rpc.d.ts +2 -2
  224. package/dist/rpc.d.ts.map +1 -1
  225. package/dist/rpc.js +2 -2
  226. package/dist/runtime.d.ts +19 -0
  227. package/dist/runtime.d.ts.map +1 -0
  228. package/dist/runtime.js +40 -0
  229. package/dist/setupRequest.d.ts +19 -0
  230. package/dist/setupRequest.d.ts.map +1 -0
  231. package/dist/setupRequest.js +69 -0
  232. package/dist/toast.d.ts +51 -0
  233. package/dist/toast.d.ts.map +1 -0
  234. package/dist/toast.js +34 -0
  235. package/dist/transform.d.ts +2 -2
  236. package/dist/transform.d.ts.map +1 -1
  237. package/dist/transform.js +4 -5
  238. package/dist/utils/effectify.d.ts +2 -2
  239. package/dist/utils/effectify.d.ts.map +1 -1
  240. package/dist/utils/effectify.js +2 -2
  241. package/dist/utils/extend.d.ts +1 -1
  242. package/dist/utils/extend.d.ts.map +1 -1
  243. package/dist/utils/gen.d.ts +5 -5
  244. package/dist/utils/gen.d.ts.map +1 -1
  245. package/dist/utils/logLevel.d.ts +3 -3
  246. package/dist/utils/logLevel.d.ts.map +1 -1
  247. package/dist/utils/logger.d.ts +5 -4
  248. package/dist/utils/logger.d.ts.map +1 -1
  249. package/dist/utils/logger.js +4 -4
  250. package/dist/utils.d.ts +40 -45
  251. package/dist/utils.d.ts.map +1 -1
  252. package/dist/utils.js +19 -27
  253. package/dist/validation/validators.d.ts +1 -1
  254. package/dist/validation/validators.d.ts.map +1 -1
  255. package/dist/validation.d.ts +1 -1
  256. package/dist/validation.d.ts.map +1 -1
  257. package/dist/withToast.d.ts +30 -0
  258. package/dist/withToast.d.ts.map +1 -0
  259. package/dist/withToast.js +64 -0
  260. package/package.json +162 -24
  261. package/src/Array.ts +3 -3
  262. package/src/Config/SecretURL.ts +5 -2
  263. package/src/Config/internal/configSecretURL.ts +1 -1
  264. package/src/Config.ts +14 -0
  265. package/src/ConfigProvider.ts +48 -0
  266. package/src/{ServiceMap.ts → Context.ts} +56 -63
  267. package/src/Effect.ts +12 -14
  268. package/src/Emailer.ts +51 -0
  269. package/src/Layer.ts +10 -6
  270. package/src/Model/Repository/Registry.ts +34 -0
  271. package/src/Model/Repository/ext.ts +375 -0
  272. package/src/Model/Repository/internal/internal.ts +691 -0
  273. package/src/Model/Repository/legacy.ts +29 -0
  274. package/src/Model/Repository/makeRepo.ts +144 -0
  275. package/src/Model/Repository/service.ts +639 -0
  276. package/src/Model/Repository/validation.ts +31 -0
  277. package/src/Model/Repository.ts +6 -0
  278. package/src/Model/dsl.ts +129 -0
  279. package/src/Model/filter/filterApi.ts +60 -0
  280. package/src/Model/filter/types/errors.ts +47 -0
  281. package/src/Model/filter/types/fields.ts +50 -0
  282. package/src/Model/filter/types/path/common.ts +404 -0
  283. package/src/Model/filter/types/path/eager.ts +297 -0
  284. package/src/Model/filter/types/path/index.ts +4 -0
  285. package/src/Model/filter/types/utils.ts +128 -0
  286. package/src/Model/filter/types/validator.ts +46 -0
  287. package/src/Model/filter/types.ts +6 -0
  288. package/src/Model/query/dsl.ts +2546 -0
  289. package/src/Model/query/new-kid-interpreter.ts +484 -0
  290. package/src/Model/query.ts +13 -0
  291. package/src/Model.ts +4 -0
  292. package/src/NonEmptySet.ts +3 -1
  293. package/src/Option.ts +2 -0
  294. package/src/Pure.ts +21 -19
  295. package/src/QueueMaker.ts +19 -0
  296. package/src/RequestContext.ts +62 -0
  297. package/src/Schema/Class.ts +274 -64
  298. package/src/Schema/SchemaParser.ts +12 -0
  299. package/src/Schema/SpecialJsonSchema.ts +139 -0
  300. package/src/Schema/SpecialOpenApi.ts +130 -0
  301. package/src/Schema/brand.ts +22 -2
  302. package/src/Schema/email.ts +7 -2
  303. package/src/Schema/ext.ts +443 -88
  304. package/src/Schema/moreStrings.ts +93 -37
  305. package/src/Schema/numbers.ts +64 -16
  306. package/src/Schema/phoneNumber.ts +5 -1
  307. package/src/Schema/strings.ts +4 -8
  308. package/src/Schema.ts +374 -10
  309. package/src/Set.ts +5 -1
  310. package/src/Store.ts +277 -0
  311. package/src/_ext/Array.ts +3 -1
  312. package/src/_ext/misc.ts +4 -1
  313. package/src/_ext/ord.ext.ts +2 -1
  314. package/src/client/InvalidationKeys.ts +50 -0
  315. package/src/client/apiClientFactory.ts +230 -131
  316. package/src/client/clientFor.ts +102 -31
  317. package/src/client/errors.ts +52 -26
  318. package/src/client/makeClient.ts +592 -71
  319. package/src/client.ts +5 -4
  320. package/src/http/Request.ts +1 -1
  321. package/src/ids.ts +25 -3
  322. package/src/index.ts +7 -10
  323. package/src/middleware.ts +13 -9
  324. package/src/rpc/Invalidation.ts +261 -0
  325. package/src/rpc/MiddlewareMaker.ts +83 -75
  326. package/src/rpc/README.md +2 -2
  327. package/src/rpc/RpcContextMap.ts +6 -5
  328. package/src/rpc/RpcMiddleware.ts +18 -12
  329. package/src/rpc.ts +1 -1
  330. package/src/runtime.ts +56 -0
  331. package/src/setupRequest.ts +134 -0
  332. package/src/toast.ts +54 -0
  333. package/src/transform.ts +3 -3
  334. package/src/utils/effectify.ts +1 -1
  335. package/src/utils/gen.ts +8 -8
  336. package/src/utils/logLevel.ts +1 -1
  337. package/src/utils/logger.ts +4 -3
  338. package/src/utils.ts +62 -139
  339. package/src/withToast.ts +133 -0
  340. package/test/dist/rpc-dynamic-middleware.test.d.ts.map +1 -0
  341. package/test/dist/rpc.test.d.ts.map +1 -1
  342. package/test/dist/secretURL.test.d.ts.map +1 -0
  343. package/test/dist/special.test.d.ts.map +1 -0
  344. package/test/dist/stream-error.types.d.ts +2 -0
  345. package/test/dist/stream-error.types.d.ts.map +1 -0
  346. package/test/dist/stream-error.types.js +27 -0
  347. package/test/moreStrings.test.ts +1 -1
  348. package/test/rpc.test.ts +46 -6
  349. package/test/schema.test.ts +459 -30
  350. package/test/secretURL.test.ts +160 -0
  351. package/test/special.test.ts +1026 -0
  352. package/test/utils.test.ts +7 -7
  353. package/tsconfig.base.json +6 -5
  354. package/tsconfig.json +2 -1
  355. package/tsconfig.json.bak +2 -2
  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 +0 -44
  362. package/dist/ServiceMap.d.ts.map +0 -1
  363. package/dist/ServiceMap.js +0 -91
  364. package/eslint.config.mjs +0 -26
  365. package/src/Operations.ts +0 -55
@@ -0,0 +1,691 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import * as Equivalence from "effect/Equivalence"
4
+ import { flow, pipe } from "effect/Function"
5
+ import * as Pipeable from "effect/Pipeable"
6
+ import * as PubSub from "effect/PubSub"
7
+ import * as Result from "effect/Result"
8
+ import * as SchemaAST from "effect/SchemaAST"
9
+ import * as Unify from "effect/Unify"
10
+ import * as Array from "../../../Array.js"
11
+ import type { NonEmptyReadonlyArray } from "../../../Array.js"
12
+ import { toNonEmptyArray } from "../../../Array.js"
13
+ import * as Chunk from "../../../Chunk.js"
14
+ import { NotFoundError } from "../../../client/errors.js"
15
+ import * as Context from "../../../Context.js"
16
+ import * as Effect from "../../../Effect.js"
17
+ import { flatMapOption } from "../../../Effect.js"
18
+ import * as Option from "../../../Option.js"
19
+ import * as S from "../../../Schema.js"
20
+ import { type Codec, NonNegativeInt } from "../../../Schema.js"
21
+ import { setupRequestContextFromCurrent } from "../../../setupRequest.ts"
22
+ import { type FilterArgs, getContextMap, type PersistenceModelType, type StoreConfig, StoreMaker } from "../../../Store.js"
23
+ import type { FieldValues } from "../../filter/types.js"
24
+ import * as Q from "../../query.js"
25
+ import type { Repository } from "../service.js"
26
+ import { ValidationError, ValidationResult } from "../validation.js"
27
+
28
+ const dedupe = Array.dedupeWith(Equivalence.String)
29
+
30
+ /**
31
+ * A base implementation to create a repository.
32
+ */
33
+ export function makeRepoInternal<
34
+ Evt = never
35
+ >() {
36
+ return <
37
+ ItemType extends string,
38
+ R,
39
+ Encoded extends FieldValues,
40
+ T,
41
+ IdKey extends keyof T & keyof Encoded
42
+ >(
43
+ name: ItemType,
44
+ schema: S.Codec<T, Encoded, R>,
45
+ mapFrom: (pm: Encoded) => Encoded,
46
+ mapTo: (e: Encoded, etag: string | undefined) => PersistenceModelType<Encoded>,
47
+ idKey: IdKey
48
+ ) => {
49
+ type PM = PersistenceModelType<Encoded>
50
+ function mapToPersistenceModel(
51
+ e: Encoded,
52
+ getEtag: (id: string) => string | undefined
53
+ ): PM {
54
+ return mapTo(e, getEtag(e[idKey]))
55
+ }
56
+
57
+ function mapReverse(
58
+ { _etag, ...e }: PM,
59
+ setEtag: (id: string, eTag: string | undefined) => void
60
+ ): Encoded {
61
+ setEtag((e as any)[idKey], _etag)
62
+ return mapFrom(e as unknown as Encoded)
63
+ }
64
+
65
+ const mkStore = makeStore<Encoded>()(name, schema, mapTo, idKey)
66
+
67
+ function make<RInitial = never, E = never, RPublish = never, RCtx = never>(
68
+ args: [Evt] extends [never] ? {
69
+ schemaContext?: Context.Context<RCtx>
70
+ makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
71
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
72
+ partitionValue?: (e?: Encoded) => string
73
+ }
74
+ }
75
+ : {
76
+ schemaContext?: Context.Context<RCtx>
77
+ publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect.Effect<void, never, RPublish>
78
+ makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
79
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
80
+ partitionValue?: (e?: Encoded) => string
81
+ }
82
+ }
83
+ ) {
84
+ return Effect
85
+ .gen(function*() {
86
+ const rctx: Context.Context<RCtx> = args.schemaContext ?? Context.empty() as any
87
+ const provideRctx = Effect.provide(rctx)
88
+ const encodeMany = flow(
89
+ S.encodeEffect(S.Array(schema)),
90
+ provideRctx,
91
+ Effect.withSpan("encodeMany", { attributes: { "app.entity": name } }, { captureStackTrace: false })
92
+ )
93
+ const decode = flow(S.decodeEffectConcurrently(schema), provideRctx)
94
+ const decodeMany = flow(
95
+ S.decodeEffectConcurrently(S.Array(schema)),
96
+ provideRctx
97
+ )
98
+
99
+ const store = yield* mkStore(args.makeInitial, args.config)
100
+ const cms = Effect.map(getContextMap.pipe(Effect.orDie), (_) => ({
101
+ get: (id: string) => _.get(`${name}.${id}`),
102
+ set: (id: string, etag: string | undefined) => _.set(`${name}.${id}`, etag)
103
+ }))
104
+
105
+ const pub = "publishEvents" in args
106
+ ? args.publishEvents
107
+ : () => Effect.void
108
+ const changeFeed = yield* PubSub.unbounded<[T[], "save" | "remove"]>()
109
+
110
+ const allE = cms
111
+ .pipe(Effect.flatMap((cm) => Effect.map(store.all, (_) => _.map((_) => mapReverse(_, cm.set)))))
112
+
113
+ const all = Effect
114
+ .flatMap(
115
+ allE,
116
+ (_) => decodeMany(_).pipe(Effect.orDie)
117
+ )
118
+ .pipe(
119
+ Effect.map((_) => _ as T[]),
120
+ Effect.withSpan("Repository.all", {
121
+ kind: "client",
122
+ attributes: { "app.entity": name }
123
+ }, { captureStackTrace: false })
124
+ )
125
+
126
+ const fieldsSchema = schema as unknown as { fields: any }
127
+ // assumes the id field never needs a service...
128
+ const i = ("fields" in fieldsSchema ? S.Struct(fieldsSchema["fields"]) as unknown as typeof schema : schema)
129
+ .pipe((_) => {
130
+ let ast = _.ast
131
+ if (ast._tag === "Declaration") ast = ast.typeParameters[0]!
132
+
133
+ const pickIdFromAst = (a: SchemaAST.AST) => {
134
+ // Unwrap Declaration (e.g. TaggedClass) to get the underlying Objects AST
135
+ let inner = a
136
+ if (inner._tag === "Declaration") inner = inner.typeParameters[0]!
137
+ // Pick from the original AST to preserve the full encoding chain (e.g. decodeTo transformations).
138
+ // Using toEncoded would lose transformation info needed to encode Type -> Encoded.
139
+ if (SchemaAST.isObjects(inner)) {
140
+ const field = inner.propertySignatures.find((_) => _.name === idKey)
141
+ if (field) {
142
+ return S.Struct({ [idKey]: S.make(field.type) }) as unknown as Codec<T, Encoded>
143
+ }
144
+ }
145
+ return S.make(a) as unknown as Codec<T, Encoded>
146
+ }
147
+
148
+ return ast._tag === "Union"
149
+ // we need to get the Objects (TypeLiteral), in case of class it has encoding chain...
150
+ ? S.Union(
151
+ ast.types.map((_) => pickIdFromAst(_))
152
+ )
153
+ : pickIdFromAst(ast)
154
+ })
155
+ const encodeId = flow(S.encodeEffect(i), provideRctx)
156
+ const encodeIdOnly = (id: string) =>
157
+ encodeId({ [idKey]: id } as any).pipe(
158
+ Effect.map((_: Record<string, unknown>) => _[idKey as string] as Encoded[IdKey])
159
+ )
160
+ const findEId = Effect.fnUntraced(function*(id: Encoded[IdKey]) {
161
+ yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
162
+
163
+ return yield* Effect.flatMap(
164
+ store.find(id),
165
+ (item) =>
166
+ Effect.gen(function*() {
167
+ const { set } = yield* cms
168
+ return item.pipe(Option.map((_) => mapReverse(_, set)))
169
+ })
170
+ )
171
+ })
172
+ // TODO: select the particular field, instead of as struct
173
+ const findE = Effect.fnUntraced(function*(id: T[IdKey]) {
174
+ yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
175
+
176
+ return yield* pipe(
177
+ encodeId({ [idKey]: id } as any),
178
+ Effect.orDie,
179
+ Effect.map((_) => (_ as any)[idKey]),
180
+ Effect.flatMap(findEId)
181
+ )
182
+ })
183
+
184
+ const find = Effect.fn("Repository.find", {
185
+ kind: "client",
186
+ attributes: { "app.entity": name }
187
+ })(function*(id: T[IdKey]) {
188
+ yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
189
+ return yield* flatMapOption(findE(id), (_) => Effect.orDie(decode(_)))
190
+ })
191
+
192
+ const saveAllE = (a: Iterable<Encoded>) =>
193
+ flatMapOption(
194
+ Effect
195
+ .sync(() => toNonEmptyArray([...a])),
196
+ (a) =>
197
+ Effect.gen(function*() {
198
+ const { get, set } = yield* cms
199
+ const items = a.map((_) => mapToPersistenceModel(_, get))
200
+ const ret = yield* store.batchSet(items)
201
+ ret.forEach((_) => set(_[idKey], _._etag))
202
+ })
203
+ )
204
+ .pipe(Effect.asVoid)
205
+
206
+ const saveAll = (a: Iterable<T>) =>
207
+ encodeMany(Array.fromIterable(a))
208
+ .pipe(
209
+ Effect.orDie,
210
+ Effect.andThen(saveAllE)
211
+ )
212
+
213
+ const saveAndPublish = Effect.fn("Repository.saveAndPublish", { attributes: { "app.entity": name } })(
214
+ function*(items: Iterable<T>, events: Iterable<Evt> = []) {
215
+ const it = Chunk.fromIterable(items)
216
+ const evts = [...events]
217
+ yield* Effect.annotateCurrentSpan({
218
+ "app.entity.ids": Chunk.map(it, (_) => _[idKey]),
219
+ "app.event.count": evts.length
220
+ })
221
+ return yield* saveAll(it)
222
+ .pipe(
223
+ Effect.andThen(Effect.sync(() => toNonEmptyArray(evts))),
224
+ // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
225
+ (_) => flatMapOption(_, pub),
226
+ Effect.andThen(PubSub.publish(changeFeed, [Chunk.toArray(it), "save"] as [T[], "save" | "remove"])),
227
+ Effect.asVoid
228
+ )
229
+ }
230
+ )
231
+
232
+ const removeAndPublish = Effect.fn("Repository.removeAndPublish", { attributes: { "app.entity": name } })(
233
+ function*(a: Iterable<T>, events: Iterable<Evt> = []) {
234
+ const { set } = yield* cms
235
+ const it = [...a]
236
+ const evts = [...events]
237
+ yield* Effect.annotateCurrentSpan({
238
+ "app.entity.ids": it.map((_) => _[idKey]),
239
+ "app.event.count": evts.length
240
+ })
241
+ const items = yield* encodeMany(it).pipe(Effect.orDie)
242
+ if (Array.isReadonlyArrayNonEmpty(items)) {
243
+ yield* store.batchRemove(
244
+ items.map((_) => (_[idKey])),
245
+ args.config?.partitionValue?.(items[0])
246
+ )
247
+ for (const e of items) {
248
+ set(e[idKey], undefined)
249
+ }
250
+ yield* Effect
251
+ .sync(() => toNonEmptyArray(evts))
252
+ // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
253
+ .pipe((_) => flatMapOption(_, pub))
254
+
255
+ yield* PubSub.publish(changeFeed, [it, "remove"] as [T[], "save" | "remove"])
256
+ }
257
+ }
258
+ )
259
+
260
+ const removeById = Effect.fn("Repository.removeById", { attributes: { "app.entity": name } })(
261
+ function*(idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>) {
262
+ const ids = globalThis.Array.isArray(idOrIds)
263
+ ? idOrIds as readonly T[IdKey][]
264
+ : [idOrIds as T[IdKey]]
265
+ if (!Array.isReadonlyArrayNonEmpty(ids)) {
266
+ return
267
+ }
268
+ const { set } = yield* cms
269
+ const eids = yield* Effect.forEach(ids, (_) => encodeIdOnly(_ as any)).pipe(Effect.orDie)
270
+ yield* Effect.annotateCurrentSpan({ "app.entity.ids": eids })
271
+ yield* store.batchRemove(eids)
272
+ for (const id of eids) {
273
+ set(id, undefined)
274
+ }
275
+ yield* PubSub.publish(changeFeed, [[], "remove"] as [T[], "save" | "remove"])
276
+ }
277
+ )
278
+
279
+ const parseMany = Effect.fn("parseMany", {
280
+ attributes: { "app.entity": name, "app.query.mode": "transform" }
281
+ })(
282
+ function*(items: readonly PM[]) {
283
+ const cm = yield* cms
284
+ return yield* decodeMany(items.map((_) => mapReverse(_, cm.set))).pipe(Effect.orDie)
285
+ }
286
+ )
287
+ const decodeManyCache = new WeakMap<
288
+ S.Codec<any, any, any>,
289
+ (i: readonly any[]) => Effect.Effect<any, any, any>
290
+ >()
291
+ const getDecodeMany = (s: S.Codec<any, Encoded, any>) => {
292
+ let dec = decodeManyCache.get(s)
293
+ if (!dec) {
294
+ dec = S.decodeEffectConcurrently(S.Array(s))
295
+ decodeManyCache.set(s, dec)
296
+ }
297
+ return dec
298
+ }
299
+ const parseMany2 = Effect.fn("parseMany", {
300
+ attributes: { "app.entity": name, "app.query.mode": "transform" }
301
+ })(
302
+ function*<A, R>(items: readonly PM[], schema: S.Codec<A, Encoded, R>) {
303
+ const cm = yield* cms
304
+ return yield* getDecodeMany(schema)(items.map((_) => mapReverse(_, cm.set))).pipe(Effect.orDie)
305
+ }
306
+ )
307
+ const filter = <U extends keyof Encoded = keyof Encoded>(args: FilterArgs<Encoded, U>) =>
308
+ store
309
+ .filter(
310
+ // always enforce id and _etag because they are system fields, required for etag tracking etc
311
+ {
312
+ ...args,
313
+ select: args.select
314
+ ? dedupe([...args.select, idKey, "_etag" as any])
315
+ : undefined
316
+ } as typeof args
317
+ )
318
+ .pipe(
319
+ Effect.tap((items) =>
320
+ Effect.map(cms, ({ set }) => items.forEach((_) => set((_ as Encoded)[idKey], (_ as PM)._etag)))
321
+ )
322
+ )
323
+
324
+ // TODO: For raw we should use S.from, and drop the R...
325
+ const query: {
326
+ <A, R, From extends FieldValues>(
327
+ q: Q.QueryProjection<Encoded extends From ? From : never, A, R>
328
+ ): Effect.Effect<readonly A[], S.SchemaError, Exclude<R, RCtx>>
329
+ <A, R, EncodedRefined extends Encoded = Encoded>(
330
+ q: Q.QAll<NoInfer<Encoded>, NoInfer<EncodedRefined>, A, R>
331
+ ): Effect.Effect<readonly A[], never, Exclude<R, RCtx>>
332
+ } = (<A, R, EncodedRefined extends Encoded = Encoded>(q: Q.QAll<Encoded, EncodedRefined, A, R>) => {
333
+ const a = Q.toFilter(q, schema)
334
+ // Mode dispatch — see `Q.project` JSDoc for the contract:
335
+ // aggregate: GROUP BY + aggregate functions at DB level; decode raw rows with schema; SchemaError surfaces.
336
+ // project : decode raw encoded rows with schema; no PM reverse-mapping; SchemaError surfaces.
337
+ // collect : same as project, but schema yields Option and None rows are dropped.
338
+ // transform: PM reverse-map (re-inject _etag/PM state from cms cache) then decode; orDie.
339
+ const eff = a.mode === "aggregate"
340
+ ? store
341
+ // `a.select` contains `{ key, aggregate }` items not expressible in FilterFunc<Encoded, U>'s
342
+ // `U extends keyof Encoded` generic. Cast is unavoidable until FilterFunc supports aggregate mode.
343
+ .filter(a as any)
344
+ // Decode raw aggregate rows directly — no PM reverse-mapping, no id/_etag needed.
345
+ .pipe(
346
+ Effect.andThen(
347
+ flow(
348
+ S.decodeEffectConcurrently(S.Array(a.schema ?? schema)),
349
+ provideRctx,
350
+ Effect.withSpan("parseMany", {
351
+ attributes: { "app.entity": name, "app.query.mode": "aggregate" }
352
+ })
353
+ )
354
+ )
355
+ )
356
+ : a.mode === "project"
357
+ ? filter(a)
358
+ // TODO: mapFrom but need to support per field and dependencies
359
+ .pipe(
360
+ Effect.andThen(
361
+ flow(
362
+ S.decodeEffectConcurrently(S.Array(a.schema ?? schema)),
363
+ provideRctx,
364
+ Effect.withSpan("parseMany", {
365
+ attributes: { "app.entity": name, "app.query.mode": "project" }
366
+ })
367
+ )
368
+ )
369
+ )
370
+ : a.mode === "collect"
371
+ ? filter(a)
372
+ // TODO: mapFrom but need to support per field and dependencies
373
+ .pipe(
374
+ Effect.flatMap(flow(
375
+ S.decodeEffectConcurrently(S.Array(a.schema)),
376
+ Effect.map(Array.getSomes),
377
+ provideRctx,
378
+ Effect.withSpan("parseMany", {
379
+ attributes: { "app.entity": name, "app.query.mode": "collect" }
380
+ })
381
+ ))
382
+ )
383
+ : Effect.flatMap(
384
+ filter(a),
385
+ (_) =>
386
+ Unify.unify(
387
+ a.schema
388
+ // TODO: partial may not match?
389
+ ? parseMany2(_ as any, a.schema as any)
390
+ : parseMany(_ as any)
391
+ )
392
+ )
393
+ return pipe(
394
+ a.ttype === "one"
395
+ ? Effect.flatMap(
396
+ eff,
397
+ flow(
398
+ Array.head,
399
+ Option.match({
400
+ onNone: () => Effect.fail(new NotFoundError({ id: "query", /* TODO */ type: name })),
401
+ onSome: Effect.succeed
402
+ })
403
+ )
404
+ )
405
+ : a.ttype === "count"
406
+ ? Effect
407
+ .map(eff, (_) => NonNegativeInt(_.length))
408
+ .pipe(Effect.catchTag("SchemaError", (e) => Effect.die(e)))
409
+ : eff,
410
+ Effect.tap((r) =>
411
+ Effect.annotateCurrentSpan({
412
+ "app.query.ttype": a.ttype,
413
+ "app.query.mode": a.mode,
414
+ "db.response.returned_rows": Array.isArray(r) ? r.length : 1
415
+ })
416
+ ),
417
+ Effect.withSpan("Repository.query", {
418
+ kind: "client",
419
+ attributes: { "app.entity": name }
420
+ }, { captureStackTrace: false })
421
+ )
422
+ }) as any
423
+
424
+ const validateSample = Effect.fn("Repository.validateSample", { attributes: { "app.entity": name } })(
425
+ function*(options?: {
426
+ percentage?: number
427
+ maxItems?: number
428
+ }) {
429
+ const percentage = options?.percentage ?? 0.1 // default 10%
430
+ const maxItems = options?.maxItems
431
+
432
+ // 1. get all IDs with projection (bypasses main schema decode)
433
+ const allIds = yield* store
434
+ .filter({
435
+ t: null as unknown as Encoded,
436
+ select: [idKey as keyof Encoded]
437
+ })
438
+ .pipe(Effect.withSpan("Repository.filter", {
439
+ kind: "client",
440
+ attributes: { "app.entity": name }
441
+ }, { captureStackTrace: false }))
442
+
443
+ // 2. random subset
444
+ const shuffled = [...allIds].sort(() => Math.random() - 0.5)
445
+ const sampleSize = Math.min(
446
+ maxItems ?? Infinity,
447
+ Math.ceil(allIds.length * percentage)
448
+ )
449
+ const sample = shuffled.slice(0, sampleSize)
450
+
451
+ // 3. validate each item
452
+ const errors: ValidationError[] = []
453
+
454
+ for (const item of sample) {
455
+ const id = item[idKey]
456
+ const rawResult = yield* store.find(id).pipe(
457
+ Effect.withSpan("Repository.find", {
458
+ kind: "client",
459
+ attributes: { "app.entity": name, "app.entity.id": id }
460
+ }, { captureStackTrace: false })
461
+ )
462
+
463
+ if (Option.isNone(rawResult)) continue
464
+
465
+ const rawData = rawResult.value as Encoded
466
+ const jitMResult = mapFrom(rawData) // apply jitM
467
+
468
+ const decodeResult = yield* S.decodeEffectConcurrently(schema)(jitMResult).pipe(
469
+ Effect.result,
470
+ provideRctx
471
+ )
472
+
473
+ if (Result.isFailure(decodeResult)) {
474
+ errors.push(
475
+ ValidationError.make({
476
+ id,
477
+ rawData,
478
+ jitMResult,
479
+ error: decodeResult.failure
480
+ })
481
+ )
482
+ }
483
+ }
484
+
485
+ return ValidationResult.make({
486
+ total: NonNegativeInt(allIds.length),
487
+ sampled: NonNegativeInt(sample.length),
488
+ valid: NonNegativeInt(sample.length - errors.length),
489
+ errors
490
+ })
491
+ }
492
+ )
493
+
494
+ const r = {
495
+ changeFeed,
496
+ itemType: name,
497
+ idKey,
498
+ find,
499
+ all,
500
+ saveAndPublish,
501
+ removeAndPublish,
502
+ removeById,
503
+ seedNamespace: (namespace: string) => store.seedNamespace(namespace),
504
+ validateSample,
505
+ queryRaw<A, Out, QR>(schema: S.Codec<A, Out, QR>, q: Q.RawQuery<Encoded, Out>) {
506
+ const dec = S.decodeEffectConcurrently(S.Array(schema))
507
+ return store.queryRaw(q).pipe(
508
+ Effect.flatMap(dec),
509
+ Effect.withSpan("Repository.queryRaw", {
510
+ kind: "client",
511
+ attributes: { "app.entity": name }
512
+ }, { captureStackTrace: false })
513
+ )
514
+ },
515
+ query(q: any) {
516
+ // eslint-disable-next-line prefer-rest-params
517
+ return query(typeof q === "function" ? Pipeable.pipeArguments(Q.make(), arguments) : q) as any
518
+ },
519
+ /**
520
+ * @internal
521
+ */
522
+ mapped: <A, R>(schema: S.Codec<A, any, R>) => {
523
+ const dec = S.decodeEffectConcurrently(schema)
524
+ const encMany = S.encodeEffect(S.Array(schema))
525
+ const decMany = S.decodeEffectConcurrently(S.Array(schema))
526
+ const spanAttrs = { kind: "client" as const, attributes: { "app.entity": name } }
527
+ return {
528
+ all: allE.pipe(
529
+ Effect.flatMap(decMany),
530
+ Effect.map((_) => _ as any[]),
531
+ Effect.withSpan("Repository.mapped.all", spanAttrs, { captureStackTrace: false })
532
+ ),
533
+ find: (id: T[IdKey]) =>
534
+ flatMapOption(findE(id), dec).pipe(
535
+ Effect.withSpan("Repository.mapped.find", {
536
+ ...spanAttrs,
537
+ attributes: { ...spanAttrs.attributes, "app.entity.id": id }
538
+ }, { captureStackTrace: false })
539
+ ),
540
+ // query: (q: any) => {
541
+ // const a = Q.toFilter(q)
542
+
543
+ // return filter(a)
544
+ // .pipe(
545
+ // Effect.flatMap(decMany),
546
+ // Effect.map((_) => _ as any[]),
547
+ // Effect.withSpan("Repository.mapped.query [effect-app/infra]", {
548
+ // captureStackTrace: false,
549
+ // attributes: {
550
+ // "repository.model_name": name,
551
+ // query: { ...a, schema: a.schema ? "__SCHEMA__" : a.schema, filter: a.filter.build() }
552
+ // }
553
+ // })
554
+ // )
555
+ // },
556
+ save: (...xes: any[]) =>
557
+ Effect.flatMap(encMany(xes), (_) => saveAllE(_)).pipe(
558
+ Effect.withSpan("Repository.mapped.save", spanAttrs, { captureStackTrace: false })
559
+ )
560
+ }
561
+ }
562
+ }
563
+ return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish, RCtx>
564
+ })
565
+ .pipe(Effect
566
+ // .withSpan("Repository.make [effect-app/infra]", { attributes: { "repository.model_name": name } })
567
+ .withLogSpan("Repository.make: " + name))
568
+ }
569
+
570
+ return {
571
+ make,
572
+ Q: Q.make<Encoded>()
573
+ }
574
+ }
575
+ }
576
+
577
+ const pluralize = (s: string) =>
578
+ s.endsWith("s")
579
+ ? s + "es"
580
+ : s.endsWith("y")
581
+ ? s.substring(0, s.length - 1) + "ies"
582
+ : s + "s"
583
+
584
+ export function makeStore<Encoded extends FieldValues>() {
585
+ return <
586
+ ItemType extends string,
587
+ R,
588
+ E,
589
+ T,
590
+ IdKey extends keyof Encoded
591
+ >(
592
+ name: ItemType,
593
+ schema: S.Codec<T, E, R>,
594
+ mapTo: (e: E, etag: string | undefined) => Encoded,
595
+ idKey: IdKey
596
+ ) => {
597
+ function makeStore<RInitial = never, EInitial = never>(
598
+ makeInitial?: Effect.Effect<readonly T[], EInitial, RInitial>,
599
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
600
+ partitionValue?: (e?: Encoded) => string
601
+ }
602
+ ) {
603
+ function encodeToEncoded() {
604
+ const getEtag = () => undefined
605
+ return (t: T) =>
606
+ S.encodeEffect(schema)(t).pipe(
607
+ Effect.orDie,
608
+ Effect.map((_) => mapToPersistenceModel(_, getEtag))
609
+ )
610
+ }
611
+
612
+ function mapToPersistenceModel(
613
+ e: E,
614
+ getEtag: (id: string) => string | undefined
615
+ ): Encoded {
616
+ return mapTo(e, getEtag((e as any)[idKey] as string))
617
+ }
618
+
619
+ return Effect.gen(function*() {
620
+ const { make } = yield* StoreMaker
621
+
622
+ const store = yield* make<IdKey, Encoded, RInitial | R, EInitial>(
623
+ pluralize(name),
624
+ idKey,
625
+ makeInitial
626
+ ? makeInitial
627
+ .pipe(
628
+ Effect.flatMap(Effect.forEach(encodeToEncoded())),
629
+ setupRequestContextFromCurrent("Repository.makeInitial [effect-app/infra]", {
630
+ attributes: { "app.entity": name }
631
+ })
632
+ )
633
+ : undefined,
634
+ {
635
+ ...config,
636
+ partitionValue: config?.partitionValue
637
+ ?? ((_) => "primary") /*(isIntegrationEvent(r) ? r.companyId : r.id*/
638
+ }
639
+ )
640
+
641
+ return store
642
+ })
643
+ }
644
+
645
+ return makeStore
646
+ }
647
+ }
648
+
649
+ export interface Repos<
650
+ T,
651
+ Encoded extends { id: string },
652
+ RSchema,
653
+ Evt,
654
+ ItemType extends string,
655
+ IdKey extends keyof T,
656
+ RPublish
657
+ > {
658
+ make<RInitial = never, E = never, R2 = never>(
659
+ args: [Evt] extends [never] ? {
660
+ makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
661
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
662
+ partitionValue?: (e?: Encoded) => string
663
+ }
664
+ }
665
+ : {
666
+ publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect.Effect<void, never, R2>
667
+ makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
668
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
669
+ partitionValue?: (e?: Encoded) => string
670
+ }
671
+ }
672
+ ): Effect.Effect<Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>, E, StoreMaker | RInitial | R2>
673
+ makeWith<Out, RInitial = never, E = never, R2 = never>(
674
+ args: [Evt] extends [never] ? {
675
+ makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
676
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
677
+ partitionValue?: (e?: Encoded) => string
678
+ }
679
+ }
680
+ : {
681
+ publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect.Effect<void, never, R2>
682
+ makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
683
+ config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
684
+ partitionValue?: (e?: Encoded) => string
685
+ }
686
+ },
687
+ f: (r: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>) => Out
688
+ ): Effect.Effect<Out, E, StoreMaker | RInitial | R2>
689
+ readonly Q: ReturnType<typeof Q.make<Encoded>>
690
+ readonly type: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>
691
+ }