@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,244 @@
1
+ import type { ClockPort, IdGeneratorPort, UUID } from "../core/ports.js";
2
+ import { MediaConflictError, MediaNotFoundError, MediaSourceImmutableError, MediaStillReferencedError, MediaValidationError, type MediaRecord, type MediaSource } from "./types.js";
3
+ import type { AssetBlobRepoPort, AssetRenditionRepoPort, BlobStorePort, MediaRepoPort } from "./ports.js";
4
+ export { MediaConflictError, MediaNotFoundError, MediaSourceImmutableError, MediaStillReferencedError, MediaValidationError, };
5
+ /** Default byte-size cap (this pass's stand-in for the real ingress policy's streaming cap). */
6
+ export declare const DEFAULT_MAX_UPLOAD_BYTES: number;
7
+ /**
8
+ * Advisory MIME allowlist. SVG is deliberately EXCLUDED (not "TODO, forgot") —
9
+ * SVG must be sanitized at ingest before it's safe to store;
10
+ * that sanitizer is not built in this pass, so SVG upload is rejected rather
11
+ * than accepted unsanitized.
12
+ *
13
+ * `video/mp4`/`video/webm` (owner-directed, 2026-08-24): the two formats
14
+ * `content-type-sniffer.ts` already recognizes by magic bytes. Unlike the four
15
+ * image types above, an accepted video is never re-encoded — there is no
16
+ * `TransformFormat` for video (`transform-types.ts`'s union is image-only), so
17
+ * a video asset's public URL bypasses the transform/rendition pipeline
18
+ * entirely and serves the original bytes as-is (host concern; see Tovu's
19
+ * `routes/site/media-rendition.ts`). This widens the SAME advisory,
20
+ * client-declared-string check item 4 above already discloses as untrusted —
21
+ * no new ingress hardening was added for video.
22
+ */
23
+ export declare const DEFAULT_ALLOWED_MIME_TYPES: ReadonlySet<string>;
24
+ /**
25
+ * Enforces the "settable-once-from-absent" write-once rule for
26
+ * `source.sha256`: absent -> set exactly once, then immutable.
27
+ *
28
+ * Not currently reachable through any exposed write path — `uploadMedia` only
29
+ * ever calls it with `existing = undefined` (a brand-new row), and
30
+ * `UpdateMediaMetadataInput` has no `sha256` field at all, so
31
+ * `updateMediaMetadata` can't trigger the rejection branch even by accident.
32
+ * Kept as an explicit, directly-testable invariant (see
33
+ * `__tests__/media-service.test.ts`) rather than an implicit one enforced only
34
+ * by "the type doesn't have the field" — and it's the seam any future
35
+ * "replace source" operation would have to go through.
36
+ *
37
+ * @complexity O(1).
38
+ * @overallScore 100
39
+ */
40
+ export declare function resolveWriteOnceSource(required: {
41
+ existing: MediaSource | undefined;
42
+ requestedSha256: string;
43
+ }, _optional?: Record<string, never>): MediaSource;
44
+ export interface UploadMediaInput {
45
+ workspaceId: UUID;
46
+ bytes: Uint8Array;
47
+ filename: string;
48
+ contentType: string;
49
+ alt?: string | undefined;
50
+ caption?: string | undefined;
51
+ credit?: string | undefined;
52
+ /** Attributed on the `asset_blobs` row (required attribution). */
53
+ createdByPrincipal: string;
54
+ }
55
+ export interface UploadMediaDeps {
56
+ clock: ClockPort;
57
+ idGen: IdGeneratorPort;
58
+ mediaRepo: MediaRepoPort;
59
+ blobRepo: AssetBlobRepoPort;
60
+ renditionRepo: AssetRenditionRepoPort;
61
+ blobStore: BlobStorePort;
62
+ }
63
+ export interface UploadMediaRequired {
64
+ deps: UploadMediaDeps;
65
+ input: UploadMediaInput;
66
+ }
67
+ export interface UploadMediaOptional {
68
+ maxUploadBytes?: number | undefined;
69
+ allowedMimeTypes?: ReadonlySet<string> | undefined;
70
+ }
71
+ /**
72
+ * Validates, hashes, dedups by `(workspaceId, sha256)`, and writes a new media
73
+ * asset. Ordering (INV-1a): bytes are written (or found already
74
+ * present via dedup) BEFORE the media row is saved — a media row never exists
75
+ * without corresponding bytes.
76
+ *
77
+ * Blob dedup is per-hash, not per-upload: uploading the same bytes twice
78
+ * always creates two `MediaRecord`s (two distinct library entries, matching
79
+ * common CMS behavior) but writes the blob bytes only once. The dedup
80
+ * check-then-act sequence runs inside {@link withSha256Lock} (`blob-gc-lock.ts`)
81
+ * so it can't interleave with a concurrent `blob-gc.ts` delete-pass on the
82
+ * same sha256 (the "Serialization" invariant). If the existing blob row
83
+ * is `tombstoned` (a pending GC candidate), this resurrects it back to
84
+ * `active` in the same locked section instead of writing a duplicate blob —
85
+ * the dedup rule's explicit resurrect case.
86
+ *
87
+ * @complexity O(1) — one hash, one blob lookup, at most one blob write, one
88
+ * media write, one rendition write (the lock itself adds O(1) scheduling
89
+ * overhead, not a scan).
90
+ * @overallScore 100
91
+ */
92
+ export declare function uploadMedia(required: UploadMediaRequired, optional?: UploadMediaOptional): Promise<{
93
+ media: MediaRecord;
94
+ }>;
95
+ export interface ListMediaRequired {
96
+ deps: {
97
+ mediaRepo: MediaRepoPort;
98
+ };
99
+ input: {
100
+ workspaceId: UUID;
101
+ };
102
+ }
103
+ /**
104
+ * Lists all media in a workspace (all statuses — active + trashed; admin sees
105
+ * everything, mirrors an admin post listing). Purged assets are absent by
106
+ * construction (`purgeMedia` removes the row), not filtered here.
107
+ *
108
+ * @complexity O(1) repo call; the returned array is bounded by the
109
+ * workspace's media row count (repo-dependent — no pagination cap added in
110
+ * this pass, acceptable at walking-skeleton scale).
111
+ * @overallScore 100
112
+ */
113
+ export declare function listMedia(required: ListMediaRequired, _optional?: Record<string, never>): Promise<{
114
+ media: MediaRecord[];
115
+ }>;
116
+ export interface GetMediaByIdRequired {
117
+ deps: {
118
+ mediaRepo: MediaRepoPort;
119
+ };
120
+ input: {
121
+ workspaceId: UUID;
122
+ id: UUID;
123
+ };
124
+ }
125
+ /**
126
+ * Fetches one media asset by id, scoped to its workspace.
127
+ *
128
+ * @complexity O(1).
129
+ * @overallScore 100
130
+ */
131
+ export declare function getMediaById(required: GetMediaByIdRequired, _optional?: Record<string, never>): Promise<{
132
+ media: MediaRecord;
133
+ }>;
134
+ export interface UpdateMediaMetadataInput {
135
+ workspaceId: UUID;
136
+ id: UUID;
137
+ title?: string | undefined;
138
+ alt?: string | undefined;
139
+ caption?: string | undefined;
140
+ credit?: string | undefined;
141
+ /**
142
+ * Quick-and-dirty sizing override fields (see `MediaRecord.width`/`height`/`cssClass` doc).
143
+ * `undefined` (the key omitted, or explicitly `undefined`) leaves the stored value unchanged —
144
+ * same optional-field/partial-patch contract every other field on this input already has.
145
+ * `null` explicitly CLEARS a previously-set override back to "not set". A provided number must be
146
+ * a positive integer (rejected with `MediaValidationError` otherwise) — this is public HTML output
147
+ * sizing, not a field worth silently coercing.
148
+ */
149
+ width?: number | null | undefined;
150
+ height?: number | null | undefined;
151
+ /** Same undefined/null/value contract as `width`/`height` above. A non-empty string is trimmed;
152
+ * a string that trims to empty is stored as `null` (equivalent to clearing it), matching the
153
+ * "empty means unset" convention `title`/`alt`/etc. already follow via `.trim()`. */
154
+ cssClass?: string | null | undefined;
155
+ }
156
+ export interface UpdateMediaMetadataDeps {
157
+ clock: ClockPort;
158
+ mediaRepo: MediaRepoPort;
159
+ }
160
+ export interface UpdateMediaMetadataRequired {
161
+ deps: UpdateMediaMetadataDeps;
162
+ input: UpdateMediaMetadataInput;
163
+ }
164
+ export declare function updateMediaMetadata(required: UpdateMediaMetadataRequired, _optional?: Record<string, never>): Promise<{
165
+ media: MediaRecord;
166
+ }>;
167
+ export interface TrashMediaDeps {
168
+ clock: ClockPort;
169
+ mediaRepo: MediaRepoPort;
170
+ }
171
+ export interface TrashMediaRequired {
172
+ deps: TrashMediaDeps;
173
+ input: {
174
+ workspaceId: UUID;
175
+ id: UUID;
176
+ };
177
+ }
178
+ /**
179
+ * Soft delete. Idempotent — trashing an already-trashed asset is a no-op
180
+ * (mirrors `disableMember`'s idempotency), not an error.
181
+ *
182
+ * @complexity O(1).
183
+ * @overallScore 100
184
+ */
185
+ export declare function trashMedia(required: TrashMediaRequired, _optional?: Record<string, never>): Promise<{
186
+ media: MediaRecord;
187
+ }>;
188
+ export interface PurgeMediaDeps {
189
+ mediaRepo: MediaRepoPort;
190
+ blobRepo: AssetBlobRepoPort;
191
+ renditionRepo: AssetRenditionRepoPort;
192
+ blobStore: BlobStorePort;
193
+ /**
194
+ * Optional — only used to timestamp the blob-GC tombstone-pass this
195
+ * function triggers after the media row is removed (`tombstoneBlobIfUnreferenced`,
196
+ * `blob-gc.ts`). Falls back to the system clock when omitted so a caller
197
+ * that doesn't wire a clock into `PurgeMediaDeps` keeps compiling and
198
+ * behaving correctly unchanged.
199
+ */
200
+ clock?: ClockPort | undefined;
201
+ }
202
+ export interface PurgeMediaRequired {
203
+ deps: PurgeMediaDeps;
204
+ input: {
205
+ workspaceId: UUID;
206
+ id: UUID;
207
+ };
208
+ }
209
+ /**
210
+ * Hard delete. Deletion ladder (mirrors `deleteMenu`): purge is
211
+ * rejected with `MediaStillReferencedError` (409-style) unless the asset has
212
+ * already been trashed first.
213
+ *
214
+ * SIMPLIFICATION (disclosed): the real design's guard checks the derived
215
+ * `entry_refs` where-used index (any live reference from published content).
216
+ * That index doesn't exist — posts don't reference media by id in `bodyJson`
217
+ * yet — so this build uses "not yet trashed" as the stand-in referenced-check.
218
+ * This is strictly weaker than the real invariant: a media asset that IS
219
+ * trashed but still referenced by a post would purge here without complaint,
220
+ * whereas the real system would keep blocking it. Do not read this function's
221
+ * 409 as evidence the where-used index exists.
222
+ *
223
+ * Once past the guard: rendition rows are removed, then the media row is
224
+ * removed. After that removal commits, the blob-GC tombstone-pass
225
+ * (`tombstoneBlobIfUnreferenced`, `blob-gc.ts`) runs for the asset's sha256 —
226
+ * it marks the blob `tombstoned` if-and-only-if the real "unreferenced"
227
+ * predicate holds (no other non-purged media row shares the hash, plus the
228
+ * disclosed `entry_refs`/retained-snapshot stubs). This function does **not**
229
+ * delete blob bytes itself anymore: the delete-pass (`runBlobGcDeletePass`)
230
+ * is grace-period-gated (`gc_grace`, default 30 days) and the unlink-pass
231
+ * (`runBlobGcUnlinkPass`) that actually removes bytes runs as a separate,
232
+ * explicit step — nothing schedules either automatically yet (see
233
+ * `blob-gc.ts`'s file header). This is a real behavior change from this
234
+ * function's prior "delete row, best-effort unlink immediately" shortcut,
235
+ * which is exactly the gap this task closes.
236
+ *
237
+ * @complexity O(n) in the workspace's media row count, inherited from the
238
+ * tombstone-pass's `isBlobUnreferenced` scan (see `blob-gc.ts`).
239
+ * @overallScore 100
240
+ */
241
+ export declare function purgeMedia(required: PurgeMediaRequired, _optional?: Record<string, never>): Promise<{
242
+ purged: true;
243
+ }>;
244
+ //# sourceMappingURL=media-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-service.d.ts","sourceRoot":"","sources":["../../src/media/media-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,345 @@
1
+ /**
2
+ * @file `media` write/read service — walking-skeleton build.
3
+ *
4
+ * Mirrors a `post`-style feature's shape: plain async functions taking
5
+ * `{ deps, input }` (+ an optional second `options` object), typed domain
6
+ * errors from `./types`.
7
+ *
8
+ * SCOPE — what this file deliberately does NOT build (disclosed, not silently
9
+ * skipped; each deferred piece is named below):
10
+ *
11
+ * 1. **Blob GC** — now built for real (`blob-gc.ts`): a journaled,
12
+ * `withSha256Lock`-serialized tombstone -> delete-pass -> unlink-pass
13
+ * protocol with `gc_grace` retention. `purgeMedia` below no longer
14
+ * deletes blob bytes itself — after removing the media row it only
15
+ * triggers the tombstone-pass (`tombstoneBlobIfUnreferenced`); actual
16
+ * byte removal is deferred to `runBlobGcDeletePass` +
17
+ * `runBlobGcUnlinkPass` (or the `runBlobGcCycle` convenience wrapper),
18
+ * which nothing schedules automatically yet (no scheduler exists — see
19
+ * `blob-gc.ts`'s file header). `uploadMedia`'s dedup check is likewise
20
+ * serialized per-sha256 and resurrects a tombstoned blob instead of
21
+ * writing a duplicate. See `blob-gc.ts` for what's still
22
+ * disclosed-stubbed within that protocol (`entry_refs`, retained
23
+ * snapshots, the monthly orphan sweep).
24
+ * 2. **Named transform registry / real image processing** — the only
25
+ * rendition this build ever creates is a trivial "original" passthrough
26
+ * row that points at the source blob (created by `uploadMedia`). No
27
+ * `transform_registry` table, no eager/lazy generation, no
28
+ * `/m/{assetId}/{transformName}.v{version}/{slug}.{ext}` URL contract.
29
+ * 3. **Origin-isolated serving** — a host may add an authenticated,
30
+ * workspace-scoped admin route that serves original bytes, with content
31
+ * type derived at serve time by `content-type-sniffer.ts` rather than
32
+ * trusted from upload, since no real content type is stored anywhere —
33
+ * that route's own security model is a host concern. What is still NOT
34
+ * built, per the full design: a second, cookie-less media
35
+ * origin/process, and signed mint-URLs (a `media.download_original`
36
+ * permission would reserve that capability for a future route).
37
+ * `Content-Disposition` rules DO now exist, but only the one such a route
38
+ * needs (forcing `attachment` when the sniffed bytes are HTML/SVG-shaped).
39
+ * 4. **`MediaIngressPolicy`** — no SSRF guards, IP pinning, redirect
40
+ * handling, pixel-bomb caps, or magic-byte sniffing. Only a byte-size cap
41
+ * and an advisory `contentType` allowlist (see `DEFAULT_ALLOWED_MIME_TYPES`
42
+ * below) — an attacker-controlled `contentType` header is trusted, which
43
+ * the real ingress policy would never do.
44
+ * 5. **Where-used / `entry_refs`** — no real index exists because posts don't
45
+ * reference media by id in `bodyJson` yet. `purgeMedia`'s 409 guard uses
46
+ * "not yet trashed" as a stand-in for "referenced" (see its doc comment).
47
+ * 6. Virus scanning, remote-URL upload, video pipeline, S3 adapter — all
48
+ * explicitly deferred by design.
49
+ *
50
+ * See `types.ts`'s file header for the other disclosed scope adjustment: the
51
+ * bespoke `MediaRecord` table in place of a generic-entries model.
52
+ */
53
+ import { createHash } from "node:crypto";
54
+ import { MediaConflictError, MediaNotFoundError, MediaSourceImmutableError, MediaStillReferencedError, MediaValidationError, } from "./types.js";
55
+ import { withSha256Lock } from "./blob-gc-lock.js";
56
+ import { tombstoneBlobIfUnreferenced } from "./blob-gc.js";
57
+ export { MediaConflictError, MediaNotFoundError, MediaSourceImmutableError, MediaStillReferencedError, MediaValidationError, };
58
+ /** Default byte-size cap (this pass's stand-in for the real ingress policy's streaming cap). */
59
+ export const DEFAULT_MAX_UPLOAD_BYTES = 10 * 1024 * 1024; // 10 MiB
60
+ /**
61
+ * Advisory MIME allowlist. SVG is deliberately EXCLUDED (not "TODO, forgot") —
62
+ * SVG must be sanitized at ingest before it's safe to store;
63
+ * that sanitizer is not built in this pass, so SVG upload is rejected rather
64
+ * than accepted unsanitized.
65
+ *
66
+ * `video/mp4`/`video/webm` (owner-directed, 2026-08-24): the two formats
67
+ * `content-type-sniffer.ts` already recognizes by magic bytes. Unlike the four
68
+ * image types above, an accepted video is never re-encoded — there is no
69
+ * `TransformFormat` for video (`transform-types.ts`'s union is image-only), so
70
+ * a video asset's public URL bypasses the transform/rendition pipeline
71
+ * entirely and serves the original bytes as-is (host concern; see Tovu's
72
+ * `routes/site/media-rendition.ts`). This widens the SAME advisory,
73
+ * client-declared-string check item 4 above already discloses as untrusted —
74
+ * no new ingress hardening was added for video.
75
+ */
76
+ export const DEFAULT_ALLOWED_MIME_TYPES = new Set([
77
+ "image/jpeg",
78
+ "image/png",
79
+ "image/webp",
80
+ "image/gif",
81
+ "video/mp4",
82
+ "video/webm",
83
+ ]);
84
+ /**
85
+ * Enforces the "settable-once-from-absent" write-once rule for
86
+ * `source.sha256`: absent -> set exactly once, then immutable.
87
+ *
88
+ * Not currently reachable through any exposed write path — `uploadMedia` only
89
+ * ever calls it with `existing = undefined` (a brand-new row), and
90
+ * `UpdateMediaMetadataInput` has no `sha256` field at all, so
91
+ * `updateMediaMetadata` can't trigger the rejection branch even by accident.
92
+ * Kept as an explicit, directly-testable invariant (see
93
+ * `__tests__/media-service.test.ts`) rather than an implicit one enforced only
94
+ * by "the type doesn't have the field" — and it's the seam any future
95
+ * "replace source" operation would have to go through.
96
+ *
97
+ * @complexity O(1).
98
+ * @overallScore 100
99
+ */
100
+ export function resolveWriteOnceSource(required, _optional = {}) {
101
+ const { existing, requestedSha256 } = required;
102
+ if (existing && existing.sha256 !== requestedSha256) {
103
+ throw new MediaSourceImmutableError(`source.sha256 is write-once: cannot change '${existing.sha256}' to '${requestedSha256}'`);
104
+ }
105
+ return { sha256: requestedSha256 };
106
+ }
107
+ function deriveTitleFromFilename(filename) {
108
+ const base = filename.trim().replace(/\.[^./\\]+$/, "");
109
+ return base.trim() || "Untitled";
110
+ }
111
+ /**
112
+ * Validates, hashes, dedups by `(workspaceId, sha256)`, and writes a new media
113
+ * asset. Ordering (INV-1a): bytes are written (or found already
114
+ * present via dedup) BEFORE the media row is saved — a media row never exists
115
+ * without corresponding bytes.
116
+ *
117
+ * Blob dedup is per-hash, not per-upload: uploading the same bytes twice
118
+ * always creates two `MediaRecord`s (two distinct library entries, matching
119
+ * common CMS behavior) but writes the blob bytes only once. The dedup
120
+ * check-then-act sequence runs inside {@link withSha256Lock} (`blob-gc-lock.ts`)
121
+ * so it can't interleave with a concurrent `blob-gc.ts` delete-pass on the
122
+ * same sha256 (the "Serialization" invariant). If the existing blob row
123
+ * is `tombstoned` (a pending GC candidate), this resurrects it back to
124
+ * `active` in the same locked section instead of writing a duplicate blob —
125
+ * the dedup rule's explicit resurrect case.
126
+ *
127
+ * @complexity O(1) — one hash, one blob lookup, at most one blob write, one
128
+ * media write, one rendition write (the lock itself adds O(1) scheduling
129
+ * overhead, not a scan).
130
+ * @overallScore 100
131
+ */
132
+ export async function uploadMedia(required, optional = {}) {
133
+ const { deps, input } = required;
134
+ const maxUploadBytes = optional.maxUploadBytes ?? DEFAULT_MAX_UPLOAD_BYTES;
135
+ const allowedMimeTypes = optional.allowedMimeTypes ?? DEFAULT_ALLOWED_MIME_TYPES;
136
+ if (!allowedMimeTypes.has(input.contentType)) {
137
+ throw new MediaValidationError(`content type '${input.contentType}' is not allowed for upload`);
138
+ }
139
+ if (input.bytes.byteLength === 0) {
140
+ throw new MediaValidationError("uploaded file is empty");
141
+ }
142
+ if (input.bytes.byteLength > maxUploadBytes) {
143
+ throw new MediaValidationError(`uploaded file exceeds the ${maxUploadBytes}-byte size cap`);
144
+ }
145
+ const sha256 = createHash("sha256").update(input.bytes).digest("hex");
146
+ const nowIso = deps.clock.nowIso();
147
+ const storageKey = await withSha256Lock(sha256, async () => {
148
+ const existingBlob = await deps.blobRepo.findByHash({ workspaceId: input.workspaceId, sha256 });
149
+ if (existingBlob) {
150
+ if (existingBlob.status === "tombstoned") {
151
+ // Resurrect: cancel the pending GC in the same locked section rather
152
+ // than writing a duplicate blob (INV-1 dedup rule).
153
+ await deps.blobRepo.save({ ...existingBlob, status: "active", tombstonedAt: undefined });
154
+ }
155
+ return existingBlob.storageKey;
156
+ }
157
+ const written = await deps.blobStore.put({
158
+ workspaceId: input.workspaceId,
159
+ sha256,
160
+ bytes: input.bytes,
161
+ });
162
+ await deps.blobRepo.save({
163
+ id: deps.idGen.newId(),
164
+ workspaceId: input.workspaceId,
165
+ sha256,
166
+ storageKey: written.storageKey,
167
+ status: "active",
168
+ createdByPrincipal: input.createdByPrincipal,
169
+ createdAt: nowIso,
170
+ });
171
+ return written.storageKey;
172
+ });
173
+ const media = {
174
+ id: deps.idGen.newId(),
175
+ workspaceId: input.workspaceId,
176
+ title: deriveTitleFromFilename(input.filename),
177
+ alt: input.alt?.trim() ?? "",
178
+ caption: input.caption?.trim() ?? "",
179
+ credit: input.credit?.trim() ?? "",
180
+ source: resolveWriteOnceSource({ existing: undefined, requestedSha256: sha256 }),
181
+ status: "active",
182
+ createdAt: nowIso,
183
+ updatedAt: nowIso,
184
+ version: 1,
185
+ // No sizing UI on upload yet (only the edit panel got one — see `UpdateMediaMetadataInput`
186
+ // below) — every freshly uploaded asset starts with no override, set via a follow-up PATCH.
187
+ width: null,
188
+ height: null,
189
+ cssClass: null,
190
+ };
191
+ await deps.mediaRepo.save(media);
192
+ await deps.renditionRepo.save({
193
+ id: deps.idGen.newId(),
194
+ workspaceId: input.workspaceId,
195
+ assetId: media.id,
196
+ transformName: "original",
197
+ version: 1,
198
+ storageKey,
199
+ createdAt: nowIso,
200
+ });
201
+ return { media };
202
+ }
203
+ /**
204
+ * Lists all media in a workspace (all statuses — active + trashed; admin sees
205
+ * everything, mirrors an admin post listing). Purged assets are absent by
206
+ * construction (`purgeMedia` removes the row), not filtered here.
207
+ *
208
+ * @complexity O(1) repo call; the returned array is bounded by the
209
+ * workspace's media row count (repo-dependent — no pagination cap added in
210
+ * this pass, acceptable at walking-skeleton scale).
211
+ * @overallScore 100
212
+ */
213
+ export async function listMedia(required, _optional = {}) {
214
+ const media = await required.deps.mediaRepo.list({ workspaceId: required.input.workspaceId });
215
+ return { media };
216
+ }
217
+ /**
218
+ * Fetches one media asset by id, scoped to its workspace.
219
+ *
220
+ * @complexity O(1).
221
+ * @overallScore 100
222
+ */
223
+ export async function getMediaById(required, _optional = {}) {
224
+ const { workspaceId, id } = required.input;
225
+ const media = await required.deps.mediaRepo.findById({ workspaceId, id });
226
+ if (!media)
227
+ throw new MediaNotFoundError(`media '${id}' was not found`);
228
+ return { media };
229
+ }
230
+ /**
231
+ * Updates editorial-only fields (title/alt/caption/credit). `source.sha256` is
232
+ * write-once — this function's input type has no `sha256` field,
233
+ * so there is no code path here that can touch it (see `resolveWriteOnceSource`
234
+ * doc for the directly-tested invariant this relies on).
235
+ *
236
+ * @complexity O(1).
237
+ * @overallScore 100
238
+ */
239
+ /** Validates a `width`/`height` override: must be a positive integer. `null` (explicit clear) and
240
+ * `undefined` (leave unchanged) both bypass this — only a real provided number is checked. */
241
+ function assertPositiveIntegerOrThrow(value, field) {
242
+ if (!Number.isInteger(value) || value <= 0) {
243
+ throw new MediaValidationError(`media.${field} must be a positive integer, got ${value}`);
244
+ }
245
+ }
246
+ export async function updateMediaMetadata(required, _optional = {}) {
247
+ const { deps, input } = required;
248
+ const existing = await deps.mediaRepo.findById({ workspaceId: input.workspaceId, id: input.id });
249
+ if (!existing)
250
+ throw new MediaNotFoundError(`media '${input.id}' was not found`);
251
+ if (input.width !== undefined && input.width !== null)
252
+ assertPositiveIntegerOrThrow(input.width, "width");
253
+ if (input.height !== undefined && input.height !== null)
254
+ assertPositiveIntegerOrThrow(input.height, "height");
255
+ const media = {
256
+ ...existing,
257
+ title: input.title !== undefined ? input.title.trim() || existing.title : existing.title,
258
+ alt: input.alt !== undefined ? input.alt.trim() : existing.alt,
259
+ caption: input.caption !== undefined ? input.caption.trim() : existing.caption,
260
+ credit: input.credit !== undefined ? input.credit.trim() : existing.credit,
261
+ width: input.width !== undefined ? input.width : existing.width,
262
+ height: input.height !== undefined ? input.height : existing.height,
263
+ cssClass: input.cssClass !== undefined ? (input.cssClass === null ? null : input.cssClass.trim() || null) : existing.cssClass,
264
+ updatedAt: deps.clock.nowIso(),
265
+ version: existing.version + 1,
266
+ };
267
+ await deps.mediaRepo.save(media);
268
+ return { media };
269
+ }
270
+ /**
271
+ * Soft delete. Idempotent — trashing an already-trashed asset is a no-op
272
+ * (mirrors `disableMember`'s idempotency), not an error.
273
+ *
274
+ * @complexity O(1).
275
+ * @overallScore 100
276
+ */
277
+ export async function trashMedia(required, _optional = {}) {
278
+ const { deps, input } = required;
279
+ const existing = await deps.mediaRepo.findById(input);
280
+ if (!existing)
281
+ throw new MediaNotFoundError(`media '${input.id}' was not found`);
282
+ if (existing.status === "trashed")
283
+ return { media: existing };
284
+ const media = {
285
+ ...existing,
286
+ status: "trashed",
287
+ updatedAt: deps.clock.nowIso(),
288
+ version: existing.version + 1,
289
+ };
290
+ await deps.mediaRepo.save(media);
291
+ return { media };
292
+ }
293
+ /**
294
+ * Hard delete. Deletion ladder (mirrors `deleteMenu`): purge is
295
+ * rejected with `MediaStillReferencedError` (409-style) unless the asset has
296
+ * already been trashed first.
297
+ *
298
+ * SIMPLIFICATION (disclosed): the real design's guard checks the derived
299
+ * `entry_refs` where-used index (any live reference from published content).
300
+ * That index doesn't exist — posts don't reference media by id in `bodyJson`
301
+ * yet — so this build uses "not yet trashed" as the stand-in referenced-check.
302
+ * This is strictly weaker than the real invariant: a media asset that IS
303
+ * trashed but still referenced by a post would purge here without complaint,
304
+ * whereas the real system would keep blocking it. Do not read this function's
305
+ * 409 as evidence the where-used index exists.
306
+ *
307
+ * Once past the guard: rendition rows are removed, then the media row is
308
+ * removed. After that removal commits, the blob-GC tombstone-pass
309
+ * (`tombstoneBlobIfUnreferenced`, `blob-gc.ts`) runs for the asset's sha256 —
310
+ * it marks the blob `tombstoned` if-and-only-if the real "unreferenced"
311
+ * predicate holds (no other non-purged media row shares the hash, plus the
312
+ * disclosed `entry_refs`/retained-snapshot stubs). This function does **not**
313
+ * delete blob bytes itself anymore: the delete-pass (`runBlobGcDeletePass`)
314
+ * is grace-period-gated (`gc_grace`, default 30 days) and the unlink-pass
315
+ * (`runBlobGcUnlinkPass`) that actually removes bytes runs as a separate,
316
+ * explicit step — nothing schedules either automatically yet (see
317
+ * `blob-gc.ts`'s file header). This is a real behavior change from this
318
+ * function's prior "delete row, best-effort unlink immediately" shortcut,
319
+ * which is exactly the gap this task closes.
320
+ *
321
+ * @complexity O(n) in the workspace's media row count, inherited from the
322
+ * tombstone-pass's `isBlobUnreferenced` scan (see `blob-gc.ts`).
323
+ * @overallScore 100
324
+ */
325
+ export async function purgeMedia(required, _optional = {}) {
326
+ const { deps, input } = required;
327
+ const existing = await deps.mediaRepo.findById(input);
328
+ if (!existing)
329
+ throw new MediaNotFoundError(`media '${input.id}' was not found`);
330
+ if (existing.status !== "trashed") {
331
+ throw new MediaStillReferencedError(`media '${input.id}' must be trashed before it can be purged`, [
332
+ `media '${input.id}' is still active (stand-in for the real entry_refs ` +
333
+ `where-used index, which is not implemented — see purgeMedia's doc comment)`,
334
+ ]);
335
+ }
336
+ await deps.renditionRepo.removeByAsset({ workspaceId: input.workspaceId, assetId: input.id });
337
+ await deps.mediaRepo.remove({ workspaceId: input.workspaceId, id: input.id });
338
+ const clock = deps.clock ?? { nowIso: () => new Date().toISOString() };
339
+ await tombstoneBlobIfUnreferenced({
340
+ deps: { mediaRepo: deps.mediaRepo, blobRepo: deps.blobRepo, clock },
341
+ input: { workspaceId: input.workspaceId, sha256: existing.source.sha256 },
342
+ });
343
+ return { purged: true };
344
+ }
345
+ //# sourceMappingURL=media-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-service.js","sourceRoot":"","sources":["../../src/media/media-service.ts"],"names":[],"mappings":"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"}