@jini-ai/cms 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +84 -0
  3. package/dist/content-types/agent-tools.d.ts +65 -0
  4. package/dist/content-types/agent-tools.d.ts.map +1 -0
  5. package/dist/content-types/agent-tools.js +172 -0
  6. package/dist/content-types/agent-tools.js.map +1 -0
  7. package/dist/content-types/cleanup.d.ts +118 -0
  8. package/dist/content-types/cleanup.d.ts.map +1 -0
  9. package/dist/content-types/cleanup.js +65 -0
  10. package/dist/content-types/cleanup.js.map +1 -0
  11. package/dist/content-types/errors.d.ts +90 -0
  12. package/dist/content-types/errors.d.ts.map +1 -0
  13. package/dist/content-types/errors.js +119 -0
  14. package/dist/content-types/errors.js.map +1 -0
  15. package/dist/content-types/field-defs.d.ts +25 -0
  16. package/dist/content-types/field-defs.d.ts.map +1 -0
  17. package/dist/content-types/field-defs.js +155 -0
  18. package/dist/content-types/field-defs.js.map +1 -0
  19. package/dist/content-types/index-provisioning.d.ts +94 -0
  20. package/dist/content-types/index-provisioning.d.ts.map +1 -0
  21. package/dist/content-types/index-provisioning.js +133 -0
  22. package/dist/content-types/index-provisioning.js.map +1 -0
  23. package/dist/content-types/index.d.ts +63 -0
  24. package/dist/content-types/index.d.ts.map +1 -0
  25. package/dist/content-types/index.js +36 -0
  26. package/dist/content-types/index.js.map +1 -0
  27. package/dist/content-types/lifecycle-dispatch.d.ts +38 -0
  28. package/dist/content-types/lifecycle-dispatch.d.ts.map +1 -0
  29. package/dist/content-types/lifecycle-dispatch.js +28 -0
  30. package/dist/content-types/lifecycle-dispatch.js.map +1 -0
  31. package/dist/content-types/lifecycle.d.ts +104 -0
  32. package/dist/content-types/lifecycle.d.ts.map +1 -0
  33. package/dist/content-types/lifecycle.js +143 -0
  34. package/dist/content-types/lifecycle.js.map +1 -0
  35. package/dist/content-types/list.d.ts +44 -0
  36. package/dist/content-types/list.d.ts.map +1 -0
  37. package/dist/content-types/list.js +13 -0
  38. package/dist/content-types/list.js.map +1 -0
  39. package/dist/content-types/repo.memory.d.ts +72 -0
  40. package/dist/content-types/repo.memory.d.ts.map +1 -0
  41. package/dist/content-types/repo.memory.js +71 -0
  42. package/dist/content-types/repo.memory.js.map +1 -0
  43. package/dist/content-types/tool-registrations.d.ts +65 -0
  44. package/dist/content-types/tool-registrations.d.ts.map +1 -0
  45. package/dist/content-types/tool-registrations.js +180 -0
  46. package/dist/content-types/tool-registrations.js.map +1 -0
  47. package/dist/content-types/types.d.ts +78 -0
  48. package/dist/content-types/types.d.ts.map +1 -0
  49. package/dist/content-types/types.js +32 -0
  50. package/dist/content-types/types.js.map +1 -0
  51. package/dist/content-types/write-service.d.ts +141 -0
  52. package/dist/content-types/write-service.d.ts.map +1 -0
  53. package/dist/content-types/write-service.js +180 -0
  54. package/dist/content-types/write-service.js.map +1 -0
  55. package/dist/core/commands/change-set.d.ts +98 -0
  56. package/dist/core/commands/change-set.d.ts.map +1 -0
  57. package/dist/core/commands/change-set.js +2 -0
  58. package/dist/core/commands/change-set.js.map +1 -0
  59. package/dist/core/commands/command.d.ts +168 -0
  60. package/dist/core/commands/command.d.ts.map +1 -0
  61. package/dist/core/commands/command.js +173 -0
  62. package/dist/core/commands/command.js.map +1 -0
  63. package/dist/core/index.d.ts +45 -0
  64. package/dist/core/index.d.ts.map +1 -0
  65. package/dist/core/index.js +43 -0
  66. package/dist/core/index.js.map +1 -0
  67. package/dist/core/ports.d.ts +139 -0
  68. package/dist/core/ports.d.ts.map +1 -0
  69. package/dist/core/ports.js +2 -0
  70. package/dist/core/ports.js.map +1 -0
  71. package/dist/core/tools/registration-kit.d.ts +308 -0
  72. package/dist/core/tools/registration-kit.d.ts.map +1 -0
  73. package/dist/core/tools/registration-kit.js +381 -0
  74. package/dist/core/tools/registration-kit.js.map +1 -0
  75. package/dist/entries/agent-tools.d.ts +78 -0
  76. package/dist/entries/agent-tools.d.ts.map +1 -0
  77. package/dist/entries/agent-tools.js +158 -0
  78. package/dist/entries/agent-tools.js.map +1 -0
  79. package/dist/entries/errors.d.ts +43 -0
  80. package/dist/entries/errors.d.ts.map +1 -0
  81. package/dist/entries/errors.js +59 -0
  82. package/dist/entries/errors.js.map +1 -0
  83. package/dist/entries/field-validation.d.ts +70 -0
  84. package/dist/entries/field-validation.d.ts.map +1 -0
  85. package/dist/entries/field-validation.js +87 -0
  86. package/dist/entries/field-validation.js.map +1 -0
  87. package/dist/entries/index.d.ts +55 -0
  88. package/dist/entries/index.d.ts.map +1 -0
  89. package/dist/entries/index.js +38 -0
  90. package/dist/entries/index.js.map +1 -0
  91. package/dist/entries/lifecycle-dispatch.d.ts +15 -0
  92. package/dist/entries/lifecycle-dispatch.d.ts.map +1 -0
  93. package/dist/entries/lifecycle-dispatch.js +16 -0
  94. package/dist/entries/lifecycle-dispatch.js.map +1 -0
  95. package/dist/entries/list.d.ts +47 -0
  96. package/dist/entries/list.d.ts.map +1 -0
  97. package/dist/entries/list.js +12 -0
  98. package/dist/entries/list.js.map +1 -0
  99. package/dist/entries/repo.memory.d.ts +64 -0
  100. package/dist/entries/repo.memory.d.ts.map +1 -0
  101. package/dist/entries/repo.memory.js +73 -0
  102. package/dist/entries/repo.memory.js.map +1 -0
  103. package/dist/entries/tool-registrations.d.ts +52 -0
  104. package/dist/entries/tool-registrations.d.ts.map +1 -0
  105. package/dist/entries/tool-registrations.js +141 -0
  106. package/dist/entries/tool-registrations.js.map +1 -0
  107. package/dist/entries/types.d.ts +55 -0
  108. package/dist/entries/types.d.ts.map +1 -0
  109. package/dist/entries/types.js +2 -0
  110. package/dist/entries/types.js.map +1 -0
  111. package/dist/entries/write-service.d.ts +202 -0
  112. package/dist/entries/write-service.d.ts.map +1 -0
  113. package/dist/entries/write-service.js +204 -0
  114. package/dist/entries/write-service.js.map +1 -0
  115. package/dist/identity/admin-crud-service.d.ts +252 -0
  116. package/dist/identity/admin-crud-service.d.ts.map +1 -0
  117. package/dist/identity/admin-crud-service.js +437 -0
  118. package/dist/identity/admin-crud-service.js.map +1 -0
  119. package/dist/identity/agent-tool-input.d.ts +58 -0
  120. package/dist/identity/agent-tool-input.d.ts.map +1 -0
  121. package/dist/identity/agent-tool-input.js +126 -0
  122. package/dist/identity/agent-tool-input.js.map +1 -0
  123. package/dist/identity/agent-tools.d.ts +101 -0
  124. package/dist/identity/agent-tools.d.ts.map +1 -0
  125. package/dist/identity/agent-tools.js +290 -0
  126. package/dist/identity/agent-tools.js.map +1 -0
  127. package/dist/identity/auth-service.d.ts +87 -0
  128. package/dist/identity/auth-service.d.ts.map +1 -0
  129. package/dist/identity/auth-service.js +141 -0
  130. package/dist/identity/auth-service.js.map +1 -0
  131. package/dist/identity/authorize.d.ts +90 -0
  132. package/dist/identity/authorize.d.ts.map +1 -0
  133. package/dist/identity/authorize.js +94 -0
  134. package/dist/identity/authorize.js.map +1 -0
  135. package/dist/identity/grant-service.d.ts +198 -0
  136. package/dist/identity/grant-service.d.ts.map +1 -0
  137. package/dist/identity/grant-service.js +361 -0
  138. package/dist/identity/grant-service.js.map +1 -0
  139. package/dist/identity/hasher.d.ts +39 -0
  140. package/dist/identity/hasher.d.ts.map +1 -0
  141. package/dist/identity/hasher.js +39 -0
  142. package/dist/identity/hasher.js.map +1 -0
  143. package/dist/identity/index.d.ts +59 -0
  144. package/dist/identity/index.d.ts.map +1 -0
  145. package/dist/identity/index.js +51 -0
  146. package/dist/identity/index.js.map +1 -0
  147. package/dist/identity/password-policy.d.ts +58 -0
  148. package/dist/identity/password-policy.d.ts.map +1 -0
  149. package/dist/identity/password-policy.js +67 -0
  150. package/dist/identity/password-policy.js.map +1 -0
  151. package/dist/identity/permission-migrations.d.ts +86 -0
  152. package/dist/identity/permission-migrations.d.ts.map +1 -0
  153. package/dist/identity/permission-migrations.js +67 -0
  154. package/dist/identity/permission-migrations.js.map +1 -0
  155. package/dist/identity/permissions.d.ts +35 -0
  156. package/dist/identity/permissions.d.ts.map +1 -0
  157. package/dist/identity/permissions.js +603 -0
  158. package/dist/identity/permissions.js.map +1 -0
  159. package/dist/identity/ports.d.ts +201 -0
  160. package/dist/identity/ports.d.ts.map +1 -0
  161. package/dist/identity/ports.js +2 -0
  162. package/dist/identity/ports.js.map +1 -0
  163. package/dist/identity/repo.memory.d.ts +164 -0
  164. package/dist/identity/repo.memory.d.ts.map +1 -0
  165. package/dist/identity/repo.memory.js +224 -0
  166. package/dist/identity/repo.memory.js.map +1 -0
  167. package/dist/identity/seed.d.ts +42 -0
  168. package/dist/identity/seed.d.ts.map +1 -0
  169. package/dist/identity/seed.js +277 -0
  170. package/dist/identity/seed.js.map +1 -0
  171. package/dist/identity/tool-registrations.d.ts +50 -0
  172. package/dist/identity/tool-registrations.d.ts.map +1 -0
  173. package/dist/identity/tool-registrations.js +419 -0
  174. package/dist/identity/tool-registrations.js.map +1 -0
  175. package/dist/identity/types.d.ts +185 -0
  176. package/dist/identity/types.d.ts.map +1 -0
  177. package/dist/identity/types.js +64 -0
  178. package/dist/identity/types.js.map +1 -0
  179. package/dist/identity/username.d.ts +12 -0
  180. package/dist/identity/username.d.ts.map +1 -0
  181. package/dist/identity/username.js +14 -0
  182. package/dist/identity/username.js.map +1 -0
  183. package/dist/media/agent-tools.d.ts +66 -0
  184. package/dist/media/agent-tools.d.ts.map +1 -0
  185. package/dist/media/agent-tools.js +131 -0
  186. package/dist/media/agent-tools.js.map +1 -0
  187. package/dist/media/blob-gc-lock.d.ts +37 -0
  188. package/dist/media/blob-gc-lock.d.ts.map +1 -0
  189. package/dist/media/blob-gc-lock.js +55 -0
  190. package/dist/media/blob-gc-lock.js.map +1 -0
  191. package/dist/media/blob-gc.d.ts +246 -0
  192. package/dist/media/blob-gc.d.ts.map +1 -0
  193. package/dist/media/blob-gc.js +254 -0
  194. package/dist/media/blob-gc.js.map +1 -0
  195. package/dist/media/blob-key.d.ts +28 -0
  196. package/dist/media/blob-key.d.ts.map +1 -0
  197. package/dist/media/blob-key.js +11 -0
  198. package/dist/media/blob-key.js.map +1 -0
  199. package/dist/media/blob-store.fs.d.ts +23 -0
  200. package/dist/media/blob-store.fs.d.ts.map +1 -0
  201. package/dist/media/blob-store.fs.js +48 -0
  202. package/dist/media/blob-store.fs.js.map +1 -0
  203. package/dist/media/blob-store.memory.d.ts +22 -0
  204. package/dist/media/blob-store.memory.d.ts.map +1 -0
  205. package/dist/media/blob-store.memory.js +23 -0
  206. package/dist/media/blob-store.memory.js.map +1 -0
  207. package/dist/media/content-type-sniffer.d.ts +49 -0
  208. package/dist/media/content-type-sniffer.d.ts.map +1 -0
  209. package/dist/media/content-type-sniffer.js +141 -0
  210. package/dist/media/content-type-sniffer.js.map +1 -0
  211. package/dist/media/image-transformer.d.ts +45 -0
  212. package/dist/media/image-transformer.d.ts.map +1 -0
  213. package/dist/media/image-transformer.js +23 -0
  214. package/dist/media/image-transformer.js.map +1 -0
  215. package/dist/media/image-transformer.sharp.d.ts +26 -0
  216. package/dist/media/image-transformer.sharp.d.ts.map +1 -0
  217. package/dist/media/image-transformer.sharp.js +91 -0
  218. package/dist/media/image-transformer.sharp.js.map +1 -0
  219. package/dist/media/index.d.ts +43 -0
  220. package/dist/media/index.d.ts.map +1 -0
  221. package/dist/media/index.js +31 -0
  222. package/dist/media/index.js.map +1 -0
  223. package/dist/media/media-service.d.ts +244 -0
  224. package/dist/media/media-service.d.ts.map +1 -0
  225. package/dist/media/media-service.js +345 -0
  226. package/dist/media/media-service.js.map +1 -0
  227. package/dist/media/ports.d.ts +142 -0
  228. package/dist/media/ports.d.ts.map +1 -0
  229. package/dist/media/ports.js +2 -0
  230. package/dist/media/ports.js.map +1 -0
  231. package/dist/media/rendition-service.d.ts +66 -0
  232. package/dist/media/rendition-service.d.ts.map +1 -0
  233. package/dist/media/rendition-service.js +135 -0
  234. package/dist/media/rendition-service.js.map +1 -0
  235. package/dist/media/repo.memory.d.ts +107 -0
  236. package/dist/media/repo.memory.d.ts.map +1 -0
  237. package/dist/media/repo.memory.js +131 -0
  238. package/dist/media/repo.memory.js.map +1 -0
  239. package/dist/media/tool-registrations.d.ts +42 -0
  240. package/dist/media/tool-registrations.d.ts.map +1 -0
  241. package/dist/media/tool-registrations.js +121 -0
  242. package/dist/media/tool-registrations.js.map +1 -0
  243. package/dist/media/transform-lock.d.ts +36 -0
  244. package/dist/media/transform-lock.d.ts.map +1 -0
  245. package/dist/media/transform-lock.js +50 -0
  246. package/dist/media/transform-lock.js.map +1 -0
  247. package/dist/media/transform-registry.d.ts +103 -0
  248. package/dist/media/transform-registry.d.ts.map +1 -0
  249. package/dist/media/transform-registry.js +87 -0
  250. package/dist/media/transform-registry.js.map +1 -0
  251. package/dist/media/transform-types.d.ts +82 -0
  252. package/dist/media/transform-types.d.ts.map +1 -0
  253. package/dist/media/transform-types.js +47 -0
  254. package/dist/media/transform-types.js.map +1 -0
  255. package/dist/media/types.d.ts +150 -0
  256. package/dist/media/types.d.ts.map +1 -0
  257. package/dist/media/types.js +26 -0
  258. package/dist/media/types.js.map +1 -0
  259. package/dist/navigation/agent-tools.d.ts +90 -0
  260. package/dist/navigation/agent-tools.d.ts.map +1 -0
  261. package/dist/navigation/agent-tools.js +225 -0
  262. package/dist/navigation/agent-tools.js.map +1 -0
  263. package/dist/navigation/contracts.d.ts +98 -0
  264. package/dist/navigation/contracts.d.ts.map +1 -0
  265. package/dist/navigation/contracts.js +70 -0
  266. package/dist/navigation/contracts.js.map +1 -0
  267. package/dist/navigation/index.d.ts +39 -0
  268. package/dist/navigation/index.d.ts.map +1 -0
  269. package/dist/navigation/index.js +30 -0
  270. package/dist/navigation/index.js.map +1 -0
  271. package/dist/navigation/menu-service.d.ts +256 -0
  272. package/dist/navigation/menu-service.d.ts.map +1 -0
  273. package/dist/navigation/menu-service.js +382 -0
  274. package/dist/navigation/menu-service.js.map +1 -0
  275. package/dist/navigation/ports.d.ts +147 -0
  276. package/dist/navigation/ports.d.ts.map +1 -0
  277. package/dist/navigation/ports.js +2 -0
  278. package/dist/navigation/ports.js.map +1 -0
  279. package/dist/navigation/read-model.d.ts +11 -0
  280. package/dist/navigation/read-model.d.ts.map +1 -0
  281. package/dist/navigation/read-model.js +27 -0
  282. package/dist/navigation/read-model.js.map +1 -0
  283. package/dist/navigation/reconcile.d.ts +57 -0
  284. package/dist/navigation/reconcile.d.ts.map +1 -0
  285. package/dist/navigation/reconcile.js +33 -0
  286. package/dist/navigation/reconcile.js.map +1 -0
  287. package/dist/navigation/repo.memory.d.ts +137 -0
  288. package/dist/navigation/repo.memory.d.ts.map +1 -0
  289. package/dist/navigation/repo.memory.js +95 -0
  290. package/dist/navigation/repo.memory.js.map +1 -0
  291. package/dist/navigation/resolver.d.ts +110 -0
  292. package/dist/navigation/resolver.d.ts.map +1 -0
  293. package/dist/navigation/resolver.js +131 -0
  294. package/dist/navigation/resolver.js.map +1 -0
  295. package/dist/navigation/tool-registrations.d.ts +43 -0
  296. package/dist/navigation/tool-registrations.d.ts.map +1 -0
  297. package/dist/navigation/tool-registrations.js +126 -0
  298. package/dist/navigation/tool-registrations.js.map +1 -0
  299. package/dist/navigation/types.d.ts +207 -0
  300. package/dist/navigation/types.d.ts.map +1 -0
  301. package/dist/navigation/types.js +14 -0
  302. package/dist/navigation/types.js.map +1 -0
  303. package/dist/presentation/index.d.ts +15 -0
  304. package/dist/presentation/index.d.ts.map +1 -0
  305. package/dist/presentation/index.js +15 -0
  306. package/dist/presentation/index.js.map +1 -0
  307. package/dist/presentation/presentation.d.ts +72 -0
  308. package/dist/presentation/presentation.d.ts.map +1 -0
  309. package/dist/presentation/presentation.js +51 -0
  310. package/dist/presentation/presentation.js.map +1 -0
  311. package/dist/presentation/repo.memory.d.ts +9 -0
  312. package/dist/presentation/repo.memory.d.ts.map +1 -0
  313. package/dist/presentation/repo.memory.js +21 -0
  314. package/dist/presentation/repo.memory.js.map +1 -0
  315. package/dist/server/index.d.ts +28 -0
  316. package/dist/server/index.d.ts.map +1 -0
  317. package/dist/server/index.js +28 -0
  318. package/dist/server/index.js.map +1 -0
  319. package/dist/settings/agent-tools.d.ts +83 -0
  320. package/dist/settings/agent-tools.d.ts.map +1 -0
  321. package/dist/settings/agent-tools.js +200 -0
  322. package/dist/settings/agent-tools.js.map +1 -0
  323. package/dist/settings/agent-writable-preferences.d.ts +67 -0
  324. package/dist/settings/agent-writable-preferences.d.ts.map +1 -0
  325. package/dist/settings/agent-writable-preferences.js +144 -0
  326. package/dist/settings/agent-writable-preferences.js.map +1 -0
  327. package/dist/settings/change-feed.d.ts +74 -0
  328. package/dist/settings/change-feed.d.ts.map +1 -0
  329. package/dist/settings/change-feed.js +61 -0
  330. package/dist/settings/change-feed.js.map +1 -0
  331. package/dist/settings/definitions-dispatch.d.ts +51 -0
  332. package/dist/settings/definitions-dispatch.d.ts.map +1 -0
  333. package/dist/settings/definitions-dispatch.js +86 -0
  334. package/dist/settings/definitions-dispatch.js.map +1 -0
  335. package/dist/settings/dictionaries/index.d.ts +45 -0
  336. package/dist/settings/dictionaries/index.d.ts.map +1 -0
  337. package/dist/settings/dictionaries/index.js +69 -0
  338. package/dist/settings/dictionaries/index.js.map +1 -0
  339. package/dist/settings/dictionaries/settings-dialog.ar.d.ts +3 -0
  340. package/dist/settings/dictionaries/settings-dialog.ar.d.ts.map +1 -0
  341. package/dist/settings/dictionaries/settings-dialog.ar.js +28 -0
  342. package/dist/settings/dictionaries/settings-dialog.ar.js.map +1 -0
  343. package/dist/settings/dictionaries/settings-dialog.bn.d.ts +3 -0
  344. package/dist/settings/dictionaries/settings-dialog.bn.d.ts.map +1 -0
  345. package/dist/settings/dictionaries/settings-dialog.bn.js +28 -0
  346. package/dist/settings/dictionaries/settings-dialog.bn.js.map +1 -0
  347. package/dist/settings/dictionaries/settings-dialog.de.d.ts +3 -0
  348. package/dist/settings/dictionaries/settings-dialog.de.d.ts.map +1 -0
  349. package/dist/settings/dictionaries/settings-dialog.de.js +28 -0
  350. package/dist/settings/dictionaries/settings-dialog.de.js.map +1 -0
  351. package/dist/settings/dictionaries/settings-dialog.es.d.ts +3 -0
  352. package/dist/settings/dictionaries/settings-dialog.es.d.ts.map +1 -0
  353. package/dist/settings/dictionaries/settings-dialog.es.js +28 -0
  354. package/dist/settings/dictionaries/settings-dialog.es.js.map +1 -0
  355. package/dist/settings/dictionaries/settings-dialog.fa.d.ts +3 -0
  356. package/dist/settings/dictionaries/settings-dialog.fa.d.ts.map +1 -0
  357. package/dist/settings/dictionaries/settings-dialog.fa.js +28 -0
  358. package/dist/settings/dictionaries/settings-dialog.fa.js.map +1 -0
  359. package/dist/settings/dictionaries/settings-dialog.fr.d.ts +3 -0
  360. package/dist/settings/dictionaries/settings-dialog.fr.d.ts.map +1 -0
  361. package/dist/settings/dictionaries/settings-dialog.fr.js +28 -0
  362. package/dist/settings/dictionaries/settings-dialog.fr.js.map +1 -0
  363. package/dist/settings/dictionaries/settings-dialog.hi.d.ts +3 -0
  364. package/dist/settings/dictionaries/settings-dialog.hi.d.ts.map +1 -0
  365. package/dist/settings/dictionaries/settings-dialog.hi.js +28 -0
  366. package/dist/settings/dictionaries/settings-dialog.hi.js.map +1 -0
  367. package/dist/settings/dictionaries/settings-dialog.hu.d.ts +3 -0
  368. package/dist/settings/dictionaries/settings-dialog.hu.d.ts.map +1 -0
  369. package/dist/settings/dictionaries/settings-dialog.hu.js +28 -0
  370. package/dist/settings/dictionaries/settings-dialog.hu.js.map +1 -0
  371. package/dist/settings/dictionaries/settings-dialog.id.d.ts +3 -0
  372. package/dist/settings/dictionaries/settings-dialog.id.d.ts.map +1 -0
  373. package/dist/settings/dictionaries/settings-dialog.id.js +28 -0
  374. package/dist/settings/dictionaries/settings-dialog.id.js.map +1 -0
  375. package/dist/settings/dictionaries/settings-dialog.it.d.ts +3 -0
  376. package/dist/settings/dictionaries/settings-dialog.it.d.ts.map +1 -0
  377. package/dist/settings/dictionaries/settings-dialog.it.js +28 -0
  378. package/dist/settings/dictionaries/settings-dialog.it.js.map +1 -0
  379. package/dist/settings/dictionaries/settings-dialog.ja.d.ts +3 -0
  380. package/dist/settings/dictionaries/settings-dialog.ja.d.ts.map +1 -0
  381. package/dist/settings/dictionaries/settings-dialog.ja.js +28 -0
  382. package/dist/settings/dictionaries/settings-dialog.ja.js.map +1 -0
  383. package/dist/settings/dictionaries/settings-dialog.ko.d.ts +3 -0
  384. package/dist/settings/dictionaries/settings-dialog.ko.d.ts.map +1 -0
  385. package/dist/settings/dictionaries/settings-dialog.ko.js +28 -0
  386. package/dist/settings/dictionaries/settings-dialog.ko.js.map +1 -0
  387. package/dist/settings/dictionaries/settings-dialog.pl.d.ts +3 -0
  388. package/dist/settings/dictionaries/settings-dialog.pl.d.ts.map +1 -0
  389. package/dist/settings/dictionaries/settings-dialog.pl.js +28 -0
  390. package/dist/settings/dictionaries/settings-dialog.pl.js.map +1 -0
  391. package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts +3 -0
  392. package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts.map +1 -0
  393. package/dist/settings/dictionaries/settings-dialog.pt-BR.js +28 -0
  394. package/dist/settings/dictionaries/settings-dialog.pt-BR.js.map +1 -0
  395. package/dist/settings/dictionaries/settings-dialog.ru.d.ts +3 -0
  396. package/dist/settings/dictionaries/settings-dialog.ru.d.ts.map +1 -0
  397. package/dist/settings/dictionaries/settings-dialog.ru.js +28 -0
  398. package/dist/settings/dictionaries/settings-dialog.ru.js.map +1 -0
  399. package/dist/settings/dictionaries/settings-dialog.th.d.ts +3 -0
  400. package/dist/settings/dictionaries/settings-dialog.th.d.ts.map +1 -0
  401. package/dist/settings/dictionaries/settings-dialog.th.js +28 -0
  402. package/dist/settings/dictionaries/settings-dialog.th.js.map +1 -0
  403. package/dist/settings/dictionaries/settings-dialog.tr.d.ts +3 -0
  404. package/dist/settings/dictionaries/settings-dialog.tr.d.ts.map +1 -0
  405. package/dist/settings/dictionaries/settings-dialog.tr.js +28 -0
  406. package/dist/settings/dictionaries/settings-dialog.tr.js.map +1 -0
  407. package/dist/settings/dictionaries/settings-dialog.uk.d.ts +3 -0
  408. package/dist/settings/dictionaries/settings-dialog.uk.d.ts.map +1 -0
  409. package/dist/settings/dictionaries/settings-dialog.uk.js +28 -0
  410. package/dist/settings/dictionaries/settings-dialog.uk.js.map +1 -0
  411. package/dist/settings/dictionaries/settings-dialog.ur.d.ts +3 -0
  412. package/dist/settings/dictionaries/settings-dialog.ur.d.ts.map +1 -0
  413. package/dist/settings/dictionaries/settings-dialog.ur.js +28 -0
  414. package/dist/settings/dictionaries/settings-dialog.ur.js.map +1 -0
  415. package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts +3 -0
  416. package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts.map +1 -0
  417. package/dist/settings/dictionaries/settings-dialog.zh-CN.js +28 -0
  418. package/dist/settings/dictionaries/settings-dialog.zh-CN.js.map +1 -0
  419. package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts +3 -0
  420. package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts.map +1 -0
  421. package/dist/settings/dictionaries/settings-dialog.zh-TW.js +28 -0
  422. package/dist/settings/dictionaries/settings-dialog.zh-TW.js.map +1 -0
  423. package/dist/settings/ensure-definitions.d.ts +88 -0
  424. package/dist/settings/ensure-definitions.d.ts.map +1 -0
  425. package/dist/settings/ensure-definitions.js +91 -0
  426. package/dist/settings/ensure-definitions.js.map +1 -0
  427. package/dist/settings/errors.d.ts +36 -0
  428. package/dist/settings/errors.d.ts.map +1 -0
  429. package/dist/settings/errors.js +40 -0
  430. package/dist/settings/errors.js.map +1 -0
  431. package/dist/settings/index.d.ts +37 -0
  432. package/dist/settings/index.d.ts.map +1 -0
  433. package/dist/settings/index.js +36 -0
  434. package/dist/settings/index.js.map +1 -0
  435. package/dist/settings/ports.d.ts +117 -0
  436. package/dist/settings/ports.d.ts.map +1 -0
  437. package/dist/settings/ports.js +2 -0
  438. package/dist/settings/ports.js.map +1 -0
  439. package/dist/settings/purge-service.d.ts +53 -0
  440. package/dist/settings/purge-service.d.ts.map +1 -0
  441. package/dist/settings/purge-service.js +105 -0
  442. package/dist/settings/purge-service.js.map +1 -0
  443. package/dist/settings/repo.memory.d.ts +119 -0
  444. package/dist/settings/repo.memory.d.ts.map +1 -0
  445. package/dist/settings/repo.memory.js +199 -0
  446. package/dist/settings/repo.memory.js.map +1 -0
  447. package/dist/settings/settings.d.ts +124 -0
  448. package/dist/settings/settings.d.ts.map +1 -0
  449. package/dist/settings/settings.js +238 -0
  450. package/dist/settings/settings.js.map +1 -0
  451. package/dist/settings/tool-registrations.d.ts +56 -0
  452. package/dist/settings/tool-registrations.d.ts.map +1 -0
  453. package/dist/settings/tool-registrations.js +240 -0
  454. package/dist/settings/tool-registrations.js.map +1 -0
  455. package/dist/settings/types.d.ts +125 -0
  456. package/dist/settings/types.d.ts.map +1 -0
  457. package/dist/settings/types.js +3 -0
  458. package/dist/settings/types.js.map +1 -0
  459. package/dist/settings/ui-tab-definitions.d.ts +41 -0
  460. package/dist/settings/ui-tab-definitions.d.ts.map +1 -0
  461. package/dist/settings/ui-tab-definitions.js +148 -0
  462. package/dist/settings/ui-tab-definitions.js.map +1 -0
  463. package/dist/settings/write-service.d.ts +314 -0
  464. package/dist/settings/write-service.d.ts.map +1 -0
  465. package/dist/settings/write-service.js +677 -0
  466. package/dist/settings/write-service.js.map +1 -0
  467. package/dist/taxonomy/agent-tools.d.ts +76 -0
  468. package/dist/taxonomy/agent-tools.d.ts.map +1 -0
  469. package/dist/taxonomy/agent-tools.js +178 -0
  470. package/dist/taxonomy/agent-tools.js.map +1 -0
  471. package/dist/taxonomy/content-lookup.d.ts +45 -0
  472. package/dist/taxonomy/content-lookup.d.ts.map +1 -0
  473. package/dist/taxonomy/content-lookup.js +9 -0
  474. package/dist/taxonomy/content-lookup.js.map +1 -0
  475. package/dist/taxonomy/index.d.ts +38 -0
  476. package/dist/taxonomy/index.d.ts.map +1 -0
  477. package/dist/taxonomy/index.js +38 -0
  478. package/dist/taxonomy/index.js.map +1 -0
  479. package/dist/taxonomy/list.d.ts +39 -0
  480. package/dist/taxonomy/list.d.ts.map +1 -0
  481. package/dist/taxonomy/list.js +19 -0
  482. package/dist/taxonomy/list.js.map +1 -0
  483. package/dist/taxonomy/merge-term.d.ts +94 -0
  484. package/dist/taxonomy/merge-term.d.ts.map +1 -0
  485. package/dist/taxonomy/merge-term.js +65 -0
  486. package/dist/taxonomy/merge-term.js.map +1 -0
  487. package/dist/taxonomy/repo.memory.d.ts +160 -0
  488. package/dist/taxonomy/repo.memory.d.ts.map +1 -0
  489. package/dist/taxonomy/repo.memory.js +171 -0
  490. package/dist/taxonomy/repo.memory.js.map +1 -0
  491. package/dist/taxonomy/validation-chain.d.ts +114 -0
  492. package/dist/taxonomy/validation-chain.d.ts.map +1 -0
  493. package/dist/taxonomy/validation-chain.js +152 -0
  494. package/dist/taxonomy/validation-chain.js.map +1 -0
  495. package/dist/taxonomy/write-service.d.ts +387 -0
  496. package/dist/taxonomy/write-service.d.ts.map +1 -0
  497. package/dist/taxonomy/write-service.js +350 -0
  498. package/dist/taxonomy/write-service.js.map +1 -0
  499. package/dist/workspace/agent-tools.d.ts +67 -0
  500. package/dist/workspace/agent-tools.d.ts.map +1 -0
  501. package/dist/workspace/agent-tools.js +103 -0
  502. package/dist/workspace/agent-tools.js.map +1 -0
  503. package/dist/workspace/create.d.ts +116 -0
  504. package/dist/workspace/create.d.ts.map +1 -0
  505. package/dist/workspace/create.js +69 -0
  506. package/dist/workspace/create.js.map +1 -0
  507. package/dist/workspace/delete.d.ts +50 -0
  508. package/dist/workspace/delete.d.ts.map +1 -0
  509. package/dist/workspace/delete.js +24 -0
  510. package/dist/workspace/delete.js.map +1 -0
  511. package/dist/workspace/index.d.ts +27 -0
  512. package/dist/workspace/index.d.ts.map +1 -0
  513. package/dist/workspace/index.js +27 -0
  514. package/dist/workspace/index.js.map +1 -0
  515. package/dist/workspace/repo.memory.d.ts +34 -0
  516. package/dist/workspace/repo.memory.d.ts.map +1 -0
  517. package/dist/workspace/repo.memory.js +50 -0
  518. package/dist/workspace/repo.memory.js.map +1 -0
  519. package/dist/workspace/tool-registrations.d.ts +38 -0
  520. package/dist/workspace/tool-registrations.d.ts.map +1 -0
  521. package/dist/workspace/tool-registrations.js +71 -0
  522. package/dist/workspace/tool-registrations.js.map +1 -0
  523. package/dist/workspace/update.d.ts +52 -0
  524. package/dist/workspace/update.d.ts.map +1 -0
  525. package/dist/workspace/update.js +41 -0
  526. package/dist/workspace/update.js.map +1 -0
  527. package/package.json +149 -0
