@effect-app/infra 4.0.0-beta.21 → 4.0.0-beta.210

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 (309) hide show
  1. package/CHANGELOG.md +1548 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +7 -7
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +10 -12
  6. package/dist/Emailer/Sendgrid.d.ts +14 -14
  7. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  8. package/dist/Emailer/Sendgrid.js +16 -15
  9. package/dist/Emailer/fake.d.ts +1 -1
  10. package/dist/Emailer/service.d.ts +10 -4
  11. package/dist/Emailer/service.d.ts.map +1 -1
  12. package/dist/Emailer/service.js +3 -3
  13. package/dist/Emailer.d.ts +1 -1
  14. package/dist/MainFiberSet.d.ts +9 -9
  15. package/dist/MainFiberSet.d.ts.map +1 -1
  16. package/dist/MainFiberSet.js +3 -3
  17. package/dist/Model/Repository/Registry.d.ts +20 -0
  18. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  19. package/dist/Model/Repository/Registry.js +17 -0
  20. package/dist/Model/Repository/ext.d.ts +33 -15
  21. package/dist/Model/Repository/ext.d.ts.map +1 -1
  22. package/dist/Model/Repository/ext.js +54 -2
  23. package/dist/Model/Repository/internal/internal.d.ts +6 -6
  24. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  25. package/dist/Model/Repository/internal/internal.js +59 -41
  26. package/dist/Model/Repository/legacy.d.ts +1 -1
  27. package/dist/Model/Repository/makeRepo.d.ts +7 -6
  28. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.js +5 -1
  30. package/dist/Model/Repository/service.d.ts +28 -23
  31. package/dist/Model/Repository/service.d.ts.map +1 -1
  32. package/dist/Model/Repository/validation.d.ts +46 -17
  33. package/dist/Model/Repository/validation.d.ts.map +1 -1
  34. package/dist/Model/Repository/validation.js +5 -5
  35. package/dist/Model/Repository.d.ts +2 -1
  36. package/dist/Model/Repository.d.ts.map +1 -1
  37. package/dist/Model/Repository.js +2 -1
  38. package/dist/Model/dsl.d.ts +4 -4
  39. package/dist/Model/dsl.d.ts.map +1 -1
  40. package/dist/Model/filter/filterApi.d.ts +5 -5
  41. package/dist/Model/filter/filterApi.d.ts.map +1 -1
  42. package/dist/Model/filter/types/errors.d.ts +1 -1
  43. package/dist/Model/filter/types/fields.d.ts +1 -1
  44. package/dist/Model/filter/types/path/common.d.ts +1 -1
  45. package/dist/Model/filter/types/path/eager.d.ts +1 -1
  46. package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
  47. package/dist/Model/filter/types/path/eager.js +1 -1
  48. package/dist/Model/filter/types/path/index.d.ts +1 -1
  49. package/dist/Model/filter/types/utils.d.ts +1 -1
  50. package/dist/Model/filter/types/validator.d.ts +1 -1
  51. package/dist/Model/filter/types.d.ts +1 -1
  52. package/dist/Model/query/dsl.d.ts +16 -16
  53. package/dist/Model/query/dsl.d.ts.map +1 -1
  54. package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
  55. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  56. package/dist/Model/query/new-kid-interpreter.js +3 -3
  57. package/dist/Model/query.d.ts +1 -1
  58. package/dist/Model.d.ts +2 -1
  59. package/dist/Model.d.ts.map +1 -1
  60. package/dist/Model.js +2 -1
  61. package/dist/QueueMaker/SQLQueue.d.ts +5 -7
  62. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  63. package/dist/QueueMaker/SQLQueue.js +130 -116
  64. package/dist/QueueMaker/errors.d.ts +2 -2
  65. package/dist/QueueMaker/errors.d.ts.map +1 -1
  66. package/dist/QueueMaker/memQueue.d.ts +7 -4
  67. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  68. package/dist/QueueMaker/memQueue.js +75 -63
  69. package/dist/QueueMaker/sbqueue.d.ts +6 -3
  70. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  71. package/dist/QueueMaker/sbqueue.js +52 -53
  72. package/dist/QueueMaker/service.d.ts +1 -1
  73. package/dist/RequestContext.d.ts +74 -35
  74. package/dist/RequestContext.d.ts.map +1 -1
  75. package/dist/RequestContext.js +13 -14
  76. package/dist/RequestFiberSet.d.ts +7 -7
  77. package/dist/RequestFiberSet.d.ts.map +1 -1
  78. package/dist/RequestFiberSet.js +3 -3
  79. package/dist/Store/ContextMapContainer.d.ts +19 -3
  80. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  81. package/dist/Store/ContextMapContainer.js +13 -3
  82. package/dist/Store/Cosmos/query.d.ts +1 -1
  83. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  84. package/dist/Store/Cosmos/query.js +10 -12
  85. package/dist/Store/Cosmos.d.ts +1 -1
  86. package/dist/Store/Cosmos.d.ts.map +1 -1
  87. package/dist/Store/Cosmos.js +335 -243
  88. package/dist/Store/Disk.d.ts +2 -2
  89. package/dist/Store/Disk.d.ts.map +1 -1
  90. package/dist/Store/Disk.js +72 -35
  91. package/dist/Store/Memory.d.ts +6 -4
  92. package/dist/Store/Memory.d.ts.map +1 -1
  93. package/dist/Store/Memory.js +90 -57
  94. package/dist/Store/SQL/Pg.d.ts +4 -0
  95. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  96. package/dist/Store/SQL/Pg.js +231 -0
  97. package/dist/Store/SQL/query.d.ts +38 -0
  98. package/dist/Store/SQL/query.d.ts.map +1 -0
  99. package/dist/Store/SQL/query.js +367 -0
  100. package/dist/Store/SQL.d.ts +20 -0
  101. package/dist/Store/SQL.d.ts.map +1 -0
  102. package/dist/Store/SQL.js +464 -0
  103. package/dist/Store/codeFilter.d.ts +1 -1
  104. package/dist/Store/codeFilter.d.ts.map +1 -1
  105. package/dist/Store/codeFilter.js +4 -2
  106. package/dist/Store/index.d.ts +5 -2
  107. package/dist/Store/index.d.ts.map +1 -1
  108. package/dist/Store/index.js +15 -3
  109. package/dist/Store/service.d.ts +18 -7
  110. package/dist/Store/service.d.ts.map +1 -1
  111. package/dist/Store/service.js +24 -6
  112. package/dist/Store/utils.d.ts +1 -1
  113. package/dist/Store/utils.d.ts.map +1 -1
  114. package/dist/Store/utils.js +3 -4
  115. package/dist/Store.d.ts +1 -1
  116. package/dist/adapters/SQL/Model.d.ts +31 -42
  117. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  118. package/dist/adapters/SQL/Model.js +29 -38
  119. package/dist/adapters/SQL.d.ts +1 -1
  120. package/dist/adapters/ServiceBus.d.ts +11 -11
  121. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  122. package/dist/adapters/ServiceBus.js +13 -15
  123. package/dist/adapters/cosmos-client.d.ts +3 -3
  124. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  125. package/dist/adapters/cosmos-client.js +3 -3
  126. package/dist/adapters/index.d.ts +8 -2
  127. package/dist/adapters/index.d.ts.map +1 -1
  128. package/dist/adapters/index.js +8 -2
  129. package/dist/adapters/logger.d.ts +2 -2
  130. package/dist/adapters/logger.d.ts.map +1 -1
  131. package/dist/adapters/memQueue.d.ts +3 -3
  132. package/dist/adapters/memQueue.d.ts.map +1 -1
  133. package/dist/adapters/memQueue.js +3 -3
  134. package/dist/adapters/mongo-client.d.ts +3 -3
  135. package/dist/adapters/mongo-client.d.ts.map +1 -1
  136. package/dist/adapters/mongo-client.js +3 -3
  137. package/dist/adapters/redis-client.d.ts +3 -3
  138. package/dist/adapters/redis-client.d.ts.map +1 -1
  139. package/dist/adapters/redis-client.js +3 -3
  140. package/dist/api/ContextProvider.d.ts +8 -8
  141. package/dist/api/ContextProvider.d.ts.map +1 -1
  142. package/dist/api/ContextProvider.js +6 -6
  143. package/dist/api/codec.d.ts +1 -1
  144. package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
  145. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  146. package/dist/api/internal/RequestContextMiddleware.js +2 -2
  147. package/dist/api/internal/auth.d.ts +44 -6
  148. package/dist/api/internal/auth.d.ts.map +1 -1
  149. package/dist/api/internal/auth.js +160 -29
  150. package/dist/api/internal/events.d.ts +3 -3
  151. package/dist/api/internal/events.d.ts.map +1 -1
  152. package/dist/api/internal/events.js +10 -8
  153. package/dist/api/internal/health.d.ts +1 -1
  154. package/dist/api/layerUtils.d.ts +6 -6
  155. package/dist/api/layerUtils.d.ts.map +1 -1
  156. package/dist/api/layerUtils.js +5 -5
  157. package/dist/api/middlewares.d.ts +1 -1
  158. package/dist/api/reportError.d.ts +1 -1
  159. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
  160. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  161. package/dist/api/routing/middleware/middleware.d.ts +39 -3
  162. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  163. package/dist/api/routing/middleware/middleware.js +48 -16
  164. package/dist/api/routing/middleware.d.ts +1 -2
  165. package/dist/api/routing/middleware.d.ts.map +1 -1
  166. package/dist/api/routing/middleware.js +1 -2
  167. package/dist/api/routing/schema/jwt.d.ts +1 -1
  168. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  169. package/dist/api/routing/tsort.d.ts +1 -1
  170. package/dist/api/routing/tsort.d.ts.map +1 -1
  171. package/dist/api/routing/utils.d.ts +3 -3
  172. package/dist/api/routing/utils.d.ts.map +1 -1
  173. package/dist/api/routing.d.ts +80 -37
  174. package/dist/api/routing.d.ts.map +1 -1
  175. package/dist/api/routing.js +112 -40
  176. package/dist/api/setupRequest.d.ts +8 -5
  177. package/dist/api/setupRequest.d.ts.map +1 -1
  178. package/dist/api/setupRequest.js +12 -7
  179. package/dist/api/util.d.ts +1 -1
  180. package/dist/arbs.d.ts +1 -1
  181. package/dist/arbs.d.ts.map +1 -1
  182. package/dist/arbs.js +5 -3
  183. package/dist/errorReporter.d.ts +4 -4
  184. package/dist/errorReporter.d.ts.map +1 -1
  185. package/dist/errorReporter.js +20 -25
  186. package/dist/errors.d.ts +1 -1
  187. package/dist/fileUtil.d.ts +1 -1
  188. package/dist/fileUtil.d.ts.map +1 -1
  189. package/dist/index.d.ts +1 -1
  190. package/dist/logger/jsonLogger.d.ts +1 -1
  191. package/dist/logger/logFmtLogger.d.ts +1 -1
  192. package/dist/logger/shared.d.ts +1 -1
  193. package/dist/logger/shared.js +2 -2
  194. package/dist/logger.d.ts +1 -1
  195. package/dist/logger.d.ts.map +1 -1
  196. package/dist/otel.d.ts +66 -0
  197. package/dist/otel.d.ts.map +1 -0
  198. package/dist/otel.js +56 -0
  199. package/dist/rateLimit.d.ts +9 -3
  200. package/dist/rateLimit.d.ts.map +1 -1
  201. package/dist/rateLimit.js +5 -11
  202. package/dist/test.d.ts +2 -2
  203. package/dist/test.d.ts.map +1 -1
  204. package/dist/test.js +1 -1
  205. package/dist/vitest.d.ts +1 -1
  206. package/examples/query.ts +39 -35
  207. package/package.json +45 -37
  208. package/src/CUPS.ts +9 -11
  209. package/src/Emailer/Sendgrid.ts +17 -14
  210. package/src/Emailer/service.ts +9 -3
  211. package/src/MainFiberSet.ts +5 -6
  212. package/src/Model/Repository/Registry.ts +33 -0
  213. package/src/Model/Repository/ext.ts +96 -10
  214. package/src/Model/Repository/internal/internal.ts +159 -139
  215. package/src/Model/Repository/makeRepo.ts +12 -10
  216. package/src/Model/Repository/service.ts +31 -22
  217. package/src/Model/Repository/validation.ts +4 -4
  218. package/src/Model/Repository.ts +1 -0
  219. package/src/Model/dsl.ts +3 -3
  220. package/src/Model/filter/types/path/eager.ts +1 -2
  221. package/src/Model/query/dsl.ts +18 -18
  222. package/src/Model/query/new-kid-interpreter.ts +2 -2
  223. package/src/Model.ts +1 -0
  224. package/src/QueueMaker/SQLQueue.ts +144 -152
  225. package/src/QueueMaker/memQueue.ts +104 -103
  226. package/src/QueueMaker/sbqueue.ts +70 -86
  227. package/src/RequestContext.ts +14 -16
  228. package/src/RequestFiberSet.ts +2 -2
  229. package/src/Store/ContextMapContainer.ts +41 -2
  230. package/src/Store/Cosmos/query.ts +16 -20
  231. package/src/Store/Cosmos.ts +473 -348
  232. package/src/Store/Disk.ts +102 -65
  233. package/src/Store/Memory.ts +118 -83
  234. package/src/Store/SQL/Pg.ts +352 -0
  235. package/src/Store/SQL/query.ts +409 -0
  236. package/src/Store/SQL.ts +734 -0
  237. package/src/Store/codeFilter.ts +3 -1
  238. package/src/Store/index.ts +17 -2
  239. package/src/Store/service.ts +32 -8
  240. package/src/Store/utils.ts +23 -22
  241. package/src/adapters/SQL/Model.ts +41 -40
  242. package/src/adapters/ServiceBus.ts +112 -116
  243. package/src/adapters/cosmos-client.ts +2 -2
  244. package/src/adapters/index.ts +7 -0
  245. package/src/adapters/memQueue.ts +2 -2
  246. package/src/adapters/mongo-client.ts +2 -2
  247. package/src/adapters/redis-client.ts +2 -2
  248. package/src/api/ContextProvider.ts +12 -13
  249. package/src/api/internal/RequestContextMiddleware.ts +1 -1
  250. package/src/api/internal/auth.ts +246 -44
  251. package/src/api/internal/events.ts +13 -9
  252. package/src/api/layerUtils.ts +8 -8
  253. package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
  254. package/src/api/routing/middleware/middleware.ts +55 -14
  255. package/src/api/routing/middleware.ts +0 -2
  256. package/src/api/routing.ts +298 -128
  257. package/src/api/setupRequest.ts +28 -8
  258. package/src/arbs.ts +4 -2
  259. package/src/errorReporter.ts +62 -74
  260. package/src/logger/shared.ts +1 -1
  261. package/src/otel.ts +141 -0
  262. package/src/rateLimit.ts +30 -22
  263. package/src/test.ts +1 -1
  264. package/test/auth.test.ts +101 -0
  265. package/test/contextProvider.test.ts +11 -11
  266. package/test/controller.test.ts +21 -30
  267. package/test/dist/auth.test.d.ts.map +1 -0
  268. package/test/dist/contextProvider.test.d.ts.map +1 -1
  269. package/test/dist/controller.test.d.ts.map +1 -1
  270. package/test/dist/date-query.test.d.ts.map +1 -0
  271. package/test/dist/fixtures.d.ts +26 -12
  272. package/test/dist/fixtures.d.ts.map +1 -1
  273. package/test/dist/fixtures.js +12 -10
  274. package/test/dist/query.test.d.ts.map +1 -1
  275. package/test/dist/rawQuery.test.d.ts.map +1 -1
  276. package/test/dist/repository-ext.test.d.ts.map +1 -0
  277. package/test/dist/requires.test.d.ts.map +1 -1
  278. package/test/dist/router-generator.test.d.ts.map +1 -0
  279. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  280. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  281. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  282. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  283. package/test/dist/sql-store.test.d.ts.map +1 -0
  284. package/test/fixtures.ts +11 -9
  285. package/test/query.test.ts +216 -34
  286. package/test/rawQuery.test.ts +23 -19
  287. package/test/repository-ext.test.ts +60 -0
  288. package/test/requires.test.ts +6 -6
  289. package/test/router-generator.test.ts +183 -0
  290. package/test/routing-interruptibility.test.ts +63 -0
  291. package/test/rpc-e2e-invalidation.test.ts +251 -0
  292. package/test/rpc-multi-middleware.test.ts +78 -9
  293. package/test/rpc-stream-fullstack.test.ts +300 -0
  294. package/test/sql-store.test.ts +1064 -0
  295. package/test/validateSample.test.ts +15 -12
  296. package/tsconfig.examples.json +1 -1
  297. package/tsconfig.json +0 -1
  298. package/tsconfig.json.bak +2 -2
  299. package/tsconfig.src.json +35 -35
  300. package/tsconfig.test.json +2 -2
  301. package/dist/Operations.d.ts +0 -55
  302. package/dist/Operations.d.ts.map +0 -1
  303. package/dist/Operations.js +0 -102
  304. package/dist/OperationsRepo.d.ts +0 -41
  305. package/dist/OperationsRepo.d.ts.map +0 -1
  306. package/dist/OperationsRepo.js +0 -14
  307. package/eslint.config.mjs +0 -24
  308. package/src/Operations.ts +0 -235
  309. package/src/OperationsRepo.ts +0 -16
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import type {} from "effect/Equal"
3
- import type {} from "effect/Hash"
4
- import { Array, Chunk, Effect, Equivalence, flow, type NonEmptyReadonlyArray, Option, pipe, Pipeable, PubSub, Result, S, SchemaAST, ServiceMap, Unify } from "effect-app"
2
+
3
+ import { Array, Chunk, Context, Effect, Equivalence, flow, type NonEmptyReadonlyArray, Option, pipe, Pipeable, PubSub, Result, S, SchemaAST, Unify } from "effect-app"
5
4
  import { toNonEmptyArray } from "effect-app/Array"
