@gettersethya/mira 0.1.0-alpha.2

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 (338) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/app/app.d.ts +96 -0
  3. package/dist/src/app/app.d.ts.map +1 -0
  4. package/dist/src/app/app.js +139 -0
  5. package/dist/src/app/app.js.map +1 -0
  6. package/dist/src/app/builder.d.ts +106 -0
  7. package/dist/src/app/builder.d.ts.map +1 -0
  8. package/dist/src/app/builder.js +122 -0
  9. package/dist/src/app/builder.js.map +1 -0
  10. package/dist/src/app/index.d.ts +31 -0
  11. package/dist/src/app/index.d.ts.map +1 -0
  12. package/dist/src/app/index.js +29 -0
  13. package/dist/src/app/index.js.map +1 -0
  14. package/dist/src/app/types.d.ts +55 -0
  15. package/dist/src/app/types.d.ts.map +1 -0
  16. package/dist/src/app/types.js +2 -0
  17. package/dist/src/app/types.js.map +1 -0
  18. package/dist/src/cache/cached-collection.d.ts +30 -0
  19. package/dist/src/cache/cached-collection.d.ts.map +1 -0
  20. package/dist/src/cache/cached-collection.js +107 -0
  21. package/dist/src/cache/cached-collection.js.map +1 -0
  22. package/dist/src/cache/collection-cache.d.ts +17 -0
  23. package/dist/src/cache/collection-cache.d.ts.map +1 -0
  24. package/dist/src/cache/collection-cache.js +37 -0
  25. package/dist/src/cache/collection-cache.js.map +1 -0
  26. package/dist/src/cache/index.d.ts +4 -0
  27. package/dist/src/cache/index.d.ts.map +1 -0
  28. package/dist/src/cache/index.js +3 -0
  29. package/dist/src/cache/index.js.map +1 -0
  30. package/dist/src/cache/types.d.ts +12 -0
  31. package/dist/src/cache/types.d.ts.map +1 -0
  32. package/dist/src/cache/types.js +2 -0
  33. package/dist/src/cache/types.js.map +1 -0
  34. package/dist/src/collection-service/collection-service.d.ts +62 -0
  35. package/dist/src/collection-service/collection-service.d.ts.map +1 -0
  36. package/dist/src/collection-service/collection-service.js +267 -0
  37. package/dist/src/collection-service/collection-service.js.map +1 -0
  38. package/dist/src/collection-service/context.d.ts +17 -0
  39. package/dist/src/collection-service/context.d.ts.map +1 -0
  40. package/dist/src/collection-service/context.js +2 -0
  41. package/dist/src/collection-service/context.js.map +1 -0
  42. package/dist/src/collection-service/decode.d.ts +6 -0
  43. package/dist/src/collection-service/decode.d.ts.map +1 -0
  44. package/dist/src/collection-service/decode.js +26 -0
  45. package/dist/src/collection-service/decode.js.map +1 -0
  46. package/dist/src/collection-service/errors.d.ts +67 -0
  47. package/dist/src/collection-service/errors.d.ts.map +1 -0
  48. package/dist/src/collection-service/errors.js +43 -0
  49. package/dist/src/collection-service/errors.js.map +1 -0
  50. package/dist/src/collection-service/index.d.ts +5 -0
  51. package/dist/src/collection-service/index.d.ts.map +1 -0
  52. package/dist/src/collection-service/index.js +3 -0
  53. package/dist/src/collection-service/index.js.map +1 -0
  54. package/dist/src/collection-service/input-schema.d.ts +10 -0
  55. package/dist/src/collection-service/input-schema.d.ts.map +1 -0
  56. package/dist/src/collection-service/input-schema.js +109 -0
  57. package/dist/src/collection-service/input-schema.js.map +1 -0
  58. package/dist/src/collection-service/where.d.ts +35 -0
  59. package/dist/src/collection-service/where.d.ts.map +1 -0
  60. package/dist/src/collection-service/where.js +88 -0
  61. package/dist/src/collection-service/where.js.map +1 -0
  62. package/dist/src/config/config.d.ts +44 -0
  63. package/dist/src/config/config.d.ts.map +1 -0
  64. package/dist/src/config/config.js +89 -0
  65. package/dist/src/config/config.js.map +1 -0
  66. package/dist/src/config/index.d.ts +3 -0
  67. package/dist/src/config/index.d.ts.map +1 -0
  68. package/dist/src/config/index.js +2 -0
  69. package/dist/src/config/index.js.map +1 -0
  70. package/dist/src/config/types.d.ts +29 -0
  71. package/dist/src/config/types.d.ts.map +1 -0
  72. package/dist/src/config/types.js +2 -0
  73. package/dist/src/config/types.js.map +1 -0
  74. package/dist/src/crypto/crypto.d.ts +11 -0
  75. package/dist/src/crypto/crypto.d.ts.map +1 -0
  76. package/dist/src/crypto/crypto.js +4 -0
  77. package/dist/src/crypto/crypto.js.map +1 -0
  78. package/dist/src/crypto/index.d.ts +3 -0
  79. package/dist/src/crypto/index.d.ts.map +1 -0
  80. package/dist/src/crypto/index.js +3 -0
  81. package/dist/src/crypto/index.js.map +1 -0
  82. package/dist/src/crypto/node.d.ts +4 -0
  83. package/dist/src/crypto/node.d.ts.map +1 -0
  84. package/dist/src/crypto/node.js +9 -0
  85. package/dist/src/crypto/node.js.map +1 -0
  86. package/dist/src/databases/index.d.ts +2 -0
  87. package/dist/src/databases/index.d.ts.map +1 -0
  88. package/dist/src/databases/index.js +2 -0
  89. package/dist/src/databases/index.js.map +1 -0
  90. package/dist/src/databases/sqlite.d.ts +24 -0
  91. package/dist/src/databases/sqlite.d.ts.map +1 -0
  92. package/dist/src/databases/sqlite.js +27 -0
  93. package/dist/src/databases/sqlite.js.map +1 -0
  94. package/dist/src/http/auth-node.d.ts +4 -0
  95. package/dist/src/http/auth-node.d.ts.map +1 -0
  96. package/dist/src/http/auth-node.js +34 -0
  97. package/dist/src/http/auth-node.js.map +1 -0
  98. package/dist/src/http/auth.d.ts +38 -0
  99. package/dist/src/http/auth.d.ts.map +1 -0
  100. package/dist/src/http/auth.js +66 -0
  101. package/dist/src/http/auth.js.map +1 -0
  102. package/dist/src/http/errors.d.ts +31 -0
  103. package/dist/src/http/errors.d.ts.map +1 -0
  104. package/dist/src/http/errors.js +36 -0
  105. package/dist/src/http/errors.js.map +1 -0
  106. package/dist/src/http/file-serve.d.ts +10 -0
  107. package/dist/src/http/file-serve.d.ts.map +1 -0
  108. package/dist/src/http/file-serve.js +159 -0
  109. package/dist/src/http/file-serve.js.map +1 -0
  110. package/dist/src/http/file-token.d.ts +7 -0
  111. package/dist/src/http/file-token.d.ts.map +1 -0
  112. package/dist/src/http/file-token.js +55 -0
  113. package/dist/src/http/file-token.js.map +1 -0
  114. package/dist/src/http/files.d.ts +11 -0
  115. package/dist/src/http/files.d.ts.map +1 -0
  116. package/dist/src/http/files.js +85 -0
  117. package/dist/src/http/files.js.map +1 -0
  118. package/dist/src/http/index.d.ts +10 -0
  119. package/dist/src/http/index.d.ts.map +1 -0
  120. package/dist/src/http/index.js +8 -0
  121. package/dist/src/http/index.js.map +1 -0
  122. package/dist/src/http/ip-middleware.d.ts +4 -0
  123. package/dist/src/http/ip-middleware.d.ts.map +1 -0
  124. package/dist/src/http/ip-middleware.js +21 -0
  125. package/dist/src/http/ip-middleware.js.map +1 -0
  126. package/dist/src/http/params.d.ts +15 -0
  127. package/dist/src/http/params.d.ts.map +1 -0
  128. package/dist/src/http/params.js +48 -0
  129. package/dist/src/http/params.js.map +1 -0
  130. package/dist/src/http/router.d.ts +11 -0
  131. package/dist/src/http/router.d.ts.map +1 -0
  132. package/dist/src/http/router.js +216 -0
  133. package/dist/src/http/router.js.map +1 -0
  134. package/dist/src/http/server-factory-node.d.ts +4 -0
  135. package/dist/src/http/server-factory-node.d.ts.map +1 -0
  136. package/dist/src/http/server-factory-node.js +8 -0
  137. package/dist/src/http/server-factory-node.js.map +1 -0
  138. package/dist/src/http/server-factory.d.ts +11 -0
  139. package/dist/src/http/server-factory.d.ts.map +1 -0
  140. package/dist/src/http/server-factory.js +4 -0
  141. package/dist/src/http/server-factory.js.map +1 -0
  142. package/dist/src/index.d.ts +8 -0
  143. package/dist/src/index.d.ts.map +1 -0
  144. package/dist/src/index.js +10 -0
  145. package/dist/src/index.js.map +1 -0
  146. package/dist/src/migrator/dialect-sqlite.d.ts +9 -0
  147. package/dist/src/migrator/dialect-sqlite.d.ts.map +1 -0
  148. package/dist/src/migrator/dialect-sqlite.js +102 -0
  149. package/dist/src/migrator/dialect-sqlite.js.map +1 -0
  150. package/dist/src/migrator/dialect.d.ts +24 -0
  151. package/dist/src/migrator/dialect.d.ts.map +1 -0
  152. package/dist/src/migrator/dialect.js +5 -0
  153. package/dist/src/migrator/dialect.js.map +1 -0
  154. package/dist/src/migrator/index.d.ts +8 -0
  155. package/dist/src/migrator/index.d.ts.map +1 -0
  156. package/dist/src/migrator/index.js +6 -0
  157. package/dist/src/migrator/index.js.map +1 -0
  158. package/dist/src/migrator/migrator.d.ts +36 -0
  159. package/dist/src/migrator/migrator.d.ts.map +1 -0
  160. package/dist/src/migrator/migrator.js +200 -0
  161. package/dist/src/migrator/migrator.js.map +1 -0
  162. package/dist/src/migrator/schema-diff.d.ts +25 -0
  163. package/dist/src/migrator/schema-diff.d.ts.map +1 -0
  164. package/dist/src/migrator/schema-diff.js +157 -0
  165. package/dist/src/migrator/schema-diff.js.map +1 -0
  166. package/dist/src/migrator/types.d.ts +91 -0
  167. package/dist/src/migrator/types.d.ts.map +1 -0
  168. package/dist/src/migrator/types.js +13 -0
  169. package/dist/src/migrator/types.js.map +1 -0
  170. package/dist/src/platforms/node.d.ts +40 -0
  171. package/dist/src/platforms/node.d.ts.map +1 -0
  172. package/dist/src/platforms/node.js +45 -0
  173. package/dist/src/platforms/node.js.map +1 -0
  174. package/dist/src/repository/id.d.ts +5 -0
  175. package/dist/src/repository/id.d.ts.map +1 -0
  176. package/dist/src/repository/id.js +9 -0
  177. package/dist/src/repository/id.js.map +1 -0
  178. package/dist/src/repository/index.d.ts +3 -0
  179. package/dist/src/repository/index.d.ts.map +1 -0
  180. package/dist/src/repository/index.js +2 -0
  181. package/dist/src/repository/index.js.map +1 -0
  182. package/dist/src/repository/repository.d.ts +53 -0
  183. package/dist/src/repository/repository.d.ts.map +1 -0
  184. package/dist/src/repository/repository.js +150 -0
  185. package/dist/src/repository/repository.js.map +1 -0
  186. package/dist/src/repository/types.d.ts +42 -0
  187. package/dist/src/repository/types.d.ts.map +1 -0
  188. package/dist/src/repository/types.js +2 -0
  189. package/dist/src/repository/types.js.map +1 -0
  190. package/dist/src/rule/compiler.d.ts +52 -0
  191. package/dist/src/rule/compiler.d.ts.map +1 -0
  192. package/dist/src/rule/compiler.js +113 -0
  193. package/dist/src/rule/compiler.js.map +1 -0
  194. package/dist/src/rule/enforcer.d.ts +47 -0
  195. package/dist/src/rule/enforcer.d.ts.map +1 -0
  196. package/dist/src/rule/enforcer.js +60 -0
  197. package/dist/src/rule/enforcer.js.map +1 -0
  198. package/dist/src/rule/index.d.ts +3 -0
  199. package/dist/src/rule/index.d.ts.map +1 -0
  200. package/dist/src/rule/index.js +3 -0
  201. package/dist/src/rule/index.js.map +1 -0
  202. package/dist/src/storage/index.d.ts +3 -0
  203. package/dist/src/storage/index.d.ts.map +1 -0
  204. package/dist/src/storage/index.js +3 -0
  205. package/dist/src/storage/index.js.map +1 -0
  206. package/dist/src/storage/local-preset.d.ts +21 -0
  207. package/dist/src/storage/local-preset.d.ts.map +1 -0
  208. package/dist/src/storage/local-preset.js +21 -0
  209. package/dist/src/storage/local-preset.js.map +1 -0
  210. package/dist/src/storage/storage.d.ts +83 -0
  211. package/dist/src/storage/storage.d.ts.map +1 -0
  212. package/dist/src/storage/storage.js +120 -0
  213. package/dist/src/storage/storage.js.map +1 -0
  214. package/dist/src/telemetry/index.d.ts +6 -0
  215. package/dist/src/telemetry/index.d.ts.map +1 -0
  216. package/dist/src/telemetry/index.js +7 -0
  217. package/dist/src/telemetry/index.js.map +1 -0
  218. package/dist/src/telemetry/logger.d.ts +4 -0
  219. package/dist/src/telemetry/logger.d.ts.map +1 -0
  220. package/dist/src/telemetry/logger.js +27 -0
  221. package/dist/src/telemetry/logger.js.map +1 -0
  222. package/dist/src/telemetry/tracer.d.ts +16 -0
  223. package/dist/src/telemetry/tracer.d.ts.map +1 -0
  224. package/dist/src/telemetry/tracer.js +106 -0
  225. package/dist/src/telemetry/tracer.js.map +1 -0
  226. package/dist/src/thumbnail/index.d.ts +4 -0
  227. package/dist/src/thumbnail/index.d.ts.map +1 -0
  228. package/dist/src/thumbnail/index.js +3 -0
  229. package/dist/src/thumbnail/index.js.map +1 -0
  230. package/dist/src/thumbnail/photon.d.ts +9 -0
  231. package/dist/src/thumbnail/photon.d.ts.map +1 -0
  232. package/dist/src/thumbnail/photon.js +73 -0
  233. package/dist/src/thumbnail/photon.js.map +1 -0
  234. package/dist/src/thumbnail/types.d.ts +23 -0
  235. package/dist/src/thumbnail/types.d.ts.map +1 -0
  236. package/dist/src/thumbnail/types.js +22 -0
  237. package/dist/src/thumbnail/types.js.map +1 -0
  238. package/dist/tests/app/app.test.d.ts +2 -0
  239. package/dist/tests/app/app.test.d.ts.map +1 -0
  240. package/dist/tests/app/app.test.js +78 -0
  241. package/dist/tests/app/app.test.js.map +1 -0
  242. package/dist/tests/app/builder.test.d.ts +2 -0
  243. package/dist/tests/app/builder.test.d.ts.map +1 -0
  244. package/dist/tests/app/builder.test.js +69 -0
  245. package/dist/tests/app/builder.test.js.map +1 -0
  246. package/dist/tests/cache/cached-collection.test.d.ts +2 -0
  247. package/dist/tests/cache/cached-collection.test.d.ts.map +1 -0
  248. package/dist/tests/cache/cached-collection.test.js +244 -0
  249. package/dist/tests/cache/cached-collection.test.js.map +1 -0
  250. package/dist/tests/cache/collection-cache.test.d.ts +2 -0
  251. package/dist/tests/cache/collection-cache.test.d.ts.map +1 -0
  252. package/dist/tests/cache/collection-cache.test.js +73 -0
  253. package/dist/tests/cache/collection-cache.test.js.map +1 -0
  254. package/dist/tests/collection-service/collection-service.test.d.ts +2 -0
  255. package/dist/tests/collection-service/collection-service.test.d.ts.map +1 -0
  256. package/dist/tests/collection-service/collection-service.test.js +805 -0
  257. package/dist/tests/collection-service/collection-service.test.js.map +1 -0
  258. package/dist/tests/collection-service/input-schema.test.d.ts +2 -0
  259. package/dist/tests/collection-service/input-schema.test.d.ts.map +1 -0
  260. package/dist/tests/collection-service/input-schema.test.js +260 -0
  261. package/dist/tests/collection-service/input-schema.test.js.map +1 -0
  262. package/dist/tests/config/config.test.d.ts +2 -0
  263. package/dist/tests/config/config.test.d.ts.map +1 -0
  264. package/dist/tests/config/config.test.js +84 -0
  265. package/dist/tests/config/config.test.js.map +1 -0
  266. package/dist/tests/crypto/crypto.test.d.ts +2 -0
  267. package/dist/tests/crypto/crypto.test.d.ts.map +1 -0
  268. package/dist/tests/crypto/crypto.test.js +56 -0
  269. package/dist/tests/crypto/crypto.test.js.map +1 -0
  270. package/dist/tests/http/file-serve.test.d.ts +2 -0
  271. package/dist/tests/http/file-serve.test.d.ts.map +1 -0
  272. package/dist/tests/http/file-serve.test.js +210 -0
  273. package/dist/tests/http/file-serve.test.js.map +1 -0
  274. package/dist/tests/http/file-token.test.d.ts +2 -0
  275. package/dist/tests/http/file-token.test.d.ts.map +1 -0
  276. package/dist/tests/http/file-token.test.js +155 -0
  277. package/dist/tests/http/file-token.test.js.map +1 -0
  278. package/dist/tests/http/ip-middleware.test.d.ts +2 -0
  279. package/dist/tests/http/ip-middleware.test.d.ts.map +1 -0
  280. package/dist/tests/http/ip-middleware.test.js +58 -0
  281. package/dist/tests/http/ip-middleware.test.js.map +1 -0
  282. package/dist/tests/http/router.test.d.ts +2 -0
  283. package/dist/tests/http/router.test.d.ts.map +1 -0
  284. package/dist/tests/http/router.test.js +252 -0
  285. package/dist/tests/http/router.test.js.map +1 -0
  286. package/dist/tests/migrator/dialect-sqlite.test.d.ts +2 -0
  287. package/dist/tests/migrator/dialect-sqlite.test.d.ts.map +1 -0
  288. package/dist/tests/migrator/dialect-sqlite.test.js +90 -0
  289. package/dist/tests/migrator/dialect-sqlite.test.js.map +1 -0
  290. package/dist/tests/migrator/integration.test.d.ts +2 -0
  291. package/dist/tests/migrator/integration.test.d.ts.map +1 -0
  292. package/dist/tests/migrator/integration.test.js +180 -0
  293. package/dist/tests/migrator/integration.test.js.map +1 -0
  294. package/dist/tests/migrator/migrator.test.d.ts +2 -0
  295. package/dist/tests/migrator/migrator.test.d.ts.map +1 -0
  296. package/dist/tests/migrator/migrator.test.js +225 -0
  297. package/dist/tests/migrator/migrator.test.js.map +1 -0
  298. package/dist/tests/migrator/schema-diff.test.d.ts +2 -0
  299. package/dist/tests/migrator/schema-diff.test.d.ts.map +1 -0
  300. package/dist/tests/migrator/schema-diff.test.js +323 -0
  301. package/dist/tests/migrator/schema-diff.test.js.map +1 -0
  302. package/dist/tests/repository/repository.test.d.ts +2 -0
  303. package/dist/tests/repository/repository.test.d.ts.map +1 -0
  304. package/dist/tests/repository/repository.test.js +255 -0
  305. package/dist/tests/repository/repository.test.js.map +1 -0
  306. package/dist/tests/rule/compiler.test.d.ts +2 -0
  307. package/dist/tests/rule/compiler.test.d.ts.map +1 -0
  308. package/dist/tests/rule/compiler.test.js +226 -0
  309. package/dist/tests/rule/compiler.test.js.map +1 -0
  310. package/dist/tests/rule/enforcer.test.d.ts +2 -0
  311. package/dist/tests/rule/enforcer.test.d.ts.map +1 -0
  312. package/dist/tests/rule/enforcer.test.js +190 -0
  313. package/dist/tests/rule/enforcer.test.js.map +1 -0
  314. package/dist/tests/storage/storage.test.d.ts +2 -0
  315. package/dist/tests/storage/storage.test.d.ts.map +1 -0
  316. package/dist/tests/storage/storage.test.js +76 -0
  317. package/dist/tests/storage/storage.test.js.map +1 -0
  318. package/dist/tests/telemetry/instrumentation.test.d.ts +2 -0
  319. package/dist/tests/telemetry/instrumentation.test.d.ts.map +1 -0
  320. package/dist/tests/telemetry/instrumentation.test.js +226 -0
  321. package/dist/tests/telemetry/instrumentation.test.js.map +1 -0
  322. package/dist/tests/telemetry/logger.test.d.ts +2 -0
  323. package/dist/tests/telemetry/logger.test.d.ts.map +1 -0
  324. package/dist/tests/telemetry/logger.test.js +56 -0
  325. package/dist/tests/telemetry/logger.test.js.map +1 -0
  326. package/dist/tests/telemetry/tracer.test.d.ts +2 -0
  327. package/dist/tests/telemetry/tracer.test.d.ts.map +1 -0
  328. package/dist/tests/telemetry/tracer.test.js +63 -0
  329. package/dist/tests/telemetry/tracer.test.js.map +1 -0
  330. package/dist/tests/thumbnail/photon.test.d.ts +2 -0
  331. package/dist/tests/thumbnail/photon.test.d.ts.map +1 -0
  332. package/dist/tests/thumbnail/photon.test.js +478 -0
  333. package/dist/tests/thumbnail/photon.test.js.map +1 -0
  334. package/dist/tests/thumbnail/thumbnail.test.d.ts +2 -0
  335. package/dist/tests/thumbnail/thumbnail.test.d.ts.map +1 -0
  336. package/dist/tests/thumbnail/thumbnail.test.js +35 -0
  337. package/dist/tests/thumbnail/thumbnail.test.js.map +1 -0
  338. package/package.json +46 -0