@@ -0,0 +1,246 @@
1
+ /**
2
+ * @file Blob-GC protocol ("References, deletion, and GC
3
+ * (never-brick)", INV-1) — the audited tombstone -> delete-pass -> unlink-pass
4
+ * design, scoped to what an in-memory-repo build can actually run today.
5
+ *
6
+ * Built in this pass:
7
+ * - The real "unreferenced" predicate's sha256-uniqueness-across-non-purged-
8
+ * media-entries conjunct ({@link isBlobUnreferenced}), backed by the actual
9
+ * `mediaRepo` data `purgeMedia` already has.
10
+ * - Ordering (INV-1a): {@link runBlobGcDeletePass} deletes the `asset_blobs`
11
+ * row and writes the `blob_gc_journal` entry together, before any bytes are
12
+ * touched; {@link runBlobGcUnlinkPass} only ever unlinks bytes for a row
13
+ * whose deletion has already happened. `uploadMedia` (see
14
+ * `media-service.ts`) already writes bytes before the row.
15
+ * - Serialization: every transition below runs inside {@link withSha256Lock}
16
+ * (`blob-gc-lock.ts`) — this build's substitute for `BEGIN IMMEDIATE`
17
+ * against an in-memory table (see that file's header for why).
18
+ * - The two-phase, journaled shape: {@link tombstoneBlobIfUnreferenced} ->
19
+ * {@link runBlobGcDeletePass} (re-checks the predicate + `gc_grace`,
20
+ * journals, deletes the row) -> {@link runBlobGcUnlinkPass} (drains the
21
+ * journal, removes bytes). {@link runBlobGcCycle} is a convenience batch
22
+ * wrapper around the last two for tests/manual operation; nothing calls it
23
+ * on a schedule.
24
+ * - `gc_grace = max(30d default, retained-snapshot age)`, with the snapshot
25
+ * input wired as a stub (see below) so a real value slots in later without
26
+ * reworking callers.
27
+ *
28
+ * Deliberately NOT built (disclosed, matches this task's explicit scope):
29
+ * - **`entry_refs` where-used index** ({@link hasLiveEntryRefs}) — belongs to
30
+ * the generic entries model, which is accepted design only, not
31
+ * running code yet (see `types.ts`'s file header on `MediaRecord` being a
32
+ * bespoke table for the same reason). Stubbed to always return `false`
33
+ * ("no live refs found").
34
+ * - **Retained-snapshot conjunct** ({@link getOldestRetainedSnapshotAgeMs}) —
35
+ * owned by a pending Storage/Backups snapshot primitive, which doesn't
36
+ * exist yet either. Stubbed to always
37
+ * return `undefined` ("no retained snapshot").
38
+ * - **Monthly orphan sweep** ({@link runMonthlyOrphanSweepStub}) — the fourth
39
+ * protocol phase, reconciling bytes on disk with no `asset_blobs` row at
40
+ * all (e.g. a crash before any GC protocol existed). Needs a scheduler
41
+ * this library doesn't provide. Named so the seam exists; performs no work
42
+ * and is never called.
43
+ * - **Cross-process safety** — `withSha256Lock` only serializes within one
44
+ * Node process. A real multi-instance deployment needs the real DB
45
+ * transaction the original design specifies, which a host's own persistence adapter
46
+ * would supply; this build has no multi-writer story for media at all yet
47
+ * (in-memory repo), so that gap is inherited, not new.
48
+ */
49
+ import type { ClockPort, IdGeneratorPort, UUID } from "../core/ports.js";
50
+ import type { AssetBlobRepoPort, BlobGcJournalRepoPort, BlobStorePort, MediaRepoPort } from "./ports.js";
51
+ /** Default retention window before a tombstoned blob's delete-pass may run. */
52
+ export declare const DEFAULT_GC_GRACE_MS: number;
53
+ /**
54
+ * `gc_grace = max(configured default, age of the oldest retained snapshot at
55
+ * delete-pass time)`. The snapshot half is always `0` in this
56
+ * build (see {@link getOldestRetainedSnapshotAgeMs}), so this currently
57
+ * always resolves to {@link DEFAULT_GC_GRACE_MS} — structured so a real
58
+ * snapshot-age input replaces that `?? 0` later without touching callers.
59
+ *
60
+ * @complexity O(1).
61
+ * @overallScore 100
62
+ */
63
+ export declare function resolveGcGraceMs(input: {
64
+ workspaceId: UUID;
65
+ sha256: string;
66
+ }): number;
67
+ export interface IsBlobUnreferencedRequired {
68
+ deps: {
69
+ mediaRepo: MediaRepoPort;
70
+ };
71
+ input: {
72
+ workspaceId: UUID;
73
+ sha256: string;
74
+ };
75
+ }
76
+ /**
77
+ * The real "unreferenced" check this file replaces `purgeMedia`'s old
78
+ * sibling-scan-and-immediately-delete shortcut with. Normative definition:
79
+ * no media entry in the workspace in any non-purged state
80
+ * (active or trashed — purged rows are physically removed by `purgeMedia`,
81
+ * so `mediaRepo.list` already excludes them by construction) references this
82
+ * sha256, AND no live `entry_refs` targets it, AND no retained snapshot
83
+ * references it. The last two conjuncts are evaluated by the disclosed stubs
84
+ * above.
85
+ *
86
+ * Callers MUST invoke this from inside {@link withSha256Lock} for the same
87
+ * sha256 — this function only reads, it does not lock itself, so its result
88
+ * is only trustworthy for as long as the caller's own lock is held.
89
+ *
90
+ * @complexity O(n) in the workspace's media row count (same disclosed
91
+ * tradeoff `purgeMedia`'s prior sibling-scan already carried — see
92
+ * `media-service.ts`'s findings note on that function).
93
+ * @overallScore 90
94
+ * @findings Medium: O(n) `mediaRepo.list` + `.some` scan per call, same
95
+ * known tradeoff as the code this replaces. A real `asset_blobs` reference
96
+ * count column would make this O(1); not worth adding for an in-memory
97
+ * walking-skeleton repo.
98
+ */
99
+ export declare function isBlobUnreferenced(required: IsBlobUnreferencedRequired): Promise<boolean>;
100
+ export interface TombstoneBlobDeps {
101
+ mediaRepo: MediaRepoPort;
102
+ blobRepo: AssetBlobRepoPort;
103
+ clock: ClockPort;
104
+ }
105
+ export interface TombstoneBlobRequired {
106
+ deps: TombstoneBlobDeps;
107
+ input: {
108
+ workspaceId: UUID;
109
+ sha256: string;
110
+ };
111
+ }
112
+ /**
113
+ * Tombstone-pass. Marks an `active` blob row `tombstoned` (starting its
114
+ * `gc_grace` clock) if-and-only-if {@link isBlobUnreferenced} holds, all
115
+ * inside one {@link withSha256Lock} section so a concurrent dedup upload for
116
+ * the same sha256 can't observe a half-updated row. Idempotent: re-tombstoning
117
+ * an already-tombstoned row is a no-op success, not an error (mirrors
118
+ * `trashMedia`'s idempotency).
119
+ *
120
+ * @complexity O(n) — dominated by {@link isBlobUnreferenced}'s scan.
121
+ * @overallScore 100
122
+ */
123
+ export declare function tombstoneBlobIfUnreferenced(required: TombstoneBlobRequired): Promise<{
124
+ tombstoned: boolean;
125
+ reason: string;
126
+ }>;
127
+ export interface RunBlobGcDeletePassDeps {
128
+ mediaRepo: MediaRepoPort;
129
+ blobRepo: AssetBlobRepoPort;
130
+ journalRepo: BlobGcJournalRepoPort;
131
+ clock: ClockPort;
132
+ idGen: IdGeneratorPort;
133
+ }
134
+ export interface RunBlobGcDeletePassRequired {
135
+ deps: RunBlobGcDeletePassDeps;
136
+ input: {
137
+ workspaceId: UUID;
138
+ sha256: string;
139
+ };
140
+ }
141
+ /**
142
+ * Delete-pass. Gated on the row being `tombstoned` AND `gc_grace` having
143
+ * elapsed since `tombstonedAt` ({@link resolveGcGraceMs}); re-checks the full
144
+ * {@link isBlobUnreferenced} predicate one more time before acting (a
145
+ * resurrect between tombstone-pass and delete-pass already flips status back
146
+ * to `active`, which the tombstoned-status check below catches first, but the
147
+ * re-check is what the protocol calls for and is what future non-stub
148
+ * entry_refs/snapshot conjuncts would need). On success: writes the
149
+ * `blob_gc_journal` entry and removes the `asset_blobs` row, in that order,
150
+ * inside the same locked section — INV-1a's "unlinked only after the row
151
+ * deletion commits" half depends on nothing touching bytes here at all.
152
+ *
153
+ * @complexity O(n) — dominated by the re-check's `isBlobUnreferenced` scan.
154
+ * @overallScore 100
155
+ */
156
+ export declare function runBlobGcDeletePass(required: RunBlobGcDeletePassRequired): Promise<{
157
+ deleted: boolean;
158
+ reason: string;
159
+ }>;
160
+ export interface RunBlobGcUnlinkPassDeps {
161
+ blobRepo: AssetBlobRepoPort;
162
+ journalRepo: BlobGcJournalRepoPort;
163
+ blobStore: BlobStorePort;
164
+ }
165
+ export interface RunBlobGcUnlinkPassRequired {
166
+ deps: RunBlobGcUnlinkPassDeps;
167
+ input: {
168
+ workspaceId: UUID;
169
+ };
170
+ }
171
+ /**
172
+ * Unlink-pass. Drains every journal entry for the workspace; for each, under
173
+ * that entry's sha256 lock, re-checks whether a **live** `asset_blobs` row now
174
+ * exists for the same sha256 (a dedup upload can legitimately recreate one
175
+ * after the delete-pass ran but before this pass drained the entry). If one
176
+ * exists, the entry is stale — its bytes are now owned by the live row, so
177
+ * this pass must NOT unlink them; the journal entry is still removed (its
178
+ * job — reconciling the row this ADR's crash-safety story cares about — is
179
+ * done either way). If no row exists, the bytes are genuinely orphaned and
180
+ * are removed.
181
+ *
182
+ * This re-check-under-lock is this build's substitute for the design's
183
+ * per-generation storage-key epochs (deferred — see `blob-key.ts`'s file
184
+ * header): instead of tagging storage keys with a generation suffix so a
185
+ * stale unlink physically cannot address live bytes, the sha256 lock plus
186
+ * this re-check gives the same guarantee for a single-process, in-memory
187
+ * build (see `blob-gc-lock.ts`'s file header for the serialization story this
188
+ * relies on).
189
+ *
190
+ * @complexity O(j) in the number of pending journal entries for the
191
+ * workspace, each doing O(1) repo/store work.
192
+ * @overallScore 100
193
+ */
194
+ export declare function runBlobGcUnlinkPass(required: RunBlobGcUnlinkPassRequired): Promise<{
195
+ unlinked: string[];
196
+ skipped: string[];
197
+ }>;
198
+ export interface RunBlobGcCycleDeps extends RunBlobGcDeletePassDeps, Pick<RunBlobGcUnlinkPassDeps, "blobStore"> {
199
+ }
200
+ export interface RunBlobGcCycleRequired {
201
+ deps: RunBlobGcCycleDeps;
202
+ input: {
203
+ workspaceId: UUID;
204
+ };
205
+ }
206
+ /**
207
+ * Convenience wrapper: runs the delete-pass over every currently-tombstoned
208
+ * blob in the workspace (each still individually grace-gated —
209
+ * `runBlobGcDeletePass` may no-op per row), then drains the unlink-pass once.
210
+ * This is NOT the ADR's periodic/monthly orphan sweep (a different,
211
+ * out-of-scope reconciliation against bytes with no row at all — see
212
+ * {@link runMonthlyOrphanSweepStub}); it is just a batch shape over the two
213
+ * in-scope phases above, for tests and any future manual/operator trigger.
214
+ * Nothing calls it on a schedule.
215
+ *
216
+ * @complexity O(t * n + j) — t tombstoned rows each doing an O(n)
217
+ * `isBlobUnreferenced` re-check, plus O(j) journal drain.
218
+ * @overallScore 100
219
+ */
220
+ export declare function runBlobGcCycle(required: RunBlobGcCycleRequired): Promise<{
221
+ deletedShas: string[];
222
+ unlinked: string[];
223
+ skipped: string[];
224
+ }>;
225
+ /**
226
+ * STUB — the protocol's fourth GC phase, a periodic/monthly orphan sweep that
227
+ * reconciles bytes physically present in the blob store with no
228
+ * corresponding `asset_blobs` row at all (e.g. bytes from a crash before any
229
+ * GC protocol existed, or before this build's ordering guarantee was in
230
+ * place). Out of scope for this task ("needs a scheduler this build doesn't
231
+ * have yet" — see this file's header). Performs no work; exists only so the
232
+ * seam a future scheduler would call has a name and signature. Never invoked
233
+ * anywhere in this build.
234
+ *
235
+ * @complexity O(1) (stub — does nothing).
236
+ * @overallScore 100
237
+ */
238
+ export declare function runMonthlyOrphanSweepStub(_deps: {
239
+ blobStore: BlobStorePort;
240
+ blobRepo: AssetBlobRepoPort;
241
+ }, _input: {
242
+ workspaceId: UUID;
243
+ }): Promise<{
244
+ implemented: false;
245
+ }>;
246
+ //# sourceMappingURL=blob-gc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-gc.d.ts","sourceRoot":"","sources":["../../src/media/blob-gc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGzG,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,QAA2B,CAAC;AA+C5D;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IAAE,WAAW,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGrF;AAMD,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE;QAAE,SAAS,EAAE,aAAa,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE;QAAE,WAAW,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,0BAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ/F;AAMD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE;QAAE,WAAW,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAalD;AAMD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,WAAW,EAAE,qBAAqB,CAAC;IACnC,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE;QAAE,WAAW,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,2BAA2B,GACpC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B/C;AAMD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,EAAE,aAAa,CAAC;CAC1B;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE;QAAE,WAAW,EAAE,IAAI,CAAA;KAAE,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,2BAA2B,GACpC,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAuBpD;AAMD,MAAM,WAAW,kBACf,SAAQ,uBAAuB,EAC7B,IAAI,CAAC,uBAAuB,EAAE,WAAW,CAAC;CAAG;AAEjD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE;QAAE,WAAW,EAAE,IAAI,CAAA;KAAE,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,sBAAsB,GAC/B,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAa3E;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE;IAAE,SAAS,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,EAChE,MAAM,EAAE;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,GAC5B,OAAO,CAAC;IAAE,WAAW,EAAE,KAAK,CAAA;CAAE,CAAC,CAEjC"}
@@ -0,0 +1,254 @@
1
+ import { withSha256Lock } from "./blob-gc-lock.js";
2
+ /** Default retention window before a tombstoned blob's delete-pass may run. */
3
+ export const DEFAULT_GC_GRACE_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
4
+ // ---------------------------------------------------------------------------
5
+ // Disclosed stubs — conjuncts this build cannot evaluate for real
6
+ // yet. Both are named, not silently folded into `true`/`false` inline, so a
7
+ // future implementation has an obvious seam to replace.
8
+ // ---------------------------------------------------------------------------
9
+ /**
10
+ * STUB — the derived `entry_refs` where-used index (TipTap image nodes
11
+ * + registry `ref` fields) does not exist as running code yet (see this
12
+ * file's header). Always reports no live references, which is what lets
13
+ * {@link isBlobUnreferenced} degrade to the sha256-uniqueness check alone.
14
+ *
15
+ * @complexity O(1) (stub).
16
+ * @overallScore 100
17
+ */
18
+ function hasLiveEntryRefs(_input) {
19
+ return false;
20
+ }
21
+ /**
22
+ * STUB — snapshot-retention is owned by a pending Storage/Backups snapshot
23
+ * primitive (not built yet at all — see this file's header). Always reports
24
+ * no retained snapshot.
25
+ *
26
+ * @complexity O(1) (stub).
27
+ * @overallScore 100
28
+ */
29
+ function hasRetainedSnapshot(_input) {
30
+ return false;
31
+ }
32
+ /**
33
+ * STUB — age (ms) of the oldest snapshot that still retains this blob, at
34
+ * delete-pass time. Always `undefined` in this build (no snapshot primitive
35
+ * exists), which is what makes {@link resolveGcGraceMs} fall back to the
36
+ * 30-day default alone. A real implementation would return a number here;
37
+ * `resolveGcGraceMs`'s `Math.max` already accepts that without change.
38
+ *
39
+ * @complexity O(1) (stub).
40
+ * @overallScore 100
41
+ */
42
+ function getOldestRetainedSnapshotAgeMs(_input) {
43
+ return undefined;
44
+ }
45
+ /**
46
+ * `gc_grace = max(configured default, age of the oldest retained snapshot at
47
+ * delete-pass time)`. The snapshot half is always `0` in this
48
+ * build (see {@link getOldestRetainedSnapshotAgeMs}), so this currently
49
+ * always resolves to {@link DEFAULT_GC_GRACE_MS} — structured so a real
50
+ * snapshot-age input replaces that `?? 0` later without touching callers.
51
+ *
52
+ * @complexity O(1).
53
+ * @overallScore 100
54
+ */
55
+ export function resolveGcGraceMs(input) {
56
+ const snapshotAgeMs = getOldestRetainedSnapshotAgeMs(input) ?? 0;
57
+ return Math.max(DEFAULT_GC_GRACE_MS, snapshotAgeMs);
58
+ }
59
+ /**
60
+ * The real "unreferenced" check this file replaces `purgeMedia`'s old
61
+ * sibling-scan-and-immediately-delete shortcut with. Normative definition:
62
+ * no media entry in the workspace in any non-purged state
63
+ * (active or trashed — purged rows are physically removed by `purgeMedia`,
64
+ * so `mediaRepo.list` already excludes them by construction) references this
65
+ * sha256, AND no live `entry_refs` targets it, AND no retained snapshot
66
+ * references it. The last two conjuncts are evaluated by the disclosed stubs
67
+ * above.
68
+ *
69
+ * Callers MUST invoke this from inside {@link withSha256Lock} for the same
70
+ * sha256 — this function only reads, it does not lock itself, so its result
71
+ * is only trustworthy for as long as the caller's own lock is held.
72
+ *
73
+ * @complexity O(n) in the workspace's media row count (same disclosed
74
+ * tradeoff `purgeMedia`'s prior sibling-scan already carried — see
75
+ * `media-service.ts`'s findings note on that function).
76
+ * @overallScore 90
77
+ * @findings Medium: O(n) `mediaRepo.list` + `.some` scan per call, same
78
+ * known tradeoff as the code this replaces. A real `asset_blobs` reference
79
+ * count column would make this O(1); not worth adding for an in-memory
80
+ * walking-skeleton repo.
81
+ */
82
+ export async function isBlobUnreferenced(required) {
83
+ const { deps, input } = required;
84
+ const rows = await deps.mediaRepo.list({ workspaceId: input.workspaceId });
85
+ const hasMediaReference = rows.some((row) => row.source.sha256 === input.sha256);
86
+ if (hasMediaReference)
87
+ return false;
88
+ if (hasLiveEntryRefs(input))
89
+ return false;
90
+ if (hasRetainedSnapshot(input))
91
+ return false;
92
+ return true;
93
+ }
94
+ /**
95
+ * Tombstone-pass. Marks an `active` blob row `tombstoned` (starting its
96
+ * `gc_grace` clock) if-and-only-if {@link isBlobUnreferenced} holds, all
97
+ * inside one {@link withSha256Lock} section so a concurrent dedup upload for
98
+ * the same sha256 can't observe a half-updated row. Idempotent: re-tombstoning
99
+ * an already-tombstoned row is a no-op success, not an error (mirrors
100
+ * `trashMedia`'s idempotency).
101
+ *
102
+ * @complexity O(n) — dominated by {@link isBlobUnreferenced}'s scan.
103
+ * @overallScore 100
104
+ */
105
+ export async function tombstoneBlobIfUnreferenced(required) {
106
+ const { deps, input } = required;
107
+ return withSha256Lock(input.sha256, async () => {
108
+ const row = await deps.blobRepo.findByHash(input);
109
+ if (!row)
110
+ return { tombstoned: false, reason: "no-blob-row" };
111
+ if (row.status === "tombstoned")
112
+ return { tombstoned: true, reason: "already-tombstoned" };
113
+ const unreferenced = await isBlobUnreferenced({ deps, input });
114
+ if (!unreferenced)
115
+ return { tombstoned: false, reason: "still-referenced" };
116
+ await deps.blobRepo.save({ ...row, status: "tombstoned", tombstonedAt: deps.clock.nowIso() });
117
+ return { tombstoned: true, reason: "tombstoned" };
118
+ });
119
+ }
120
+ /**
121
+ * Delete-pass. Gated on the row being `tombstoned` AND `gc_grace` having
122
+ * elapsed since `tombstonedAt` ({@link resolveGcGraceMs}); re-checks the full
123
+ * {@link isBlobUnreferenced} predicate one more time before acting (a
124
+ * resurrect between tombstone-pass and delete-pass already flips status back
125
+ * to `active`, which the tombstoned-status check below catches first, but the
126
+ * re-check is what the protocol calls for and is what future non-stub
127
+ * entry_refs/snapshot conjuncts would need). On success: writes the
128
+ * `blob_gc_journal` entry and removes the `asset_blobs` row, in that order,
129
+ * inside the same locked section — INV-1a's "unlinked only after the row
130
+ * deletion commits" half depends on nothing touching bytes here at all.
131
+ *
132
+ * @complexity O(n) — dominated by the re-check's `isBlobUnreferenced` scan.
133
+ * @overallScore 100
134
+ */
135
+ export async function runBlobGcDeletePass(required) {
136
+ const { deps, input } = required;
137
+ return withSha256Lock(input.sha256, async () => {
138
+ const row = await deps.blobRepo.findByHash(input);
139
+ if (!row)
140
+ return { deleted: false, reason: "no-blob-row" };
141
+ if (row.status !== "tombstoned" || !row.tombstonedAt) {
142
+ return { deleted: false, reason: "not-tombstoned" };
143
+ }
144
+ const graceMs = resolveGcGraceMs(input);
145
+ const elapsedMs = new Date(deps.clock.nowIso()).getTime() - new Date(row.tombstonedAt).getTime();
146
+ if (elapsedMs < graceMs)
147
+ return { deleted: false, reason: "grace-period-not-elapsed" };
148
+ const stillUnreferenced = await isBlobUnreferenced({ deps, input });
149
+ if (!stillUnreferenced)
150
+ return { deleted: false, reason: "resurrected" };
151
+ await deps.journalRepo.save({
152
+ id: deps.idGen.newId(),
153
+ workspaceId: input.workspaceId,
154
+ sha256: input.sha256,
155
+ storageKey: row.storageKey,
156
+ journaledAt: deps.clock.nowIso(),
157
+ });
158
+ await deps.blobRepo.remove(input);
159
+ return { deleted: true, reason: "deleted" };
160
+ });
161
+ }
162
+ /**
163
+ * Unlink-pass. Drains every journal entry for the workspace; for each, under
164
+ * that entry's sha256 lock, re-checks whether a **live** `asset_blobs` row now
165
+ * exists for the same sha256 (a dedup upload can legitimately recreate one
166
+ * after the delete-pass ran but before this pass drained the entry). If one
167
+ * exists, the entry is stale — its bytes are now owned by the live row, so
168
+ * this pass must NOT unlink them; the journal entry is still removed (its
169
+ * job — reconciling the row this ADR's crash-safety story cares about — is
170
+ * done either way). If no row exists, the bytes are genuinely orphaned and
171
+ * are removed.
172
+ *
173
+ * This re-check-under-lock is this build's substitute for the design's
174
+ * per-generation storage-key epochs (deferred — see `blob-key.ts`'s file
175
+ * header): instead of tagging storage keys with a generation suffix so a
176
+ * stale unlink physically cannot address live bytes, the sha256 lock plus
177
+ * this re-check gives the same guarantee for a single-process, in-memory
178
+ * build (see `blob-gc-lock.ts`'s file header for the serialization story this
179
+ * relies on).
180
+ *
181
+ * @complexity O(j) in the number of pending journal entries for the
182
+ * workspace, each doing O(1) repo/store work.
183
+ * @overallScore 100
184
+ */
185
+ export async function runBlobGcUnlinkPass(required) {
186
+ const { deps, input } = required;
187
+ const entries = await deps.journalRepo.list(input);
188
+ const unlinked = [];
189
+ const skipped = [];
190
+ for (const entry of entries) {
191
+ await withSha256Lock(entry.sha256, async () => {
192
+ const liveRow = await deps.blobRepo.findByHash({
193
+ workspaceId: entry.workspaceId,
194
+ sha256: entry.sha256,
195
+ });
196
+ if (liveRow) {
197
+ skipped.push(entry.sha256);
198
+ }
199
+ else {
200
+ await deps.blobStore.remove({ storageKey: entry.storageKey });
201
+ unlinked.push(entry.sha256);
202
+ }
203
+ await deps.journalRepo.remove({ workspaceId: entry.workspaceId, id: entry.id });
204
+ });
205
+ }
206
+ return { unlinked, skipped };
207
+ }
208
+ /**
209
+ * Convenience wrapper: runs the delete-pass over every currently-tombstoned
210
+ * blob in the workspace (each still individually grace-gated —
211
+ * `runBlobGcDeletePass` may no-op per row), then drains the unlink-pass once.
212
+ * This is NOT the ADR's periodic/monthly orphan sweep (a different,
213
+ * out-of-scope reconciliation against bytes with no row at all — see
214
+ * {@link runMonthlyOrphanSweepStub}); it is just a batch shape over the two
215
+ * in-scope phases above, for tests and any future manual/operator trigger.
216
+ * Nothing calls it on a schedule.
217
+ *
218
+ * @complexity O(t * n + j) — t tombstoned rows each doing an O(n)
219
+ * `isBlobUnreferenced` re-check, plus O(j) journal drain.
220
+ * @overallScore 100
221
+ */
222
+ export async function runBlobGcCycle(required) {
223
+ const { deps, input } = required;
224
+ const rows = await deps.blobRepo.list(input);
225
+ const tombstonedRows = rows.filter((row) => row.status === "tombstoned");
226
+ const deletedShas = [];
227
+ for (const row of tombstonedRows) {
228
+ const result = await runBlobGcDeletePass({ deps, input: { workspaceId: input.workspaceId, sha256: row.sha256 } });
229
+ if (result.deleted)
230
+ deletedShas.push(row.sha256);
231
+ }
232
+ const { unlinked, skipped } = await runBlobGcUnlinkPass({ deps, input });
233
+ return { deletedShas, unlinked, skipped };
234
+ }
235
+ // ---------------------------------------------------------------------------
236
+ // Explicitly out of scope — named stub only (see file header)
237
+ // ---------------------------------------------------------------------------
238
+ /**
239
+ * STUB — the protocol's fourth GC phase, a periodic/monthly orphan sweep that
240
+ * reconciles bytes physically present in the blob store with no
241
+ * corresponding `asset_blobs` row at all (e.g. bytes from a crash before any
242
+ * GC protocol existed, or before this build's ordering guarantee was in
243
+ * place). Out of scope for this task ("needs a scheduler this build doesn't
244
+ * have yet" — see this file's header). Performs no work; exists only so the
245
+ * seam a future scheduler would call has a name and signature. Never invoked
246
+ * anywhere in this build.
247
+ *
248
+ * @complexity O(1) (stub — does nothing).
249
+ * @overallScore 100
250
+ */
251
+ export async function runMonthlyOrphanSweepStub(_deps, _input) {
252
+ return { implemented: false };
253
+ }
254
+ //# sourceMappingURL=blob-gc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-gc.js","sourceRoot":"","sources":["../../src/media/blob-gc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file Shared storage-key derivation for `BlobStorePort` adapters
3
+ * (workspace-prefixed keys).
4
+ *
5
+ * Purpose:
6
+ * Both `blob-store.fs.ts` and `blob-store.memory.ts` must derive the same key
7
+ * shape from `(workspaceId, sha256)` so switching adapters never changes what a
8
+ * stored key looks like. Kept as one small pure function rather than
9
+ * duplicated inline in each adapter.
10
+ *
11
+ * No per-generation epoch suffix (contrast the original design's
12
+ * `{sha256}-{storage_epoch}`) — epochs exist to make the journaled 2-phase GC
13
+ * race-proof, and that protocol is explicitly deferred in this build (see
14
+ * `media-service.ts` file header). A future epoch-aware rewrite would change
15
+ * this function's output shape, not its callers' contract.
16
+ */
17
+ import type { UUID } from "../core/ports.js";
18
+ /**
19
+ * Derives `ws/{workspaceId}/blobs/{sha256[0..1]}/{sha256}`.
20
+ *
21
+ * @complexity O(1).
22
+ * @overallScore 100
23
+ */
24
+ export declare function computeBlobStorageKey(input: {
25
+ workspaceId: UUID;
26
+ sha256: string;
27
+ }): string;
28
+ //# sourceMappingURL=blob-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-key.d.ts","sourceRoot":"","sources":["../../src/media/blob-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAAE,WAAW,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAG1F"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Derives `ws/{workspaceId}/blobs/{sha256[0..1]}/{sha256}`.
3
+ *
4
+ * @complexity O(1).
5
+ * @overallScore 100
6
+ */
7
+ export function computeBlobStorageKey(input) {
8
+ const shard = input.sha256.slice(0, 2);
9
+ return `ws/${input.workspaceId}/blobs/${shard}/${input.sha256}`;
10
+ }
11
+ //# sourceMappingURL=blob-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-key.js","sourceRoot":"","sources":["../../src/media/blob-key.ts"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAA4C;IAChF,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvC,OAAO,MAAM,KAAK,CAAC,WAAW,UAAU,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;AAClE,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { BlobStorePort, PutBlobInput } from "./ports.js";
2
+ export interface LocalFsBlobStoreDeps {
3
+ /** Root directory blob storage keys are resolved relative to. */
4
+ rootDir: string;
5
+ }
6
+ export declare class LocalFsBlobStore implements BlobStorePort {
7
+ private readonly rootDir;
8
+ constructor(deps: LocalFsBlobStoreDeps);
9
+ private resolvePath;
10
+ put(input: PutBlobInput): Promise<{
11
+ storageKey: string;
12
+ }>;
13
+ get(input: {
14
+ storageKey: string;
15
+ }): Promise<Uint8Array>;
16
+ exists(input: {
17
+ storageKey: string;
18
+ }): Promise<boolean>;
19
+ remove(input: {
20
+ storageKey: string;
21
+ }): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=blob-store.fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-store.fs.d.ts","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAiB,YAAW,aAAa;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,oBAAoB;IAItC,OAAO,CAAC,WAAW;IAIb,GAAG,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAQzD,GAAG,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IASvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3D"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @file Local-filesystem `BlobStorePort` adapter (port/adapter rule-of-two "one
3
+ * being built now" half; the `uploads/` convention).
4
+ *
5
+ * Purpose:
6
+ * Writes/reads blob bytes under a configurable root directory, keyed by
7
+ * `computeBlobStorageKey` (`blob-key.ts`). A host wires this in for its real
8
+ * running server; the in-memory adapter (`blob-store.memory.ts`) is what
9
+ * hermetic tests and a default dev composition use instead.
10
+ *
11
+ * Deliberately NOT built: the S3 adapter (deferred), the presign
12
+ * surface, per-generation storage epochs (see `blob-key.ts` file header).
13
+ */
14
+ import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
15
+ import { dirname, join } from "node:path";
16
+ import { computeBlobStorageKey } from "./blob-key.js";
17
+ export class LocalFsBlobStore {
18
+ rootDir;
19
+ constructor(deps) {
20
+ this.rootDir = deps.rootDir;
21
+ }
22
+ resolvePath(storageKey) {
23
+ return join(this.rootDir, storageKey);
24
+ }
25
+ async put(input) {
26
+ const storageKey = computeBlobStorageKey(input);
27
+ const path = this.resolvePath(storageKey);
28
+ await mkdir(dirname(path), { recursive: true });
29
+ await writeFile(path, input.bytes);
30
+ return { storageKey };
31
+ }
32
+ async get(input) {
33
+ return readFile(this.resolvePath(input.storageKey));
34
+ }
35
+ async exists(input) {
36
+ try {
37
+ await stat(this.resolvePath(input.storageKey));
38
+ return true;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ async remove(input) {
45
+ await rm(this.resolvePath(input.storageKey), { force: true });
46
+ }
47
+ }
48
+ //# sourceMappingURL=blob-store.fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-store.fs.js","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD,MAAM,OAAO,gBAAgB;IACV,OAAO,CAAS;IAEjC,YAAY,IAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAEO,WAAW,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAmB;QAC3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAA6B;QACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;CACF"}