6
5
  import { NotFoundError } from "effect-app/client/errors"
7
6
  import { flatMapOption } from "effect-app/Effect"
@@ -55,14 +54,14 @@ export function makeRepoInternal<
55
54
 
56
55
  function make<RInitial = never, E = never, RPublish = never, RCtx = never>(
57
56
  args: [Evt] extends [never] ? {
58
- schemaContext?: ServiceMap.ServiceMap<RCtx>
57
+ schemaContext?: Context.Context<RCtx>
59
58
  makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
60
59
  config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
61
60
  partitionValue?: (e?: Encoded) => string
62
61
  }
63
62
  }
64
63
  : {
65
- schemaContext?: ServiceMap.ServiceMap<RCtx>
64
+ schemaContext?: Context.Context<RCtx>
66
65
  publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect.Effect<void, never, RPublish>
67
66
  makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
68
67
  config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
@@ -72,16 +71,16 @@ export function makeRepoInternal<
72
71
  ) {
73
72
  return Effect
74
73
  .gen(function*() {
75
- const rctx: ServiceMap.ServiceMap<RCtx> = args.schemaContext ?? ServiceMap.empty() as any
74
+ const rctx: Context.Context<RCtx> = args.schemaContext ?? Context.empty() as any
76
75
  const provideRctx = Effect.provide(rctx)
77
76
  const encodeMany = flow(
78
77
  S.encodeEffect(S.Array(schema)),
79
78
  provideRctx,
80
- Effect.withSpan("encodeMany", {}, { captureStackTrace: false })
79
+ Effect.withSpan("encodeMany", { attributes: { "app.entity": name } }, { captureStackTrace: false })
81
80
  )
82
- const decode = flow(S.decodeEffect(schema), provideRctx)
81
+ const decode = flow(S.decodeEffectConcurrently(schema), provideRctx)
83
82
  const decodeMany = flow(
84
- S.decodeEffect(S.Array(schema)),
83
+ S.decodeEffectConcurrently(S.Array(schema)),
85
84
  provideRctx
86
85
  )
87
86
 
@@ -113,11 +112,14 @@ export function makeRepoInternal<
113
112
  let ast = _.ast
114
113
  if (ast._tag === "Declaration") ast = ast.typeParameters[0]!
115
114
 
116
- // In v4, to get the encoded (from) side of a schema, use SchemaAST.toEncoded
117
115
  const pickIdFromAst = (a: SchemaAST.AST) => {
118
- const encoded = SchemaAST.toEncoded(a)
119
- if (SchemaAST.isObjects(encoded)) {
120
- const field = encoded.propertySignatures.find((_) => _.name === idKey)
116
+ // Unwrap Declaration (e.g. TaggedClass) to get the underlying Objects AST
117
+ let inner = a
118
+ if (inner._tag === "Declaration") inner = inner.typeParameters[0]!
119
+ // Pick from the original AST to preserve the full encoding chain (e.g. decodeTo transformations).
120
+ // Using toEncoded would lose transformation info needed to encode Type -> Encoded.
121
+ if (SchemaAST.isObjects(inner)) {
122
+ const field = inner.propertySignatures.find((_) => _.name === idKey)
121
123
  if (field) {
122
124
  return S.Struct({ [idKey]: S.make(field.type) }) as unknown as Codec<T, Encoded>
123
125
  }
@@ -138,7 +140,7 @@ export function makeRepoInternal<
138
140
  Effect.map((_: Record<string, unknown>) => _[idKey as string] as Encoded[IdKey])
139
141
  )
140
142
  const findEId = Effect.fnUntraced(function*(id: Encoded[IdKey]) {
141
- yield* Effect.annotateCurrentSpan({ itemId: id })
143
+ yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
142
144
 
143
145
  return yield* Effect.flatMap(
144
146
  store.find(id),
@@ -151,7 +153,7 @@ export function makeRepoInternal<
151
153
  })
152
154
  // TODO: select the particular field, instead of as struct
153
155
  const findE = Effect.fnUntraced(function*(id: T[IdKey]) {
154
- yield* Effect.annotateCurrentSpan({ itemId: id })
156
+ yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
155
157
 
156
158
  return yield* pipe(
157
159
  encodeId({ [idKey]: id } as any),
@@ -161,8 +163,8 @@ export function makeRepoInternal<
161
163
  )
162
164
  })
163
165
 
164
- const find = Effect.fn("find")(function*(id: T[IdKey]) {
165
- yield* Effect.annotateCurrentSpan({ itemId: id })
166
+ const find = Effect.fn("find", { attributes: { "app.entity": name } })(function*(id: T[IdKey]) {
167
+ yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
166
168
 
167
169
  return yield* flatMapOption(findE(id), (_) => Effect.orDie(decode(_)))
168
170
  })
@@ -188,73 +190,86 @@ export function makeRepoInternal<
188
190
  Effect.andThen(saveAllE)
189
191
  )
190
192
 
191
- const saveAndPublish = Effect.fn("saveAndPublish")(function*(items: Iterable<T>, events: Iterable<Evt> = []) {
192
- const it = Chunk.fromIterable(items)
193
- const evts = [...events]
194
- yield* Effect.annotateCurrentSpan({ itemIds: [...Chunk.map(it, (_) => _[idKey])], events: evts.length })
195
- return yield* saveAll(it)
196
- .pipe(
197
- Effect.andThen(Effect.sync(() => toNonEmptyArray(evts))),
198
- // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
199
- (_) => flatMapOption(_, pub),
200
- Effect.andThen(PubSub.publish(changeFeed, [Chunk.toArray(it), "save"] as [T[], "save" | "remove"])),
201
- Effect.asVoid
202
- )
203
- })
193
+ const saveAndPublish = Effect.fn("saveAndPublish", { attributes: { "app.entity": name } })(
194
+ function*(items: Iterable<T>, events: Iterable<Evt> = []) {
195
+ const it = Chunk.fromIterable(items)
196
+ const evts = [...events]
197
+ yield* Effect.annotateCurrentSpan({
198
+ "app.entity.ids": Chunk.map(it, (_) => _[idKey]),
199
+ "app.event.count": evts.length
200
+ })
201
+ return yield* saveAll(it)
202
+ .pipe(
203
+ Effect.andThen(Effect.sync(() => toNonEmptyArray(evts))),
204
+ // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
205
+ (_) => flatMapOption(_, pub),
206
+ Effect.andThen(PubSub.publish(changeFeed, [Chunk.toArray(it), "save"] as [T[], "save" | "remove"])),
207
+ Effect.asVoid
208
+ )
209
+ }
210
+ )
204
211
 
205
- const removeAndPublish = Effect.fn("removeAndPublish")(function*(a: Iterable<T>, events: Iterable<Evt> = []) {
206
- const { set } = yield* cms
207
- const it = [...a]
208
- const evts = [...events]
209
- yield* Effect.annotateCurrentSpan({ itemIds: it.map((_) => _[idKey]), eventCount: evts.length })
210
- const items = yield* encodeMany(it).pipe(Effect.orDie)
211
- if (Array.isReadonlyArrayNonEmpty(items)) {
212
- yield* store.batchRemove(
213
- items.map((_) => (_[idKey])),
214
- args.config?.partitionValue?.(items[0])
215
- )
216
- for (const e of items) {
217
- set(e[idKey], undefined)
212
+ const removeAndPublish = Effect.fn("removeAndPublish", { attributes: { "app.entity": name } })(
213
+ function*(a: Iterable<T>, events: Iterable<Evt> = []) {
214
+ const { set } = yield* cms
215
+ const it = [...a]
216
+ const evts = [...events]
217
+ yield* Effect.annotateCurrentSpan({
218
+ "app.entity.ids": it.map((_) => _[idKey]),
219
+ "app.event.count": evts.length
220
+ })
221
+ const items = yield* encodeMany(it).pipe(Effect.orDie)
222
+ if (Array.isReadonlyArrayNonEmpty(items)) {
223
+ yield* store.batchRemove(
224
+ items.map((_) => (_[idKey])),
225
+ args.config?.partitionValue?.(items[0])
226
+ )
227
+ for (const e of items) {
228
+ set(e[idKey], undefined)
229
+ }
230
+ yield* Effect
231
+ .sync(() => toNonEmptyArray(evts))
232
+ // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
233
+ .pipe((_) => flatMapOption(_, pub))
234
+
235
+ yield* PubSub.publish(changeFeed, [it, "remove"] as [T[], "save" | "remove"])
218
236
  }
219
- yield* Effect
220
- .sync(() => toNonEmptyArray(evts))
221
- // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
222
- .pipe((_) => flatMapOption(_, pub))
237
+ }
238
+ )
223
239
 
224
- yield* PubSub.publish(changeFeed, [it, "remove"] as [T[], "save" | "remove"])
240
+ const removeById = Effect.fn("removeById", { attributes: { "app.entity": name } })(
241
+ function*(idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>) {
242
+ const ids = globalThis.Array.isArray(idOrIds)
243
+ ? idOrIds as readonly T[IdKey][]
244
+ : [idOrIds as T[IdKey]]
245
+ if (!Array.isReadonlyArrayNonEmpty(ids)) {
246
+ return
247
+ }
248
+ const { set } = yield* cms
249
+ const eids = yield* Effect.forEach(ids, (_) => encodeIdOnly(_ as any)).pipe(Effect.orDie)
250
+ yield* Effect.annotateCurrentSpan({ "app.entity.ids": eids })
251
+ yield* store.batchRemove(eids)
252
+ for (const id of eids) {
253
+ set(id, undefined)
254
+ }
255
+ yield* PubSub.publish(changeFeed, [[], "remove"] as [T[], "save" | "remove"])
225
256
  }
226
- })
257
+ )
227
258
 
228
- const removeById = Effect.fn("removeById")(function*(...ids: readonly T[IdKey][]) {
229
- if (!Array.isReadonlyArrayNonEmpty(ids)) {
230
- return
259
+ const parseMany = Effect.fn("parseMany", { attributes: { "app.entity": name } })(
260
+ function*(items: readonly PM[]) {
261
+ const cm = yield* cms
262
+ return yield* decodeMany(items.map((_) => mapReverse(_, cm.set))).pipe(Effect.orDie)
231
263
  }
232
- const { set } = yield* cms
233
- const eids = yield* Effect.forEach(ids, (_) => encodeIdOnly(_ as any)).pipe(Effect.orDie)
234
- yield* Effect.annotateCurrentSpan({ itemIds: eids })
235
- yield* store.batchRemove(eids)
236
- for (const id of eids) {
237
- set(id, undefined)
264
+ )
265
+ const parseMany2 = Effect.fn("parseMany2", { attributes: { "app.entity": name } })(
266
+ function*<A, R>(items: readonly PM[], schema: S.Codec<A, Encoded, R>) {
267
+ const cm = yield* cms
268
+ return yield* S.decodeEffectConcurrently(S.Array(schema))(items.map((_) => mapReverse(_, cm.set))).pipe(
269
+ Effect.orDie
270
+ )
238
271
  }
239
- yield* PubSub.publish(changeFeed, [[], "remove"] as [T[], "save" | "remove"])
240
- })
241
-
242
- const parseMany = (items: readonly PM[]) =>
243
- Effect
244
- .flatMap(cms, (cm) =>
245
- decodeMany(items.map((_) => mapReverse(_, cm.set)))
246
- .pipe(Effect.orDie, Effect.withSpan("parseMany", {}, { captureStackTrace: false })))
247
- const parseMany2 = <A, R>(
248
- items: readonly PM[],
249
- schema: S.Codec<A, Encoded, R>
250
- ) =>
251
- Effect
252
- .flatMap(cms, (cm) =>
253
- S
254
- .decodeEffect(S.Array(schema))(
255
- items.map((_) => mapReverse(_, cm.set))
256
- )
257
- .pipe(Effect.orDie, Effect.withSpan("parseMany2", {}, { captureStackTrace: false })))
272
+ )
258
273
  const filter = <U extends keyof Encoded = keyof Encoded>(args: FilterArgs<Encoded, U>) =>
259
274
  store
260
275
  .filter(
@@ -276,24 +291,24 @@ export function makeRepoInternal<
276
291
  const query: {
277
292
  <A, R, From extends FieldValues>(
278
293
  q: Q.QueryProjection<Encoded extends From ? From : never, A, R>
279
- ): Effect.Effect<readonly A[], S.SchemaError, R>
294
+ ): Effect.Effect<readonly A[], S.SchemaError, Exclude<R, RCtx>>
280
295
  <A, R, EncodedRefined extends Encoded = Encoded>(
281
296
  q: Q.QAll<NoInfer<Encoded>, NoInfer<EncodedRefined>, A, R>
282
- ): Effect.Effect<readonly A[], never, R>
297
+ ): Effect.Effect<readonly A[], never, Exclude<R, RCtx>>
283
298
  } = (<A, R, EncodedRefined extends Encoded = Encoded>(q: Q.QAll<Encoded, EncodedRefined, A, R>) => {
284
299
  const a = Q.toFilter(q)
285
300
  const eff = a.mode === "project"
286
301
  ? filter(a)
287
302
  // TODO: mapFrom but need to support per field and dependencies
288
303
  .pipe(
289
- Effect.andThen(flow(S.decodeEffect(S.Array(a.schema ?? schema)), provideRctx))
304
+ Effect.andThen(flow(S.decodeEffectConcurrently(S.Array(a.schema ?? schema)), provideRctx))
290
305
  )
291
306
  : a.mode === "collect"
292
307
  ? filter(a)
293
308
  // TODO: mapFrom but need to support per field and dependencies
294
309
  .pipe(
295
310
  Effect.flatMap(flow(
296
- S.decodeEffect(S.Array(a.schema)),
311
+ S.decodeEffectConcurrently(S.Array(a.schema)),
297
312
  Effect.map(Array.getSomes),
298
313
  provideRctx
299
314
  ))
@@ -325,72 +340,76 @@ export function makeRepoInternal<
325
340
  .map(eff, (_) => NonNegativeInt(_.length))
326
341
  .pipe(Effect.catchTag("SchemaError", (e) => Effect.die(e)))
327
342
  : eff,
328
- Effect.withSpan("Repository.query [effect-app/infra]", {
343
+ Effect.withSpan(`query ${name}`, {
344
+ kind: "client",
329
345
  attributes: {
330
- "repository.model_name": name,
331
- query: { ...a, schema: a.schema ? "__SCHEMA__" : a.schema, filter: a.filter }
346
+ "app.entity": name,
347
+ "db.operation.name": "query",
348
+ "db.collection.name": name
332
349
  }
333
350
  }, { captureStackTrace: false })
334
351
  )
335
352
  }) as any
336
353
 
337
- const validateSample = Effect.fn("validateSample")(function*(options?: {
338
- percentage?: number
339
- maxItems?: number
340
- }) {
341
- const percentage = options?.percentage ?? 0.1 // default 10%
342
- const maxItems = options?.maxItems
343
-
344
- // 1. get all IDs with projection (bypasses main schema decode)
345
- const allIds = yield* store.filter({
346
- t: null as unknown as Encoded,
347
- select: [idKey as keyof Encoded]
348
- })
349
-
350
- // 2. random subset
351
- const shuffled = [...allIds].sort(() => Math.random() - 0.5)
352
- const sampleSize = Math.min(
353
- maxItems ?? Infinity,
354
- Math.ceil(allIds.length * percentage)
355
- )
356
- const sample = shuffled.slice(0, sampleSize)
357
-
358
- // 3. validate each item
359
- const errors: ValidationError[] = []
354
+ const validateSample = Effect.fn("validateSample", { attributes: { "app.entity": name } })(
355
+ function*(options?: {
356
+ percentage?: number
357
+ maxItems?: number
358
+ }) {
359
+ const percentage = options?.percentage ?? 0.1 // default 10%
360
+ const maxItems = options?.maxItems
361
+
362
+ // 1. get all IDs with projection (bypasses main schema decode)
363
+ const allIds = yield* store.filter({
364
+ t: null as unknown as Encoded,
365
+ select: [idKey as keyof Encoded]
366
+ })
367
+
368
+ // 2. random subset
369
+ const shuffled = [...allIds].sort(() => Math.random() - 0.5)
370
+ const sampleSize = Math.min(
371
+ maxItems ?? Infinity,
372
+ Math.ceil(allIds.length * percentage)
373
+ )
374
+ const sample = shuffled.slice(0, sampleSize)
360
375
 
361
- for (const item of sample) {
362
- const id = item[idKey]
363
- const rawResult = yield* store.find(id)
376
+ // 3. validate each item
377
+ const errors: ValidationError[] = []
364
378
 
365
- if (Option.isNone(rawResult)) continue
379
+ for (const item of sample) {
380
+ const id = item[idKey]
381
+ const rawResult = yield* store.find(id)
366
382
 
367
- const rawData = rawResult.value as Encoded
368
- const jitMResult = mapFrom(rawData) // apply jitM
383
+ if (Option.isNone(rawResult)) continue
369
384
 
370
- const decodeResult = yield* S.decodeEffect(schema)(jitMResult).pipe(
371
- Effect.result,
372
- provideRctx
373
- )
385
+ const rawData = rawResult.value as Encoded
386
+ const jitMResult = mapFrom(rawData) // apply jitM
374
387
 
375
- if (Result.isFailure(decodeResult)) {
376
- errors.push(
377
- new ValidationError({
378
- id,
379
- rawData,
380
- jitMResult,
381
- error: decodeResult.failure
382
- })
388
+ const decodeResult = yield* S.decodeEffectConcurrently(schema)(jitMResult).pipe(
389
+ Effect.result,
390
+ provideRctx
383
391
  )
392
+
393
+ if (Result.isFailure(decodeResult)) {
394
+ errors.push(
395
+ ValidationError.make({
396
+ id,
397
+ rawData,
398
+ jitMResult,
399
+ error: decodeResult.failure
400
+ })
401
+ )
402
+ }
384
403
  }
385
- }
386
404
 
387
- return new ValidationResult({
388
- total: NonNegativeInt(allIds.length),
389
- sampled: NonNegativeInt(sample.length),
390
- valid: NonNegativeInt(sample.length - errors.length),
391
- errors
392
- })
393
- })
405
+ return ValidationResult.make({
406
+ total: NonNegativeInt(allIds.length),
407
+ sampled: NonNegativeInt(sample.length),
408
+ valid: NonNegativeInt(sample.length - errors.length),
409
+ errors
410
+ })
411
+ }
412
+ )
394
413
 
395
414
  const r = {
396
415
  changeFeed,
@@ -401,9 +420,10 @@ export function makeRepoInternal<
401
420
  saveAndPublish,
402
421
  removeAndPublish,
403
422
  removeById,
423
+ seedNamespace: (namespace: string) => store.seedNamespace(namespace),
404
424
  validateSample,
405
425
  queryRaw<A, Out, QR>(schema: S.Codec<A, Out, QR>, q: Q.RawQuery<Encoded, Out>) {
406
- const dec = S.decodeEffect(S.Array(schema))
426
+ const dec = S.decodeEffectConcurrently(S.Array(schema))
407
427
  return store.queryRaw(q).pipe(Effect.flatMap(dec))
408
428
  },
409
429
  query(q: any) {
@@ -414,9 +434,9 @@ export function makeRepoInternal<
414
434
  * @internal
415
435
  */
416
436
  mapped: <A, R>(schema: S.Codec<A, any, R>) => {
417
- const dec = S.decodeEffect(schema)
437
+ const dec = S.decodeEffectConcurrently(schema)
418
438
  const encMany = S.encodeEffect(S.Array(schema))
419
- const decMany = S.decodeEffect(S.Array(schema))
439
+ const decMany = S.decodeEffectConcurrently(S.Array(schema))
420
440
  return {
421
441
  all: allE.pipe(
422
442
  Effect.flatMap(decMany),
@@ -441,12 +461,12 @@ export function makeRepoInternal<
441
461
  // },
442
462
  save: (...xes: any[]) =>
443
463
  Effect.flatMap(encMany(xes), (_) => saveAllE(_)).pipe(
444
- Effect.withSpan("mapped.save", {}, { captureStackTrace: false })
464
+ Effect.withSpan("mapped.save", { attributes: { "app.entity": name } }, { captureStackTrace: false })
445
465
  )
446
466
  }
447
467
  }
448
468
  }
449
- return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish>
469
+ return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish, RCtx>
450
470
  })
451
471
  .pipe(Effect
452
472
  // .withSpan("Repository.make [effect-app/infra]", { attributes: { "repository.model_name": name } })
@@ -513,7 +533,7 @@ export function makeStore<Encoded extends FieldValues>() {
513
533
  .pipe(
514
534
  Effect.flatMap(Effect.forEach(encodeToEncoded())),
515
535
  setupRequestContextFromCurrent("Repository.makeInitial [effect-app/infra]", {
516
- attributes: { "repository.model_name": name }
536
+ attributes: { "app.entity": name }
517
537
  })
518
538
  )
519
539
  : undefined,
@@ -5,13 +5,13 @@
5
5
  /* eslint-disable @typescript-eslint/no-explicit-any */
6
6
 
7
7
  // import type { ParserEnv } from "effect-app/Schema/custom/Parser"
8
- import type {} from "effect/Equal"
9
- import type {} from "effect/Hash"
10
- import { Effect, type NonEmptyReadonlyArray, type S, type ServiceMap } from "effect-app"
8
+
9
+ import { type Context, Effect, type NonEmptyReadonlyArray, type S } from "effect-app"
11
10
  import type { StoreConfig, StoreMaker } from "../../Store.js"
12
11
  import type { FieldValues } from "../filter/types.js"
13
12
  import { type ExtendedRepository, extendRepo } from "./ext.js"
14
13
  import { makeRepoInternal } from "./internal/internal.js"
14
+ import { RepositoryRegistry } from "./Registry.js"
15
15
  import type { Repository } from "./service.js"
16
16
 
17
17
  export interface RepositoryOptions<
@@ -52,11 +52,11 @@ export interface RepositoryOptions<
52
52
  * Optional context to be provided to Schema decode/encode.
53
53
  * Useful for effectful transformations like XWithItems, where items is a transformation retrieving elements from another database table or other source.
54
54
  */
55
- schemaContext?: ServiceMap.ServiceMap<RCtx>
55
+ schemaContext?: Context.Context<RCtx>
56
56
 
57
57
  overrides?: (
58
- repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>
59
- ) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>
58
+ repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
59
+ ) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
60
60
  }
61
61
 
62
62
  /**
@@ -83,9 +83,9 @@ export const makeRepo: {
83
83
  schema: S.Codec<T, Encoded, RSchema>,
84
84
  options: RepositoryOptions<IdKey, Encoded, T, ItemType, Evt, RPublish, E, RInitial, RCtx, RSchema>
85
85
  ): Effect.Effect<
86
- ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>,
86
+ ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>,
87
87
  E,
88
- RInitial | StoreMaker
88
+ RInitial | StoreMaker | RepositoryRegistry
89
89
  >
90
90
  <
91
91
  ItemType extends string,
@@ -102,9 +102,9 @@ export const makeRepo: {
102
102
  schema: S.Codec<T, Encoded, RSchema>,
103
103
  options: Omit<RepositoryOptions<"id", Encoded, T, ItemType, Evt, RPublish, E, RInitial, RCtx, RSchema>, "idKey">
104
104
  ): Effect.Effect<
105
- ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish>,
105
+ ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish, RCtx>,
106
106
  E,
107
- RInitial | StoreMaker
107
+ RInitial | StoreMaker | RepositoryRegistry
108
108
  >
109
109
  } = <
110
110
  ItemType extends string,
@@ -135,5 +135,7 @@ export const makeRepo: {
135
135
  let r = yield* mkRepo.make<RInitial, E, RPublish, RCtx>(options as any)
136
136
  if (options.overrides) r = options.overrides(r)
137
137
  const repo = extendRepo(r)
138
+ const registry = yield* RepositoryRegistry
139
+ registry.register(itemType, repo)
138
140
  return repo
139
141
  })