@@ -0,0 +1,30 @@
1
+ import { SqlClient } from "@effect/sql";
2
+ import { Layer } from "effect";
3
+ import type { AnyCollectionDef } from "@gettersethya/mira-client";
4
+ import { Repository } from "../repository/repository.js";
5
+ import { CollectionService } from "../collection-service/collection-service.js";
6
+ import { FileStorage } from "../storage/storage.js";
7
+ import type { CollectionCacheConfigValues } from "./types.js";
8
+ /**
9
+ * Create a cached `CollectionService` layer that wraps the standard collection service.
10
+ *
11
+ * The cache is transparent — it implements the same `CollectionService` tag.
12
+ * List results and individual records are cached with a configurable TTL.
13
+ * Cache is invalidated (nuked) on any write operation (create/update/delete).
14
+ *
15
+ * This is the default service layer used by MiraApp — the standard
16
+ * `makeCollectionServiceLayer` is wrapped by this function internally.
17
+ *
18
+ * @param allCollections - Array of collection definitions
19
+ * @param config - Optional cache configuration (record TTL, list TTL, max entries)
20
+ * @returns A Layer providing CollectionService with caching
21
+ *
22
+ * @example
23
+ * makeCachedCollectionServiceLayer([Posts, Users])
24
+ * makeCachedCollectionServiceLayer([Posts], { recordTtlMs: 60_000 })
25
+ *
26
+ * @see CollectionService — the service tag
27
+ * @see makeCollectionServiceLayer — the underlying uncached service
28
+ */
29
+ export declare function makeCachedCollectionServiceLayer(allCollections: ReadonlyArray<AnyCollectionDef>, config?: CollectionCacheConfigValues): Layer.Layer<CollectionService, never, Repository | SqlClient.SqlClient | FileStorage>;
30
+ //# sourceMappingURL=cached-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cached-collection.d.ts","sourceRoot":"","sources":["../../../src/cache/cached-collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAU,KAAK,EAAkB,MAAM,QAAQ,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAA8B,MAAM,4CAA4C,CAAA;AAC1G,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAElD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AA2D7D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gCAAgC,CAC9C,cAAc,EAAE,aAAa,CAAC,gBAAgB,CAAC,EAC/C,MAAM,GAAE,2BAA2C,GAClD,KAAK,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC,SAAS,GAAG,WAAW,CAAC,CAmFvF"}
@@ -0,0 +1,107 @@
1
+ import { Effect, Layer, Option } from "effect";
2
+ import { CollectionService, makeCollectionServiceLayer } from "../collection-service/collection-service.js";
3
+ import { CollectionCache, makeCollectionCacheLayer } from "./collection-cache.js";
4
+ function serializeFilterNode(node) {
5
+ switch (node.op) {
6
+ case "eq":
7
+ case "neq":
8
+ case "gt":
9
+ case "gte":
10
+ case "lt":
11
+ case "lte":
12
+ return `${node.op}(${node.field},${String(node.value)})`;
13
+ case "in":
14
+ return `in(${node.field},[${node.values.map(String).join(",")}])`;
15
+ case "like":
16
+ return `like(${node.field},${node.value})`;
17
+ case "null":
18
+ case "not_null":
19
+ return `${node.op}(${node.field})`;
20
+ case "and":
21
+ case "or":
22
+ return `${node.op}(${serializeFilterNode(node.left)},${serializeFilterNode(node.right)})`;
23
+ case "not":
24
+ return `not(${serializeFilterNode(node.node)})`;
25
+ }
26
+ }
27
+ function stableViewKey(col, id, select, expand) {
28
+ const selectPart = select != null ? [...select].sort().join(",") : "";
29
+ const expandPart = expand != null ? [...expand].sort().join(",") : "";
30
+ return `${col}:${id}:${selectPart}|${expandPart}`;
31
+ }
32
+ function stableListKey(cursor, perPage, filter, sort, select, expand) {
33
+ const filterPart = filter !== undefined ? serializeFilterNode(filter) : "";
34
+ const sortPart = sort !== undefined ? `${sort.field}:${sort.direction}` : "";
35
+ const selectPart = select != null ? [...select].sort().join(",") : "";
36
+ const expandPart = expand != null ? [...expand].sort().join(",") : "";
37
+ return `${cursor ?? ""}|${perPage}|${filterPart}|${sortPart}|${selectPart}|${expandPart}`;
38
+ }
39
+ const defaultConfig = {
40
+ recordTtlMs: 30_000,
41
+ listTtlMs: 10_000,
42
+ maxRecords: 50_000,
43
+ maxLists: 5_000,
44
+ };
45
+ /**
46
+ * Create a cached `CollectionService` layer that wraps the standard collection service.
47
+ *
48
+ * The cache is transparent — it implements the same `CollectionService` tag.
49
+ * List results and individual records are cached with a configurable TTL.
50
+ * Cache is invalidated (nuked) on any write operation (create/update/delete).
51
+ *
52
+ * This is the default service layer used by MiraApp — the standard
53
+ * `makeCollectionServiceLayer` is wrapped by this function internally.
54
+ *
55
+ * @param allCollections - Array of collection definitions
56
+ * @param config - Optional cache configuration (record TTL, list TTL, max entries)
57
+ * @returns A Layer providing CollectionService with caching
58
+ *
59
+ * @example
60
+ * makeCachedCollectionServiceLayer([Posts, Users])
61
+ * makeCachedCollectionServiceLayer([Posts], { recordTtlMs: 60_000 })
62
+ *
63
+ * @see CollectionService — the service tag
64
+ * @see makeCollectionServiceLayer — the underlying uncached service
65
+ */
66
+ export function makeCachedCollectionServiceLayer(allCollections, config = defaultConfig) {
67
+ return Layer.effect(CollectionService, Effect.gen(function* () {
68
+ const svc = yield* CollectionService;
69
+ const cache = yield* CollectionCache;
70
+ return CollectionService.of({
71
+ list: (collection, cursor, perPage, ctx, filter, sort, select, expand) => {
72
+ const key = `${collection.name}:${stableListKey(cursor, perPage, filter, sort, select, expand)}`;
73
+ return Effect.gen(function* () {
74
+ const cached = yield* cache.getList(key);
75
+ yield* Effect.currentSpan.pipe(Effect.tap((span) => Effect.sync(() => span.attribute("cache.hit", Option.isSome(cached)))), Effect.ignore);
76
+ if (Option.isSome(cached))
77
+ return cached.value;
78
+ const page = yield* svc.list(collection, cursor, perPage, ctx, filter, sort, select, expand);
79
+ yield* cache.putList(key, page);
80
+ return page;
81
+ }).pipe(Effect.withSpan("cache.list", {
82
+ kind: "internal",
83
+ attributes: { collection: collection.name },
84
+ }));
85
+ },
86
+ view: (collection, id, ctx, select, expand) => {
87
+ const key = stableViewKey(collection.name, id, select, expand);
88
+ return Effect.gen(function* () {
89
+ const cached = yield* cache.getRecord(key);
90
+ yield* Effect.currentSpan.pipe(Effect.tap((span) => Effect.sync(() => span.attribute("cache.hit", Option.isSome(cached)))), Effect.ignore);
91
+ if (Option.isSome(cached))
92
+ return cached.value;
93
+ const record = yield* svc.view(collection, id, ctx, select, expand);
94
+ yield* cache.putRecord(key, record);
95
+ return record;
96
+ }).pipe(Effect.withSpan("cache.view", {
97
+ kind: "internal",
98
+ attributes: { collection: collection.name },
99
+ }));
100
+ },
101
+ create: (collection, data, ctx) => svc.create(collection, data, ctx).pipe(Effect.tap(() => cache.nukeListsFor(collection.name))),
102
+ update: (collection, id, data, ctx) => svc.update(collection, id, data, ctx).pipe(Effect.tap(() => Effect.all([cache.invalidateRecord(collection.name, id), cache.nukeListsFor(collection.name)], { concurrency: "unbounded" }))),
103
+ delete: (collection, id, ctx) => svc.delete(collection, id, ctx).pipe(Effect.tap(() => Effect.all([cache.invalidateRecord(collection.name, id), cache.nukeListsFor(collection.name)], { concurrency: "unbounded" }))),
104
+ });
105
+ })).pipe(Layer.provide(Layer.merge(makeCollectionServiceLayer(allCollections), makeCollectionCacheLayer(config))));
106
+ }
107
+ //# sourceMappingURL=cached-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cached-collection.js","sourceRoot":"","sources":["../../../src/cache/cached-collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Context, Effect, Layer, Option } from "effect";
2
+ import type { CursorPage } from "../collection-service/context.js";
3
+ import type { RepoRecord } from "../repository/types.js";
4
+ import type { CollectionCacheConfigValues } from "./types.js";
5
+ declare const CollectionCache_base: Context.TagClass<CollectionCache, "CollectionCache", {
6
+ getRecord(key: string): Effect.Effect<Option.Option<RepoRecord>>;
7
+ putRecord(key: string, v: RepoRecord): Effect.Effect<void>;
8
+ invalidateRecord(col: string, id: string): Effect.Effect<void>;
9
+ getList(key: string): Effect.Effect<Option.Option<CursorPage>>;
10
+ putList(key: string, v: CursorPage): Effect.Effect<void>;
11
+ nukeListsFor(col: string): Effect.Effect<void>;
12
+ }>;
13
+ export declare class CollectionCache extends CollectionCache_base {
14
+ }
15
+ export declare function makeCollectionCacheLayer(config: CollectionCacheConfigValues): Layer.Layer<CollectionCache>;
16
+ export {};
17
+ //# sourceMappingURL=collection-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-cache.d.ts","sourceRoot":"","sources":["../../../src/cache/collection-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAW,KAAK,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,KAAK,EAAc,2BAA2B,EAAE,MAAM,YAAY,CAAA;;mBAKtD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;mBACjD,MAAM,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;0BACpC,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;iBACjD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;iBACjD,MAAM,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;sBACtC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;;AARlD,qBAAa,eAAgB,SAAQ,oBAUlC;CAAG;AAoCN,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,2BAA2B,GAClC,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,CA4B9B"}
@@ -0,0 +1,37 @@
1
+ import { Context, Effect, HashMap, Layer, Option, Ref } from "effect";
2
+ export class CollectionCache extends Context.Tag("CollectionCache")() {
3
+ }
4
+ const get = (ref, key) => Ref.get(ref).pipe(Effect.map(HashMap.get(key)), Effect.map(Option.filter((e) => e.expiresAt > Date.now())), Effect.map(Option.map((e) => e.value)));
5
+ const put = (ref, key, value, ttlMs, maxSize) => {
6
+ const now = Date.now();
7
+ const entry = { value, insertedAt: now, expiresAt: now + ttlMs };
8
+ return Ref.update(ref, (map) => {
9
+ const inserted = HashMap.set(map, key, entry);
10
+ if (HashMap.size(inserted) <= maxSize)
11
+ return inserted;
12
+ let oldestKey;
13
+ let oldestTime = Infinity;
14
+ for (const [k, v] of inserted) {
15
+ if (v.insertedAt < oldestTime) {
16
+ oldestTime = v.insertedAt;
17
+ oldestKey = k;
18
+ }
19
+ }
20
+ return oldestKey !== undefined ? HashMap.remove(inserted, oldestKey) : inserted;
21
+ });
22
+ };
23
+ export function makeCollectionCacheLayer(config) {
24
+ return Layer.effect(CollectionCache, Effect.gen(function* () {
25
+ const recordRef = yield* Ref.make(HashMap.empty());
26
+ const listRef = yield* Ref.make(HashMap.empty());
27
+ return CollectionCache.of({
28
+ getRecord: (key) => get(recordRef, key),
29
+ putRecord: (key, v) => put(recordRef, key, v, config.recordTtlMs, config.maxRecords),
30
+ invalidateRecord: (col, id) => Ref.update(recordRef, (map) => HashMap.filter(map, (_, key) => !key.startsWith(`${col}:${id}:`))),
31
+ getList: (key) => get(listRef, key),
32
+ putList: (key, v) => put(listRef, key, v, config.listTtlMs, config.maxLists),
33
+ nukeListsFor: (col) => Ref.update(listRef, (map) => HashMap.filter(map, (_, key) => !key.startsWith(`${col}:`))),
34
+ });
35
+ }));
36
+ }
37
+ //# sourceMappingURL=collection-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-cache.js","sourceRoot":"","sources":["../../../src/cache/collection-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { CollectionCache, makeCollectionCacheLayer } from "./collection-cache.js";
2
+ export { makeCachedCollectionServiceLayer } from "./cached-collection.js";
3
+ export type { CacheEntry, CollectionCacheConfigValues } from "./types.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,wBAAwB,CAAA;AACzE,YAAY,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { CollectionCache, makeCollectionCacheLayer } from "./collection-cache.js";
2
+ export { makeCachedCollectionServiceLayer } from "./cached-collection.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,wBAAwB,CAAA"}
@@ -0,0 +1,12 @@
1
+ export interface CacheEntry<A> {
2
+ value: A;
3
+ insertedAt: number;
4
+ expiresAt: number;
5
+ }
6
+ export interface CollectionCacheConfigValues {
7
+ recordTtlMs: number;
8
+ listTtlMs: number;
9
+ maxRecords: number;
10
+ maxLists: number;
11
+ }
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cache/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAA;IACR,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/cache/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,62 @@
1
+ import { SqlClient } from "@effect/sql";
2
+ import { Context, Effect, Layer } from "effect";
3
+ import type { AnyCollectionDef } from "@gettersethya/mira-client";
4
+ import type { FilterNode } from "@gettersethya/mira-client";
5
+ import { Repository } from "../repository/repository.js";
6
+ import type { RepoRecord, SortOrder } from "../repository/types.js";
7
+ import { FileStorage } from "../storage/storage.js";
8
+ import type { CursorPage, RequestCtx } from "./context.js";
9
+ import type { CollectionError } from "./errors.js";
10
+ declare const CollectionService_base: Context.TagClass<CollectionService, "CollectionService", {
11
+ list(collection: AnyCollectionDef, cursor: number | null, perPage: number, ctx: RequestCtx, filter?: FilterNode, sort?: SortOrder, select?: ReadonlyArray<string> | null, expand?: ReadonlyArray<string> | null): Effect.Effect<CursorPage, CollectionError>;
12
+ view(collection: AnyCollectionDef, id: string, ctx: RequestCtx, select?: ReadonlyArray<string> | null, expand?: ReadonlyArray<string> | null): Effect.Effect<RepoRecord, CollectionError>;
13
+ create(collection: AnyCollectionDef, data: RepoRecord, ctx: RequestCtx): Effect.Effect<RepoRecord, CollectionError>;
14
+ update(collection: AnyCollectionDef, id: string, data: RepoRecord, ctx: RequestCtx): Effect.Effect<RepoRecord, CollectionError>;
15
+ delete(collection: AnyCollectionDef, id: string, ctx: RequestCtx): Effect.Effect<void, CollectionError>;
16
+ }>;
17
+ /**
18
+ * Collection Service tag — the core business-logic layer sitting between
19
+ * the HTTP router and the repository.
20
+ *
21
+ * Each method performs:
22
+ * - Schema validation (field types, required fields, constraints via Effect Schema)
23
+ * - Access rule enforcement (compiles and applies x-rules)
24
+ * - System field management (seqId, created, updated timestamps)
25
+ * - Hidden/read-only field stripping for responses
26
+ * - Cursor-based pagination for list operations
27
+ * - File cleanup on update/delete (best-effort)
28
+ *
29
+ * @example
30
+ * import { CollectionService } from "@gettersethya/mira"
31
+ *
32
+ * Effect.gen(function* () {
33
+ * const svc = yield* CollectionService
34
+ * const page = yield* svc.list(postsDef, null, 20, ctx, undefined, { field: "seqId", direction: "asc" })
35
+ * })
36
+ *
37
+ * @see makeCollectionServiceLayer — factory function
38
+ * @see Repository — the underlying data access layer
39
+ */
40
+ export declare class CollectionService extends CollectionService_base {
41
+ }
42
+ /**
43
+ * Create a `CollectionService` layer for a given set of collection definitions.
44
+ * Each collection gets its own validated service instance with per-collection
45
+ * rules, field schemas, and system field handling.
46
+ *
47
+ * The layer depends on `Repository`, `SqlClient`, and `FileStorage`.
48
+ *
49
+ * @param allCollections - Array of collection definitions
50
+ * @returns A Layer providing CollectionService
51
+ *
52
+ * @example
53
+ * Layer.provideMerge(makeCollectionServiceLayer([Posts, Users]))
54
+ *
55
+ * @see CollectionService — the service tag
56
+ * @see makeCachedCollectionServiceLayer — wrapping layer that adds caching
57
+ */
58
+ export declare function makeCollectionServiceLayer(allCollections: ReadonlyArray<AnyCollectionDef>): Layer.Layer<CollectionService, never, Repository | SqlClient.SqlClient | FileStorage>;
59
+ /** @deprecated Use makeCollectionServiceLayer(allCollections) */
60
+ export declare const CollectionServiceLive: Layer.Layer<CollectionService, never, FileStorage | SqlClient.SqlClient | Repository>;
61
+ export {};
62
+ //# sourceMappingURL=collection-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-service.d.ts","sourceRoot":"","sources":["../../../src/collection-service/collection-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAkB,MAAM,QAAQ,CAAA;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,2BAA2B,CAAA;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,KAAK,EAAa,UAAU,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGlD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;;qBAgChC,gBAAgB,UACpB,MAAM,GAAG,IAAI,WACZ,MAAM,OACV,UAAU,WACN,UAAU,SACZ,SAAS,WACP,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,WAC5B,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,GACpC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC;qBAG/B,gBAAgB,MACxB,MAAM,OACL,UAAU,WACN,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,WAC5B,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,GACpC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC;uBAE1B,gBAAgB,QAAQ,UAAU,OAAO,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC;uBAGrG,gBAAgB,MACxB,MAAM,QACJ,UAAU,OACX,UAAU,GACd,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC;uBAE1B,gBAAgB,MAAM,MAAM,OAAO,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC;;AAtD3G;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,iBAAkB,SAAQ,sBAiCpC;CAAG;AAqGN;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CACxC,cAAc,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAC9C,KAAK,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC,SAAS,GAAG,WAAW,CAAC,CAyOvF;AAED,iEAAiE;AACjE,eAAO,MAAM,qBAAqB,uFAAiC,CAAA"}
@@ -0,0 +1,267 @@
1
+ import { SqlClient } from "@effect/sql";
2
+ import { unsafeFragment } from "@effect/sql/Statement";
3
+ import { Context, Effect, Layer, Option, Schema } from "effect";
4
+ import { filterNodeToWhereClause } from "@gettersethya/mira-client";
5
+ import { enforcerForAction } from "../rule/enforcer.js";
6
+ import { Repository } from "../repository/repository.js";
7
+ import { FileStorage } from "../storage/storage.js";
8
+ import { makeRowDecoder } from "./decode.js";
9
+ import { ForbiddenError, NotFoundError, ReadOnlyError, ValidationError } from "./errors.js";
10
+ import { buildInputSchemas, parseErrToValidationError } from "./input-schema.js";
11
+ import { andWhere, cursorClause, idClause, resolveCtxPlaceholders, resolveFieldRefs } from "./where.js";
12
+ /**
13
+ * Collection Service tag — the core business-logic layer sitting between
14
+ * the HTTP router and the repository.
15
+ *
16
+ * Each method performs:
17
+ * - Schema validation (field types, required fields, constraints via Effect Schema)
18
+ * - Access rule enforcement (compiles and applies x-rules)
19
+ * - System field management (seqId, created, updated timestamps)
20
+ * - Hidden/read-only field stripping for responses
21
+ * - Cursor-based pagination for list operations
22
+ * - File cleanup on update/delete (best-effort)
23
+ *
24
+ * @example
25
+ * import { CollectionService } from "@gettersethya/mira"
26
+ *
27
+ * Effect.gen(function* () {
28
+ * const svc = yield* CollectionService
29
+ * const page = yield* svc.list(postsDef, null, 20, ctx, undefined, { field: "seqId", direction: "asc" })
30
+ * })
31
+ *
32
+ * @see makeCollectionServiceLayer — factory function
33
+ * @see Repository — the underlying data access layer
34
+ */
35
+ export class CollectionService extends Context.Tag("CollectionService")() {
36
+ }
37
+ function resolveFields(schema, userSelect) {
38
+ const nonHidden = Object.entries(schema.properties)
39
+ .filter(([, p]) => !p["x-hidden"])
40
+ .map(([k]) => k);
41
+ if (userSelect === null)
42
+ return nonHidden;
43
+ // Intersect with non-hidden fields
44
+ const nonHiddenSet = new Set(nonHidden);
45
+ const selected = userSelect.filter((f) => nonHiddenSet.has(f));
46
+ // Always include core system fields needed for the response
47
+ const always = new Set(["id", "created", "updated"]);
48
+ for (const a of always) {
49
+ if (!selected.includes(a)) {
50
+ selected.push(a);
51
+ }
52
+ }
53
+ return selected;
54
+ }
55
+ function resolveExpand(schema, expandFieldNames, allCollections) {
56
+ if (expandFieldNames === null)
57
+ return [];
58
+ const collectionMap = new Map(allCollections.map((c) => [c.name, c]));
59
+ const result = [];
60
+ for (const name of expandFieldNames) {
61
+ const prop = schema.properties[name];
62
+ if (!prop || prop["x-kind"] !== "relation")
63
+ continue;
64
+ if (!prop["x-collection"])
65
+ continue;
66
+ const target = collectionMap.get(prop["x-collection"]);
67
+ if (!target)
68
+ continue;
69
+ const targetColumns = resolveFields(target.schema, null);
70
+ result.push({ localField: name, targetTable: prop["x-collection"], targetColumns });
71
+ }
72
+ return result;
73
+ }
74
+ function rejectSystemFields(data, schema, collectionName) {
75
+ const sysKeys = Object.keys(data).filter((k) => schema.properties[k]?.["x-system"] === true);
76
+ if (sysKeys.length === 0)
77
+ return Effect.void;
78
+ return Effect.fail(new ValidationError({
79
+ collection: collectionName,
80
+ issues: [`Fields are read-only: ${sysKeys.join(", ")}`]
81
+ }));
82
+ }
83
+ function extractFileKeys(record, schema) {
84
+ return Object.entries(schema.properties)
85
+ .filter(([, prop]) => prop["x-kind"] === "file")
86
+ .map(([field]) => record[field])
87
+ .filter((v) => typeof v === "string" && v.length > 0);
88
+ }
89
+ function extractReplacedFileKeys(existing, patch, schema) {
90
+ return Object.entries(schema.properties)
91
+ .filter(([, prop]) => prop["x-kind"] === "file")
92
+ .flatMap(([field]) => {
93
+ const oldKey = existing[field];
94
+ const newKey = patch[field];
95
+ if (typeof oldKey === "string" && oldKey.length > 0 && field in patch && newKey !== oldKey) {
96
+ return [oldKey];
97
+ }
98
+ return [];
99
+ });
100
+ }
101
+ function compileRule(collection, action, ctx) {
102
+ const result = enforcerForAction(collection.schema, action);
103
+ if (result === null) {
104
+ return Effect.fail(new ForbiddenError({ collection: collection.name, action }));
105
+ }
106
+ return resolveCtxPlaceholders(result, ctx, collection.name, action);
107
+ }
108
+ /**
109
+ * Create a `CollectionService` layer for a given set of collection definitions.
110
+ * Each collection gets its own validated service instance with per-collection
111
+ * rules, field schemas, and system field handling.
112
+ *
113
+ * The layer depends on `Repository`, `SqlClient`, and `FileStorage`.
114
+ *
115
+ * @param allCollections - Array of collection definitions
116
+ * @returns A Layer providing CollectionService
117
+ *
118
+ * @example
119
+ * Layer.provideMerge(makeCollectionServiceLayer([Posts, Users]))
120
+ *
121
+ * @see CollectionService — the service tag
122
+ * @see makeCachedCollectionServiceLayer — wrapping layer that adds caching
123
+ */
124
+ export function makeCollectionServiceLayer(allCollections) {
125
+ return Layer.effect(CollectionService, Effect.gen(function* () {
126
+ const repo = yield* Repository;
127
+ const sql = yield* SqlClient.SqlClient;
128
+ const fileStorage = yield* FileStorage;
129
+ const decoderMap = new Map(allCollections.map((c) => [c.name, makeRowDecoder(c.schema)]));
130
+ const inputSchemaMap = new Map(allCollections.map((c) => [c.name, buildInputSchemas(c)]));
131
+ const getInputSchemas = (col) => inputSchemaMap.get(col.name) ?? buildInputSchemas(col);
132
+ const decodeRow = (collection, record) => (decoderMap.get(collection.name) ?? Effect.succeed)(record);
133
+ const list = (collection, cursor, perPage, ctx, filter, sort, select, expand) => Effect.gen(function* () {
134
+ const ruleWhere = yield* compileRule(collection, "list", ctx);
135
+ const userFilter = filter !== undefined ? yield* filterNodeToWhereClause(filter, collection.schema, collection.name) : null;
136
+ const where = userFilter !== null ? andWhere(ruleWhere, userFilter) : ruleWhere;
137
+ const combined = cursor !== null ? andWhere(where, cursorClause(cursor)) : where;
138
+ const fields = resolveFields(collection.schema, select ?? null);
139
+ const expandDefs = resolveExpand(collection.schema, expand ?? null, allCollections);
140
+ const fieldsWithExpand = [...new Set([...fields, ...expandDefs.map((e) => e.localField)])];
141
+ // seqId is x-hidden but must be fetched for cursor-based pagination
142
+ const fieldsForQuery = fieldsWithExpand.includes("seqId") ? fieldsWithExpand : [...fieldsWithExpand, "seqId"];
143
+ const rows = yield* repo.list(collection.name, perPage, {
144
+ where: combined,
145
+ sort: sort ?? { field: "seqId", direction: "asc" },
146
+ fields: fieldsForQuery,
147
+ expand: expandDefs
148
+ });
149
+ const lastRow = rows.items.at(-1);
150
+ const rawSeqId = lastRow?.["seqId"];
151
+ const lastSeqId = typeof rawSeqId === "number" ? rawSeqId : null;
152
+ const nextCursor = rows.items.length === perPage ? lastSeqId : null;
153
+ // Strip seqId — it's internal and must not appear in API responses
154
+ const items = yield* Effect.forEach(rows.items.map((r) => {
155
+ const copy = { ...r };
156
+ delete copy["seqId"];
157
+ return copy;
158
+ }), (r) => decodeRow(collection, r));
159
+ return { items, nextCursor };
160
+ }).pipe(Effect.withSpan("collection.list", {
161
+ kind: "internal",
162
+ attributes: { collection: collection.name }
163
+ }));
164
+ const view = (collection, id, ctx, select, expand) => Effect.gen(function* () {
165
+ const ruleWhere = yield* compileRule(collection, "view", ctx);
166
+ const combined = andWhere(ruleWhere, idClause(id));
167
+ const fields = resolveFields(collection.schema, select ?? null);
168
+ const expandDefs = resolveExpand(collection.schema, expand ?? null, allCollections);
169
+ const fieldsWithExpand = [...new Set([...fields, ...expandDefs.map((e) => e.localField)])];
170
+ const rows = yield* repo.viewFilter(collection.name, {
171
+ where: combined,
172
+ fields: fieldsWithExpand,
173
+ expand: expandDefs
174
+ });
175
+ if (rows.length === 0) {
176
+ return yield* new NotFoundError({ collection: collection.name, id });
177
+ }
178
+ return yield* decodeRow(collection, rows[0]);
179
+ }).pipe(Effect.withSpan("collection.view", {
180
+ kind: "internal",
181
+ attributes: { collection: collection.name }
182
+ }));
183
+ const create = (collection, data, ctx) => Effect.gen(function* () {
184
+ if (collection.schema["x-collection-kind"] === "view") {
185
+ return yield* new ReadOnlyError({ collection: collection.name });
186
+ }
187
+ yield* rejectSystemFields(data, collection.schema, collection.name);
188
+ const schemas = getInputSchemas(collection);
189
+ const cleaned = yield* Schema.decodeUnknown(schemas.create)(data).pipe(Effect.mapError(parseErrToValidationError(collection.name)));
190
+ const ruleWhere = yield* compileRule(collection, "create", ctx);
191
+ // Pre-check: evaluate the create rule against the payload (no table needed).
192
+ const payloadBound = resolveFieldRefs(ruleWhere, cleaned);
193
+ const where = unsafeFragment(payloadBound.sql, payloadBound.params);
194
+ const check = yield* sql `SELECT 1 AS ok WHERE ${where}`;
195
+ if (check.length === 0) {
196
+ return yield* new ForbiddenError({ collection: collection.name, action: "create" });
197
+ }
198
+ const row = yield* repo.create(collection.name, cleaned);
199
+ return yield* decodeRow(collection, row);
200
+ }).pipe(Effect.withSpan("collection.create", {
201
+ kind: "internal",
202
+ attributes: { collection: collection.name }
203
+ }));
204
+ const update = (collection, id, data, ctx) => Effect.gen(function* () {
205
+ if (collection.schema["x-collection-kind"] === "view") {
206
+ return yield* new ReadOnlyError({ collection: collection.name });
207
+ }
208
+ yield* rejectSystemFields(data, collection.schema, collection.name);
209
+ const schemas = getInputSchemas(collection);
210
+ const cleaned = yield* Schema.decodeUnknown(schemas.update)(data).pipe(Effect.mapError(parseErrToValidationError(collection.name)));
211
+ const ruleWhere = yield* compileRule(collection, "update", ctx);
212
+ // Existence check first — distinguish NotFound from Forbidden
213
+ const existing = yield* repo.view(collection.name, id);
214
+ if (Option.isNone(existing)) {
215
+ return yield* new NotFoundError({ collection: collection.name, id });
216
+ }
217
+ // Rule check against this specific row
218
+ const combined = andWhere(ruleWhere, idClause(id));
219
+ const allowed = yield* repo.viewFilter(collection.name, { where: combined });
220
+ if (allowed.length === 0) {
221
+ return yield* new ForbiddenError({ collection: collection.name, action: "update" });
222
+ }
223
+ const updated = yield* repo.update(collection.name, id, cleaned);
224
+ // Best-effort: delete old files and their thumbnails for any replaced file fields.
225
+ const oldKeys = extractReplacedFileKeys(existing.value, cleaned, collection.schema);
226
+ yield* Effect.forEach(oldKeys, (key) => Effect.gen(function* () {
227
+ yield* fileStorage.delete(key).pipe(Effect.orElse(() => Effect.void));
228
+ const thumbKeys = yield* fileStorage.list(`_thumbs/${key}/`).pipe(Effect.orElseSucceed(() => []));
229
+ yield* Effect.forEach(thumbKeys, (tk) => fileStorage.delete(tk).pipe(Effect.orElse(() => Effect.void)), { concurrency: "unbounded" });
230
+ }), { concurrency: "unbounded" });
231
+ return yield* decodeRow(collection, Option.getOrElse(updated, () => existing.value));
232
+ }).pipe(Effect.withSpan("collection.update", {
233
+ kind: "internal",
234
+ attributes: { collection: collection.name }
235
+ }));
236
+ const deleteImpl = (collection, id, ctx) => Effect.gen(function* () {
237
+ if (collection.schema["x-collection-kind"] === "view") {
238
+ return yield* new ReadOnlyError({ collection: collection.name });
239
+ }
240
+ const ruleWhere = yield* compileRule(collection, "delete", ctx);
241
+ const existing = yield* repo.view(collection.name, id);
242
+ if (Option.isNone(existing)) {
243
+ return yield* new NotFoundError({ collection: collection.name, id });
244
+ }
245
+ const combined = andWhere(ruleWhere, idClause(id));
246
+ const allowed = yield* repo.viewFilter(collection.name, { where: combined });
247
+ if (allowed.length === 0) {
248
+ return yield* new ForbiddenError({ collection: collection.name, action: "delete" });
249
+ }
250
+ yield* repo.delete(collection.name, id);
251
+ // Best-effort: delete files and their thumbnails after the record is gone.
252
+ const keys = extractFileKeys(existing.value, collection.schema);
253
+ yield* Effect.forEach(keys, (key) => Effect.gen(function* () {
254
+ yield* fileStorage.delete(key).pipe(Effect.orElse(() => Effect.void));
255
+ const thumbKeys = yield* fileStorage.list(`_thumbs/${key}/`).pipe(Effect.orElseSucceed(() => []));
256
+ yield* Effect.forEach(thumbKeys, (tk) => fileStorage.delete(tk).pipe(Effect.orElse(() => Effect.void)), { concurrency: "unbounded" });
257
+ }), { concurrency: "unbounded" });
258
+ }).pipe(Effect.withSpan("collection.delete", {
259
+ kind: "internal",
260
+ attributes: { collection: collection.name }
261
+ }));
262
+ return { list, view, create, update, delete: deleteImpl };
263
+ }));
264
+ }
265
+ /** @deprecated Use makeCollectionServiceLayer(allCollections) */
266
+ export const CollectionServiceLive = makeCollectionServiceLayer([]);
267
+ //# sourceMappingURL=collection-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-service.js","sourceRoot":"","sources":["../../../src/collection-service/collection-service.ts"],"names":[],"mappings":"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"}