@beechcms/core 0.8.0 → 0.9.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 (389) hide show
  1. package/dist/auth/account-email.d.ts +3 -0
  2. package/dist/auth/account-email.d.ts.map +1 -0
  3. package/dist/auth/account-email.js +9 -0
  4. package/dist/auth/password-reset-token.repository.d.ts +13 -2
  5. package/dist/auth/password-reset-token.repository.d.ts.map +1 -1
  6. package/dist/auth/user.repository.d.ts +69 -4
  7. package/dist/auth/user.repository.d.ts.map +1 -1
  8. package/dist/automations-grammar-words.d.ts +2 -0
  9. package/dist/automations-grammar-words.d.ts.map +1 -0
  10. package/dist/automations-grammar-words.js +8 -0
  11. package/dist/automations.repository.interface.d.ts +19 -0
  12. package/dist/automations.repository.interface.d.ts.map +1 -0
  13. package/dist/automations.repository.interface.js +3 -0
  14. package/dist/automations.runner.interface.d.ts +10 -0
  15. package/dist/automations.runner.interface.d.ts.map +1 -0
  16. package/dist/automations.runner.interface.js +3 -0
  17. package/dist/automations.runner.stub.d.ts +5 -0
  18. package/dist/automations.runner.stub.d.ts.map +1 -0
  19. package/dist/automations.runner.stub.js +7 -0
  20. package/dist/automations.types.d.ts +75 -0
  21. package/dist/automations.types.d.ts.map +1 -0
  22. package/dist/automations.types.js +3 -0
  23. package/dist/clock.d.ts +25 -0
  24. package/dist/clock.d.ts.map +1 -0
  25. package/dist/clock.js +11 -0
  26. package/dist/common/canonical-json.d.ts +31 -0
  27. package/dist/common/canonical-json.d.ts.map +1 -0
  28. package/dist/common/canonical-json.js +91 -0
  29. package/dist/content/content-scan.repository.d.ts +1 -1
  30. package/dist/content/content.repository.d.ts +154 -3
  31. package/dist/content/content.repository.d.ts.map +1 -1
  32. package/dist/content/content.repository.js +62 -0
  33. package/dist/content/deletion-ledger.d.ts +39 -0
  34. package/dist/content/deletion-ledger.d.ts.map +1 -0
  35. package/dist/content/deletion-ledger.js +3 -0
  36. package/dist/content/seed-media-purge.repository.d.ts +34 -0
  37. package/dist/content/seed-media-purge.repository.d.ts.map +1 -0
  38. package/dist/content/seed-media-purge.repository.js +3 -0
  39. package/dist/content/seed.repository.d.ts +14 -0
  40. package/dist/content/seed.repository.d.ts.map +1 -1
  41. package/dist/content-scan.repository.d.ts +9 -0
  42. package/dist/content-scan.repository.d.ts.map +1 -0
  43. package/dist/content-scan.repository.js +3 -0
  44. package/dist/content.repository.d.ts +247 -0
  45. package/dist/content.repository.d.ts.map +1 -0
  46. package/dist/content.repository.js +59 -0
  47. package/dist/dashboard-layout/content-view.d.ts +757 -0
  48. package/dist/dashboard-layout/content-view.d.ts.map +1 -0
  49. package/dist/dashboard-layout/content-view.js +285 -0
  50. package/dist/dashboard-layout/content-view.repository.d.ts +39 -0
  51. package/dist/dashboard-layout/content-view.repository.d.ts.map +1 -0
  52. package/dist/dashboard-layout/content-view.repository.js +3 -0
  53. package/dist/dashboard-layout/dashboard-layout.d.ts +5 -0
  54. package/dist/dashboard-layout/dashboard-layout.d.ts.map +1 -1
  55. package/dist/dashboard-layout/dashboard-layout.js +17 -9
  56. package/dist/dashboard-layout/kanban/kanban.d.ts +32 -18
  57. package/dist/dashboard-layout/kanban/kanban.d.ts.map +1 -1
  58. package/dist/dashboard-layout/kanban/kanban.js +45 -21
  59. package/dist/dashboard-layout/seed-layout.d.ts +22 -31
  60. package/dist/dashboard-layout/seed-layout.d.ts.map +1 -1
  61. package/dist/dashboard-layout/seed-layout.js +93 -18
  62. package/dist/dashboard-layout/seed-layout.repository.d.ts +1 -5
  63. package/dist/dashboard-layout/seed-layout.repository.d.ts.map +1 -1
  64. package/dist/dashboard-layout.d.ts +154 -0
  65. package/dist/dashboard-layout.d.ts.map +1 -0
  66. package/dist/dashboard-layout.js +186 -0
  67. package/dist/dashboard-layout.repository.d.ts +18 -0
  68. package/dist/dashboard-layout.repository.d.ts.map +1 -0
  69. package/dist/dashboard-layout.repository.js +3 -0
  70. package/dist/dashboard-permissions.d.ts +3 -0
  71. package/dist/dashboard-permissions.d.ts.map +1 -0
  72. package/dist/dashboard-permissions.js +11 -0
  73. package/dist/dashboard-scopes.d.ts +12 -0
  74. package/dist/dashboard-scopes.d.ts.map +1 -0
  75. package/dist/dashboard-scopes.js +30 -0
  76. package/dist/define-seed.d.ts +3 -0
  77. package/dist/define-seed.d.ts.map +1 -0
  78. package/dist/define-seed.js +5 -0
  79. package/dist/demo-data.repository.d.ts +5 -0
  80. package/dist/demo-data.repository.d.ts.map +1 -0
  81. package/dist/demo-data.repository.js +3 -0
  82. package/dist/email.provider.d.ts +32 -0
  83. package/dist/email.provider.d.ts.map +1 -0
  84. package/dist/email.provider.js +4 -0
  85. package/dist/engine/ddl/ddl.d.ts +247 -0
  86. package/dist/engine/ddl/ddl.d.ts.map +1 -0
  87. package/dist/engine/ddl/ddl.js +653 -0
  88. package/dist/engine/ddl/schema-mutator.d.ts +29 -0
  89. package/dist/engine/ddl/schema-mutator.d.ts.map +1 -0
  90. package/dist/engine/ddl/schema-mutator.js +3 -0
  91. package/dist/engine/ddl/seed-ddl-destructive.d.ts +40 -0
  92. package/dist/engine/ddl/seed-ddl-destructive.d.ts.map +1 -0
  93. package/dist/engine/ddl/seed-ddl-destructive.js +149 -0
  94. package/dist/engine/ddl/seed-ddl.d.ts +43 -0
  95. package/dist/engine/ddl/seed-ddl.d.ts.map +1 -0
  96. package/dist/engine/ddl/seed-ddl.js +115 -0
  97. package/dist/engine/ddl/seed-purge-guards.d.ts +7 -0
  98. package/dist/engine/ddl/seed-purge-guards.d.ts.map +1 -0
  99. package/dist/engine/ddl/seed-purge-guards.js +19 -0
  100. package/dist/engine/engine.d.ts +4 -3
  101. package/dist/engine/engine.d.ts.map +1 -1
  102. package/dist/engine/engine.js +4 -3
  103. package/dist/engine/introspection/introspection.d.ts +101 -0
  104. package/dist/engine/introspection/introspection.d.ts.map +1 -0
  105. package/dist/engine/introspection/introspection.js +127 -0
  106. package/dist/engine/introspection/relation-audit.d.ts +46 -0
  107. package/dist/engine/introspection/relation-audit.d.ts.map +1 -0
  108. package/dist/engine/introspection/relation-audit.js +103 -0
  109. package/dist/engine/introspection/schema-fingerprint.d.ts +74 -0
  110. package/dist/engine/introspection/schema-fingerprint.d.ts.map +1 -0
  111. package/dist/engine/introspection/schema-fingerprint.js +102 -0
  112. package/dist/engine/introspection.d.ts +101 -0
  113. package/dist/engine/introspection.d.ts.map +1 -0
  114. package/dist/engine/introspection.js +127 -0
  115. package/dist/engine/localization/localization.d.ts +127 -0
  116. package/dist/engine/localization/localization.d.ts.map +1 -0
  117. package/dist/engine/localization/localization.js +212 -0
  118. package/dist/engine/localization.d.ts +127 -0
  119. package/dist/engine/localization.d.ts.map +1 -0
  120. package/dist/engine/localization.js +212 -0
  121. package/dist/engine/privacy/policies.d.ts +58 -0
  122. package/dist/engine/privacy/policies.d.ts.map +1 -0
  123. package/dist/engine/privacy/policies.js +191 -0
  124. package/dist/engine/privacy/privacy.service.d.ts +78 -0
  125. package/dist/engine/privacy/privacy.service.d.ts.map +1 -0
  126. package/dist/engine/privacy/privacy.service.js +138 -0
  127. package/dist/engine/privacy.service.d.ts.map +1 -1
  128. package/dist/engine/query/active-clause.d.ts +19 -0
  129. package/dist/engine/query/active-clause.d.ts.map +1 -0
  130. package/dist/engine/query/active-clause.js +27 -0
  131. package/dist/engine/query/query.d.ts +36 -0
  132. package/dist/engine/query/query.d.ts.map +1 -0
  133. package/dist/engine/query/query.js +393 -0
  134. package/dist/engine/query/relations.d.ts +28 -0
  135. package/dist/engine/query/relations.d.ts.map +1 -0
  136. package/dist/engine/query/relations.js +25 -0
  137. package/dist/engine/query/serialize.d.ts +22 -0
  138. package/dist/engine/query/serialize.d.ts.map +1 -0
  139. package/dist/engine/query/serialize.js +175 -0
  140. package/dist/engine/schema-fingerprint.d.ts +73 -0
  141. package/dist/engine/schema-fingerprint.d.ts.map +1 -0
  142. package/dist/engine/schema-fingerprint.js +97 -0
  143. package/dist/engine/seed-registry.d.ts.map +1 -1
  144. package/dist/engine/seeds/candidate-ids.d.ts +14 -0
  145. package/dist/engine/seeds/candidate-ids.d.ts.map +1 -0
  146. package/dist/engine/seeds/candidate-ids.js +40 -0
  147. package/dist/engine/seeds/define-seed.d.ts +3 -0
  148. package/dist/engine/seeds/define-seed.d.ts.map +1 -0
  149. package/dist/engine/seeds/define-seed.js +5 -0
  150. package/dist/engine/seeds/seed-definition-diff.d.ts +38 -0
  151. package/dist/engine/seeds/seed-definition-diff.d.ts.map +1 -0
  152. package/dist/engine/seeds/seed-definition-diff.js +51 -0
  153. package/dist/engine/seeds/seed-registry.d.ts +88 -0
  154. package/dist/engine/seeds/seed-registry.d.ts.map +1 -0
  155. package/dist/engine/seeds/seed-registry.js +194 -0
  156. package/dist/engine/seeds/seed-types-generator.d.ts +25 -0
  157. package/dist/engine/seeds/seed-types-generator.d.ts.map +1 -0
  158. package/dist/engine/seeds/seed-types-generator.js +116 -0
  159. package/dist/engine/seeds/seed-validation.d.ts +35 -0
  160. package/dist/engine/seeds/seed-validation.d.ts.map +1 -0
  161. package/dist/engine/seeds/seed-validation.js +384 -0
  162. package/dist/engine/seeds/seeds.d.ts +20 -0
  163. package/dist/engine/seeds/seeds.d.ts.map +1 -0
  164. package/dist/engine/seeds/seeds.js +21 -0
  165. package/dist/engine/seeds/tag-migration.d.ts +73 -0
  166. package/dist/engine/seeds/tag-migration.d.ts.map +1 -0
  167. package/dist/engine/seeds/tag-migration.js +212 -0
  168. package/dist/engine/seeds/tag-options.d.ts +15 -0
  169. package/dist/engine/seeds/tag-options.d.ts.map +1 -0
  170. package/dist/engine/seeds/tag-options.js +111 -0
  171. package/dist/engine/seeds/tag-value.d.ts +31 -0
  172. package/dist/engine/seeds/tag-value.d.ts.map +1 -0
  173. package/dist/engine/seeds/tag-value.js +51 -0
  174. package/dist/engine/types.d.ts +59 -7
  175. package/dist/engine/types.d.ts.map +1 -1
  176. package/dist/engine/validation/cache.d.ts.map +1 -1
  177. package/dist/engine/validation/cache.js +20 -4
  178. package/dist/engine/validation/emptiness.d.ts +12 -0
  179. package/dist/engine/validation/emptiness.d.ts.map +1 -0
  180. package/dist/engine/validation/emptiness.js +33 -0
  181. package/dist/engine/validation/index.d.ts +11 -0
  182. package/dist/engine/validation/index.d.ts.map +1 -1
  183. package/dist/engine/validation/index.js +29 -33
  184. package/dist/engine/validation/primitives.d.ts +12 -0
  185. package/dist/engine/validation/primitives.d.ts.map +1 -1
  186. package/dist/engine/validation/primitives.js +22 -0
  187. package/dist/engine/validation/richtext-sanitizer.d.ts +9 -1
  188. package/dist/engine/validation/richtext-sanitizer.d.ts.map +1 -1
  189. package/dist/engine/validation/richtext-sanitizer.js +36 -7
  190. package/dist/engine/validation/schema-builders.d.ts +16 -0
  191. package/dist/engine/validation/schema-builders.d.ts.map +1 -1
  192. package/dist/engine/validation/schema-builders.js +125 -18
  193. package/dist/engine.d.ts +144 -0
  194. package/dist/engine.d.ts.map +1 -0
  195. package/dist/engine.js +741 -0
  196. package/dist/file-types.d.ts +13 -0
  197. package/dist/file-types.d.ts.map +1 -0
  198. package/dist/file-types.js +85 -0
  199. package/dist/hooks.d.ts +29 -0
  200. package/dist/hooks.d.ts.map +1 -0
  201. package/dist/hooks.js +3 -0
  202. package/dist/id-generator.d.ts +26 -0
  203. package/dist/id-generator.d.ts.map +1 -0
  204. package/dist/id-generator.js +12 -0
  205. package/dist/idempotency.repository.d.ts +13 -0
  206. package/dist/idempotency.repository.d.ts.map +1 -0
  207. package/dist/idempotency.repository.js +3 -0
  208. package/dist/index.d.ts +34 -11
  209. package/dist/index.d.ts.map +1 -1
  210. package/dist/index.js +34 -11
  211. package/dist/kanban-position.repository.d.ts +19 -0
  212. package/dist/kanban-position.repository.d.ts.map +1 -0
  213. package/dist/kanban-position.repository.js +3 -0
  214. package/dist/kanban.d.ts +75 -0
  215. package/dist/kanban.d.ts.map +1 -0
  216. package/dist/kanban.js +82 -0
  217. package/dist/layout-permissions.d.ts +3 -0
  218. package/dist/layout-permissions.d.ts.map +1 -0
  219. package/dist/layout-permissions.js +11 -0
  220. package/dist/media/file-types.d.ts +12 -0
  221. package/dist/media/file-types.d.ts.map +1 -1
  222. package/dist/media/file-types.js +24 -4
  223. package/dist/media/image-transformer.d.ts +34 -0
  224. package/dist/media/image-transformer.d.ts.map +1 -0
  225. package/dist/media/image-transformer.js +3 -0
  226. package/dist/media/magic-bytes.d.ts.map +1 -1
  227. package/dist/media/magic-bytes.js +19 -9
  228. package/dist/media/media-transform.d.ts +92 -0
  229. package/dist/media/media-transform.d.ts.map +1 -0
  230. package/dist/media/media-transform.js +197 -0
  231. package/dist/media/media.repository.d.ts +5 -0
  232. package/dist/media/media.repository.d.ts.map +1 -1
  233. package/dist/media.repository.d.ts +61 -0
  234. package/dist/media.repository.d.ts.map +1 -0
  235. package/dist/media.repository.js +3 -0
  236. package/dist/notifications/notification.repository.d.ts +11 -2
  237. package/dist/notifications/notification.repository.d.ts.map +1 -1
  238. package/dist/oauth/authorization-code.repository.d.ts +10 -5
  239. package/dist/oauth/authorization-code.repository.d.ts.map +1 -1
  240. package/dist/oauth/role-guard.d.ts +30 -11
  241. package/dist/oauth/role-guard.d.ts.map +1 -1
  242. package/dist/oauth/role-guard.js +27 -5
  243. package/dist/oauth/token.repository.d.ts +2 -0
  244. package/dist/oauth/token.repository.d.ts.map +1 -1
  245. package/dist/policies.d.ts +10 -0
  246. package/dist/policies.d.ts.map +1 -0
  247. package/dist/policies.js +33 -0
  248. package/dist/queue/queue.interface.d.ts +9 -1
  249. package/dist/queue/queue.interface.d.ts.map +1 -1
  250. package/dist/queue/queue.stub.d.ts +1 -1
  251. package/dist/queue/queue.stub.d.ts.map +1 -1
  252. package/dist/queue/queue.stub.js +2 -3
  253. package/dist/queue.interface.d.ts +39 -0
  254. package/dist/queue.interface.d.ts.map +1 -0
  255. package/dist/queue.interface.js +3 -0
  256. package/dist/queue.stub.d.ts +6 -0
  257. package/dist/queue.stub.d.ts.map +1 -0
  258. package/dist/queue.stub.js +8 -0
  259. package/dist/rate-limit/token-bucket-rate-limiter.d.ts +7 -0
  260. package/dist/rate-limit/token-bucket-rate-limiter.d.ts.map +1 -1
  261. package/dist/rate-limit/token-bucket-rate-limiter.js +66 -0
  262. package/dist/rbac/evaluate.d.ts +57 -0
  263. package/dist/rbac/evaluate.d.ts.map +1 -0
  264. package/dist/rbac/evaluate.js +113 -0
  265. package/dist/rbac/invitation.repository.d.ts +84 -0
  266. package/dist/rbac/invitation.repository.d.ts.map +1 -0
  267. package/dist/rbac/invitation.repository.js +3 -0
  268. package/dist/rbac/permissions.d.ts +39 -0
  269. package/dist/rbac/permissions.d.ts.map +1 -0
  270. package/dist/rbac/permissions.js +43 -0
  271. package/dist/rbac/types.d.ts +130 -0
  272. package/dist/rbac/types.d.ts.map +1 -0
  273. package/dist/rbac/types.js +4 -0
  274. package/dist/relations.d.ts +28 -0
  275. package/dist/relations.d.ts.map +1 -0
  276. package/dist/relations.js +25 -0
  277. package/dist/richtext-render.d.ts +11 -0
  278. package/dist/richtext-render.d.ts.map +1 -0
  279. package/dist/richtext-render.js +87 -0
  280. package/dist/richtext.d.ts +11 -0
  281. package/dist/richtext.d.ts.map +1 -0
  282. package/dist/richtext.js +13 -0
  283. package/dist/scheduler.interface.d.ts +4 -0
  284. package/dist/scheduler.interface.d.ts.map +1 -0
  285. package/dist/scheduler.interface.js +3 -0
  286. package/dist/scheduler.stub.d.ts +5 -0
  287. package/dist/scheduler.stub.d.ts.map +1 -0
  288. package/dist/scheduler.stub.js +7 -0
  289. package/dist/schema/canonical.d.ts +15 -0
  290. package/dist/schema/canonical.d.ts.map +1 -0
  291. package/dist/schema/canonical.js +37 -0
  292. package/dist/schema/define.d.ts +42 -0
  293. package/dist/schema/define.d.ts.map +1 -0
  294. package/dist/schema/define.js +56 -0
  295. package/dist/schema/emit.d.ts +14 -0
  296. package/dist/schema/emit.d.ts.map +1 -0
  297. package/dist/schema/emit.js +43 -0
  298. package/dist/schema/index.d.ts +12 -0
  299. package/dist/schema/index.d.ts.map +1 -0
  300. package/dist/schema/index.js +13 -0
  301. package/dist/schema/manifest-seeds.d.ts +12 -0
  302. package/dist/schema/manifest-seeds.d.ts.map +1 -0
  303. package/dist/schema/manifest-seeds.js +48 -0
  304. package/dist/schema/manifest-validation.d.ts +13 -0
  305. package/dist/schema/manifest-validation.d.ts.map +1 -0
  306. package/dist/schema/manifest-validation.js +41 -0
  307. package/dist/schema/manifest.types.d.ts +54 -0
  308. package/dist/schema/manifest.types.d.ts.map +1 -0
  309. package/dist/schema/manifest.types.js +7 -0
  310. package/dist/schema-mutator.d.ts +26 -0
  311. package/dist/schema-mutator.d.ts.map +1 -0
  312. package/dist/schema-mutator.js +3 -0
  313. package/dist/search/search.repository.d.ts +5 -4
  314. package/dist/search/search.repository.d.ts.map +1 -1
  315. package/dist/search/vector-extractor.d.ts.map +1 -1
  316. package/dist/search/vector-extractor.js +23 -2
  317. package/dist/search/vector.repository.d.ts +2 -1
  318. package/dist/search/vector.repository.d.ts.map +1 -1
  319. package/dist/security/time-trap-token.repository.d.ts +5 -3
  320. package/dist/security/time-trap-token.repository.d.ts.map +1 -1
  321. package/dist/seed-ddl-destructive.d.ts +40 -0
  322. package/dist/seed-ddl-destructive.d.ts.map +1 -0
  323. package/dist/seed-ddl-destructive.js +149 -0
  324. package/dist/seed-ddl.d.ts +40 -0
  325. package/dist/seed-ddl.d.ts.map +1 -0
  326. package/dist/seed-ddl.js +100 -0
  327. package/dist/seed-layout.d.ts +145 -0
  328. package/dist/seed-layout.d.ts.map +1 -0
  329. package/dist/seed-layout.js +192 -0
  330. package/dist/seed-layout.repository.d.ts +22 -0
  331. package/dist/seed-layout.repository.d.ts.map +1 -0
  332. package/dist/seed-layout.repository.js +3 -0
  333. package/dist/seed-registry.d.ts +71 -0
  334. package/dist/seed-registry.d.ts.map +1 -0
  335. package/dist/seed-registry.js +143 -0
  336. package/dist/seed-types-generator.d.ts +1 -1
  337. package/dist/seed-types-generator.d.ts.map +1 -1
  338. package/dist/seed-validation.d.ts +23 -0
  339. package/dist/seed-validation.d.ts.map +1 -0
  340. package/dist/seed-validation.js +224 -0
  341. package/dist/seed.repository.d.ts +37 -0
  342. package/dist/seed.repository.d.ts.map +1 -0
  343. package/dist/seed.repository.js +3 -0
  344. package/dist/seeds.d.ts +20 -0
  345. package/dist/seeds.d.ts.map +1 -0
  346. package/dist/seeds.js +21 -0
  347. package/dist/settings/site-settings.repository.d.ts +8 -0
  348. package/dist/settings/site-settings.repository.d.ts.map +1 -1
  349. package/dist/site-settings.repository.d.ts +16 -0
  350. package/dist/site-settings.repository.d.ts.map +1 -0
  351. package/dist/site-settings.repository.js +3 -0
  352. package/dist/slug-utils.d.ts +18 -0
  353. package/dist/slug-utils.d.ts.map +1 -0
  354. package/dist/slug-utils.js +32 -0
  355. package/dist/storage.d.ts +46 -0
  356. package/dist/storage.d.ts.map +1 -0
  357. package/dist/storage.js +3 -0
  358. package/dist/transfer/csv.d.ts +34 -0
  359. package/dist/transfer/csv.d.ts.map +1 -0
  360. package/dist/transfer/csv.js +135 -0
  361. package/dist/transfer/flat-seed.d.ts +13 -0
  362. package/dist/transfer/flat-seed.d.ts.map +1 -0
  363. package/dist/transfer/flat-seed.js +50 -0
  364. package/dist/transfer/index.d.ts +7 -0
  365. package/dist/transfer/index.d.ts.map +1 -0
  366. package/dist/transfer/index.js +8 -0
  367. package/dist/transfer/ndjson.d.ts +25 -0
  368. package/dist/transfer/ndjson.d.ts.map +1 -0
  369. package/dist/transfer/ndjson.js +62 -0
  370. package/dist/transfer/row-mapping.d.ts +36 -0
  371. package/dist/transfer/row-mapping.d.ts.map +1 -0
  372. package/dist/transfer/row-mapping.js +97 -0
  373. package/dist/transfer/transfer.constants.d.ts +20 -0
  374. package/dist/transfer/transfer.constants.d.ts.map +1 -0
  375. package/dist/transfer/transfer.constants.js +21 -0
  376. package/dist/transfer/transfer.types.d.ts +46 -0
  377. package/dist/transfer/transfer.types.d.ts.map +1 -0
  378. package/dist/transfer/transfer.types.js +6 -0
  379. package/dist/types.d.ts +243 -0
  380. package/dist/types.d.ts.map +1 -0
  381. package/dist/types.js +3 -0
  382. package/dist/validation.d.ts +50 -0
  383. package/dist/validation.d.ts.map +1 -0
  384. package/dist/validation.js +660 -0
  385. package/dist/webhook-validation.d.ts +3 -0
  386. package/dist/webhook-validation.d.ts.map +1 -0
  387. package/dist/webhook-validation.js +6 -0
  388. package/package.json +11 -6
  389. package/dist/.tsbuildinfo +0 -1
@@ -0,0 +1,113 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ import { GLOBAL_SCOPE } from './permissions.js';
4
+ /**
5
+ * Folds a user's active assignments into their effective authority.
6
+ *
7
+ * The model is strictly additive: every assignment can only widen the result, and
8
+ * assignments referencing an unknown role are ignored rather than treated as an error.
9
+ *
10
+ * @param assignments - Active assignments, already decay-filtered by the repository.
11
+ * @param roles - The roles those assignments reference; extra roles are harmless.
12
+ */
13
+ export function buildEffectivePermissions(assignments, roles) {
14
+ const rolesById = new Map(roles.map(role => [role.id, role]));
15
+ const global = new Set();
16
+ const byScope = new Map();
17
+ for (const assignment of assignments) {
18
+ const role = rolesById.get(assignment.roleId);
19
+ if (!role)
20
+ continue;
21
+ if (assignment.scope === GLOBAL_SCOPE) {
22
+ for (const permission of role.permissions)
23
+ global.add(permission);
24
+ continue;
25
+ }
26
+ let bucket = byScope.get(assignment.scope);
27
+ if (!bucket) {
28
+ bucket = new Set();
29
+ byScope.set(assignment.scope, bucket);
30
+ }
31
+ for (const permission of role.permissions)
32
+ bucket.add(permission);
33
+ }
34
+ return { global, byScope };
35
+ }
36
+ /**
37
+ * Returns everything the caller may do within one scope: the union of their global
38
+ * permissions and the permissions granted on that specific seed.
39
+ */
40
+ export function permissionsForScope(effective, scope) {
41
+ if (scope === GLOBAL_SCOPE)
42
+ return effective.global;
43
+ const scoped = effective.byScope.get(scope);
44
+ if (!scoped)
45
+ return effective.global;
46
+ return new Set([...effective.global, ...scoped]);
47
+ }
48
+ /**
49
+ * The single authorization question: may this caller perform `permission` on `scope`?
50
+ *
51
+ * A global grant satisfies any scope. A scoped grant satisfies only its own seed and
52
+ * never {@link GLOBAL_SCOPE} — that asymmetry is what stops horizontal escalation.
53
+ */
54
+ export function hasPermission(effective, permission, scope) {
55
+ if (effective.global.has(permission))
56
+ return true;
57
+ if (scope === GLOBAL_SCOPE)
58
+ return false;
59
+ return effective.byScope.get(scope)?.has(permission) === true;
60
+ }
61
+ /**
62
+ * The anti-escalation rule: an actor may only hand out authority they already hold.
63
+ *
64
+ * A grant is legal only when the actor holds every permission being granted, at the
65
+ * scope it is being granted on. Consequently an actor scoped to seed X can never mint
66
+ * a global assignment, and can never include a permission absent from their own set —
67
+ * regardless of what the role itself contains.
68
+ *
69
+ * @param actor - The granting user's effective authority.
70
+ * @param targetScope - The scope the new assignment would apply to.
71
+ * @param targetPermissions - The permissions carried by the role being assigned.
72
+ */
73
+ export function canGrant(actor, targetScope, targetPermissions) {
74
+ if (targetScope === GLOBAL_SCOPE) {
75
+ return targetPermissions.every(permission => actor.global.has(permission));
76
+ }
77
+ const held = permissionsForScope(actor, targetScope);
78
+ return targetPermissions.every(permission => held.has(permission));
79
+ }
80
+ /**
81
+ * Every permission the actor holds at ANY scope — global or seed-scoped — folded into
82
+ * one set.
83
+ *
84
+ * This is deliberately NOT an authorization primitive: it answers "could this actor
85
+ * ever grant X somewhere", not "may this actor do X here". Only {@link hasPermission}
86
+ * and {@link canGrant} answer the latter, and every route-level decision must keep
87
+ * using them.
88
+ */
89
+ export function permissionsHeldAnywhere(effective) {
90
+ const held = new Set(effective.global);
91
+ for (const bucket of effective.byScope.values()) {
92
+ for (const permission of bucket)
93
+ held.add(permission);
94
+ }
95
+ return held;
96
+ }
97
+ /**
98
+ * Whether the actor holds `permission` on at least one scope.
99
+ *
100
+ * Backs the coarse route gate for administration endpoints whose scope is not in the
101
+ * URL: the gate keeps out callers with no administrative authority at all, and the
102
+ * slice then makes the exact per-scope decision with {@link hasPermission} /
103
+ * {@link canGrant}. Never use it as the final authorization check.
104
+ */
105
+ export function hasPermissionAnywhere(effective, permission) {
106
+ if (effective.global.has(permission))
107
+ return true;
108
+ for (const bucket of effective.byScope.values()) {
109
+ if (bucket.has(permission))
110
+ return true;
111
+ }
112
+ return false;
113
+ }
@@ -0,0 +1,84 @@
1
+ import type { NewUserInput } from '../auth/user.repository.js';
2
+ import type { PageRequest } from './types.js';
3
+ import type { Scope } from './permissions.js';
4
+ /** One invitation row. `tokenHash` is deliberately absent: nothing above the storage
5
+ * boundary ever needs it, and an administration listing must not carry credential
6
+ * material (same rule as AccountSummary omitting passwordHash). */
7
+ export interface InvitationRecord {
8
+ id: string;
9
+ email: string;
10
+ roleId: string;
11
+ scope: Scope;
12
+ invitedBy: string;
13
+ expiresAt: number;
14
+ createdAt: number;
15
+ /** Non-null once redeemed. Single-use is enforced by {@link IInvitationRepository.redeem}. */
16
+ usedAt: number | null;
17
+ }
18
+ export interface NewInvitationInput {
19
+ email: string;
20
+ tokenHash: string;
21
+ roleId: string;
22
+ scope: Scope;
23
+ invitedBy: string;
24
+ expiresAt: number;
25
+ }
26
+ /** A live invitation resolved from a bearer token, with the pre-assignment it carries. */
27
+ export interface ValidatedInvitation {
28
+ id: string;
29
+ email: string;
30
+ roleId: string;
31
+ scope: Scope;
32
+ invitedBy: string;
33
+ }
34
+ /** What {@link IInvitationRepository.redeem} writes in one transaction. */
35
+ export interface InvitationRedemption {
36
+ invitationId: string;
37
+ user: NewUserInput;
38
+ assignmentId: string;
39
+ roleId: string;
40
+ scope: Scope;
41
+ usedAt: number;
42
+ }
43
+ /**
44
+ * Storage contract for onboarding invitations.
45
+ *
46
+ * Deliberately shaped after {@link IPasswordResetTokenRepository}: a single-use,
47
+ * expiring, hash-only bearer credential is the same lifecycle, and the codebase keeps
48
+ * exactly one shape for it.
49
+ */
50
+ export interface IInvitationRepository {
51
+ /** Deletes every unredeemed invitation for an email before a new one is issued, so at
52
+ * most one live token per address exists at any time. They are removed, not marked
53
+ * used: `used_at` means "redeemed", and a superseded row must never be reported as
54
+ * accepted. */
55
+ supersedePending(email: string): Promise<void>;
56
+ /** Stores a new invitation. Only the hash is persisted, never the plaintext.
57
+ * Returns the new invitation id. */
58
+ create(input: NewInvitationInput): Promise<string>;
59
+ /** Resolves a live (unused, unexpired) invitation by token hash. Null otherwise —
60
+ * expired, already used and unknown are deliberately indistinguishable. */
61
+ findValidByHash(tokenHash: string, nowTimestamp: number): Promise<ValidatedInvitation | null>;
62
+ /**
63
+ * Redeems an invitation: creates the account, writes its (role, scope) assignment and
64
+ * consumes the invitation in ONE atomic write. Either all three land or none does, so a
65
+ * failure can neither burn the invitation nor leave an account without its role.
66
+ *
67
+ * Returns TRUE only when THIS call performed the transition (`used_at IS NULL` at write
68
+ * time), which is what makes redemption single-use under concurrency; FALSE means the
69
+ * invitation was consumed or revoked meanwhile and nothing was written. Throws when the
70
+ * email is already registered (UNIQUE), writing nothing.
71
+ */
72
+ redeem(input: InvitationRedemption): Promise<boolean>;
73
+ /** One invitation by id, regardless of state. Null when absent. */
74
+ findById(invitationId: string): Promise<InvitationRecord | null>;
75
+ /** One page of invitations, newest first. */
76
+ list(page: PageRequest): Promise<InvitationRecord[]>;
77
+ /** Replaces the token and expiry of an existing PENDING-or-EXPIRED invitation,
78
+ * preserving its (role, scope, email) pre-assignment. Returns false when the row is
79
+ * absent or already used — a consumed invitation is never re-armed. */
80
+ regenerate(invitationId: string, tokenHash: string, expiresAt: number): Promise<boolean>;
81
+ /** Revokes (hard-deletes) an invitation. Returns false when it did not exist. */
82
+ delete(invitationId: string): Promise<boolean>;
83
+ }
84
+ //# sourceMappingURL=invitation.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invitation.repository.d.ts","sourceRoot":"","sources":["../../src/rbac/invitation.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C;;oEAEoE;AACpE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,8FAA8F;IAC9F,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,2EAA2E;AAC3E,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,YAAY,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;oBAGgB;IAChB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9C;yCACqC;IACrC,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAElD;gFAC4E;IAC5E,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAA;IAE7F;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAErD,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAEhE,6CAA6C;IAC7C,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAEpD;;4EAEwE;IACxE,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAExF,iFAAiF;IACjF,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC/C"}
@@ -0,0 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The closed atomic permission vocabulary.
3
+ *
4
+ * This tuple is the single source of truth for what a role may contain. It is
5
+ * CLOSED BY DESIGN: new permissions arrive only as a developer code change plus a
6
+ * migration widening the `role_permissions` CHECK constraint. Nothing at runtime —
7
+ * no API, no plugin, no dashboard screen — may extend it.
8
+ *
9
+ * `manage_seeds` (or any schema-mutation permission) is deliberately absent and must
10
+ * never be added. Seed schema mutation stays a developer capability exercised outside
11
+ * the dashboard, via CLI and migrations.
12
+ *
13
+ * Each non-CRUD dashboard surface owns one dedicated permission (`view_analytics` is
14
+ * the first). Absence of the permission hides the surface; there is no default-visible
15
+ * exception.
16
+ */
17
+ export declare const PERMISSIONS: readonly ["content:read", "content:create", "content:update", "content:delete", "manage_users", "manage_roles", "view_analytics"];
18
+ /** A single atomic permission drawn from the closed vocabulary. */
19
+ export type Permission = (typeof PERMISSIONS)[number];
20
+ /**
21
+ * The sentinel scope granting a permission across every seed, present and future.
22
+ * Reserved for cross-cutting coordination roles (e.g. SuperAdmin).
23
+ */
24
+ export declare const GLOBAL_SCOPE = "*";
25
+ /**
26
+ * A permission perimeter: either {@link GLOBAL_SCOPE} or a `seeds.slug`.
27
+ * Isolation is per-seed, never row-level.
28
+ */
29
+ export type Scope = string;
30
+ /** Narrows an arbitrary string to a known permission. */
31
+ export declare function isPermission(value: string): value is Permission;
32
+ /**
33
+ * Name of the system role seeded by `0000_v040_base.sql` with the full permission set.
34
+ *
35
+ * `roles.name` is UNIQUE, so the name is a stable handle; the id is minted by the
36
+ * migration and differs per database, which is why nothing may hardcode it.
37
+ */
38
+ export declare const SUPER_ADMIN_ROLE_NAME = "SuperAdmin";
39
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/rbac/permissions.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,mIAQd,CAAA;AAEV,mEAAmE;AACnE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAErD;;;GAGG;AACH,eAAO,MAAM,YAAY,MAAM,CAAA;AAE/B;;;GAGG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAA;AAE1B,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,UAAU,CAE/D;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAA"}
@@ -0,0 +1,43 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * The closed atomic permission vocabulary.
5
+ *
6
+ * This tuple is the single source of truth for what a role may contain. It is
7
+ * CLOSED BY DESIGN: new permissions arrive only as a developer code change plus a
8
+ * migration widening the `role_permissions` CHECK constraint. Nothing at runtime —
9
+ * no API, no plugin, no dashboard screen — may extend it.
10
+ *
11
+ * `manage_seeds` (or any schema-mutation permission) is deliberately absent and must
12
+ * never be added. Seed schema mutation stays a developer capability exercised outside
13
+ * the dashboard, via CLI and migrations.
14
+ *
15
+ * Each non-CRUD dashboard surface owns one dedicated permission (`view_analytics` is
16
+ * the first). Absence of the permission hides the surface; there is no default-visible
17
+ * exception.
18
+ */
19
+ export const PERMISSIONS = [
20
+ 'content:read',
21
+ 'content:create',
22
+ 'content:update',
23
+ 'content:delete',
24
+ 'manage_users',
25
+ 'manage_roles',
26
+ 'view_analytics',
27
+ ];
28
+ /**
29
+ * The sentinel scope granting a permission across every seed, present and future.
30
+ * Reserved for cross-cutting coordination roles (e.g. SuperAdmin).
31
+ */
32
+ export const GLOBAL_SCOPE = '*';
33
+ /** Narrows an arbitrary string to a known permission. */
34
+ export function isPermission(value) {
35
+ return PERMISSIONS.includes(value);
36
+ }
37
+ /**
38
+ * Name of the system role seeded by `0000_v040_base.sql` with the full permission set.
39
+ *
40
+ * `roles.name` is UNIQUE, so the name is a stable handle; the id is minted by the
41
+ * migration and differs per database, which is why nothing may hardcode it.
42
+ */
43
+ export const SUPER_ADMIN_ROLE_NAME = 'SuperAdmin';
@@ -0,0 +1,130 @@
1
+ import type { Permission, Scope } from './permissions.js';
2
+ /** A named, reusable bundle of atomic permissions. */
3
+ export interface RoleRecord {
4
+ id: string;
5
+ name: string;
6
+ description: string | null;
7
+ icon?: string | null;
8
+ /** System roles (e.g. SuperAdmin) are seeded by migration and may not be deleted. */
9
+ isSystem: boolean;
10
+ /** Always a subset of `PERMISSIONS`; unknown values are dropped at the storage boundary. */
11
+ permissions: Permission[];
12
+ createdAt: number;
13
+ updatedAt: number;
14
+ }
15
+ /** One (user, role, scope) triple. A user may hold N independent assignments. */
16
+ export interface PermissionAssignment {
17
+ id: string;
18
+ userId: string;
19
+ roleId: string;
20
+ scope: Scope;
21
+ }
22
+ export interface NewRoleInput {
23
+ name: string;
24
+ description: string | null;
25
+ icon?: string | null;
26
+ permissions: readonly Permission[];
27
+ }
28
+ export interface NewAssignmentInput {
29
+ userId: string;
30
+ roleId: string;
31
+ scope: Scope;
32
+ }
33
+ /**
34
+ * A caller's resolved authority, computed once per request from their active
35
+ * assignments. Purely additive: there is no negative permission and no conflict
36
+ * resolution between roles.
37
+ */
38
+ export interface EffectivePermissions {
39
+ /** Permissions held at {@link GLOBAL_SCOPE}; they apply to every seed. */
40
+ global: ReadonlySet<Permission>;
41
+ /** Permissions held at a specific seed slug, keyed by that slug. */
42
+ byScope: ReadonlyMap<Scope, ReadonlySet<Permission>>;
43
+ }
44
+ /** One page of an administration listing. `limit` is at most {@link MAX_PAGE_SIZE}. */
45
+ export interface PageRequest {
46
+ limit: number;
47
+ offset: number;
48
+ }
49
+ /** Largest page the administration listings serve. Keeps every `IN (...)` fan-out under D1's bound-parameter cap. */
50
+ export declare const MAX_PAGE_SIZE = 100;
51
+ /**
52
+ * Outcome of a write that must never remove the platform's last active global
53
+ * administrator. The repository enforces the invariant inside the write itself (one
54
+ * conditional statement), so two concurrent requests cannot both pass a stale count.
55
+ * - `applied`: the write happened.
56
+ * - `not-found`: the target does not exist (or is an immutable system role); nothing changed.
57
+ * - `last-global-admin`: refused because it would leave no other active global administrator.
58
+ */
59
+ export type AdminGuardedResult = 'applied' | 'not-found' | 'last-global-admin';
60
+ /** Storage contract for roles and their permission bundles. */
61
+ export interface IRoleRepository {
62
+ /** Retrieves a role with its permissions, or null when it does not exist. */
63
+ findById(roleId: string): Promise<RoleRecord | null>;
64
+ /** Retrieves several roles in one round trip. Missing ids are simply absent. */
65
+ findByIds(roleIds: readonly string[]): Promise<RoleRecord[]>;
66
+ /** Lists every role, system roles included, ordered by name. */
67
+ listAll(): Promise<RoleRecord[]>;
68
+ /** Creates a role and its permission rows atomically. Returns the new role id. */
69
+ create(input: NewRoleInput): Promise<string>;
70
+ /**
71
+ * Replaces a role's name, description and full permission set atomically.
72
+ *
73
+ * `not-found` — changing NOTHING, permissions included — when the role does not exist or
74
+ * is a system role. System roles are seeded by migration and are immutable in both halves
75
+ * of the write, which is the guarantee callers rely on to keep `SuperAdmin` intact.
76
+ * `last-global-admin` when the new set drops `manage_users` from a role that carries the
77
+ * last active global administrator; nothing is written then either.
78
+ */
79
+ update(roleId: string, input: NewRoleInput): Promise<AdminGuardedResult>;
80
+ /**
81
+ * Deletes a non-system role and, by cascade, its permissions and assignments.
82
+ * `not-found` when the role does not exist or is a system role; `last-global-admin` when
83
+ * the role carries the last active global administrator.
84
+ */
85
+ delete(roleId: string): Promise<AdminGuardedResult>;
86
+ }
87
+ /** Storage contract for (user, role, scope) assignments. */
88
+ export interface IRoleAssignmentRepository {
89
+ /**
90
+ * Lists a user's assignments that currently grant anything.
91
+ *
92
+ * An assignment is skipped when its scope names a seed that is absent or
93
+ * `status != 'active'`, so scopes decay with their seed and revive with it.
94
+ * {@link GLOBAL_SCOPE} assignments are always returned.
95
+ */
96
+ listActiveForUser(userId: string): Promise<PermissionAssignment[]>;
97
+ /** Lists every assignment referencing a role, decay filter NOT applied. */
98
+ listByRole(roleId: string): Promise<PermissionAssignment[]>;
99
+ /** Creates an assignment. Returns its id; an existing identical triple is a no-op. */
100
+ create(input: NewAssignmentInput): Promise<string>;
101
+ /**
102
+ * Removes one assignment. `not-found` when it did not exist; `last-global-admin` when it is
103
+ * the global `manage_users` assignment of the last active global administrator.
104
+ */
105
+ delete(assignmentId: string): Promise<AdminGuardedResult>;
106
+ /**
107
+ * Read-only twin of the {@link delete} guard: would removing this assignment leave no
108
+ * other active global administrator? ADVISORY — it only lets a caller that refuses for
109
+ * another reason (the Developer account) report the more fundamental one; it is never a
110
+ * substitute for the guard inside {@link delete}.
111
+ */
112
+ isLastGlobalAdminAssignment(assignmentId: string): Promise<boolean>;
113
+ /** One assignment by id, decay filter NOT applied. Null when absent. */
114
+ findById(assignmentId: string): Promise<PermissionAssignment | null>;
115
+ /**
116
+ * Every assignment of the given users, decay filter NOT applied, in ONE round trip.
117
+ *
118
+ * Exists so the account-list endpoint can resolve the scopes of one page of accounts
119
+ * without a query per account. Callers pass at most {@link MAX_PAGE_SIZE} ids (D1 caps
120
+ * bound parameters per statement); an empty list returns an empty list.
121
+ */
122
+ listForUsers(userIds: readonly string[]): Promise<PermissionAssignment[]>;
123
+ /**
124
+ * Every assignment of one user, decay filter NOT applied — administration screens must
125
+ * see (and be able to remove) a row whose seed is currently deleted, which
126
+ * {@link listActiveForUser} deliberately hides.
127
+ */
128
+ listAllForUser(userId: string): Promise<PermissionAssignment[]>;
129
+ }
130
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rbac/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /** Largest page the administration listings serve. Keeps every `IN (...)` fan-out under D1's bound-parameter cap. */
4
+ export const MAX_PAGE_SIZE = 100;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Back-reference helpers for the Beech CMS relation system.
3
+ *
4
+ * `buildBackrefMap` is a pure function that iterates the seed registry once
5
+ * and builds a lookup map: targetSlug → sources that point to it.
6
+ * Build this once at app factory time and cache it for the process lifetime.
7
+ */
8
+ import type { Seed } from './types.js';
9
+ export interface BackrefSource {
10
+ /** Slug of the seed that owns the relation branch */
11
+ sourceSlug: string;
12
+ /** `branch.alias` — the FK column name (single) or join-table name suffix (multi) */
13
+ branchAlias: string;
14
+ /** `branch.label` — human label for UI grouping */
15
+ branchLabel: string;
16
+ /** 'single' for direct FK, 'multi' for many-to-many join table */
17
+ relationship: 'single' | 'multi';
18
+ /** True when branch.onDelete === 'RESTRICT' — used to disable Delete button */
19
+ restricts: boolean;
20
+ }
21
+ /** Map: targetSlug → every source that points to it */
22
+ export type BackrefMap = Map<string, BackrefSource[]>;
23
+ /**
24
+ * Builds the back-reference map from an array of seeds.
25
+ * Pure function — no side-effects, safe to call at startup and cache forever.
26
+ */
27
+ export declare function buildBackrefMap(seeds: Seed[]): BackrefMap;
28
+ //# sourceMappingURL=relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../src/relations.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAA;IAClB,qFAAqF;IACrF,WAAW,EAAE,MAAM,CAAA;IACnB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAA;IAChC,+EAA+E;IAC/E,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAA;AAErD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,UAAU,CAoBzD"}
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * Builds the back-reference map from an array of seeds.
5
+ * Pure function — no side-effects, safe to call at startup and cache forever.
6
+ */
7
+ export function buildBackrefMap(seeds) {
8
+ const map = new Map();
9
+ for (const seed of seeds) {
10
+ for (const branch of seed.branches) {
11
+ if (branch.type !== 'relation' || !branch.targetSeed)
12
+ continue;
13
+ const existing = map.get(branch.targetSeed) ?? [];
14
+ existing.push({
15
+ sourceSlug: seed.slug,
16
+ branchAlias: branch.alias,
17
+ branchLabel: branch.label,
18
+ relationship: branch.multiple === true ? 'multi' : 'single',
19
+ restricts: branch.onDelete === 'RESTRICT',
20
+ });
21
+ map.set(branch.targetSeed, existing);
22
+ }
23
+ }
24
+ return map;
25
+ }
@@ -0,0 +1,11 @@
1
+ import type { JSONContent } from '@tiptap/core';
2
+ /**
3
+ * Accetta JSON TipTap (`{ type: 'doc', ... }`), envelope v1, o stringa HTML legacy.
4
+ */
5
+ export declare function normalizeRichtextForRender(value: unknown): JSONContent | string | null;
6
+ /**
7
+ * Render deterministico JSON → HTML (per display, anteprime, API pubblica).
8
+ * Per stringhe HTML legacy restituisce la stringa sanificata come pass-through (nessun parse TipTap).
9
+ */
10
+ export declare function renderRichText(value: unknown): string;
11
+ //# sourceMappingURL=richtext-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"richtext-render.d.ts","sourceRoot":"","sources":["../src/richtext-render.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAuD/C;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,IAAI,CAatF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQrD"}
@@ -0,0 +1,87 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ import { generateHTML } from '@tiptap/html';
4
+ import Highlight from '@tiptap/extension-highlight';
5
+ import Image from '@tiptap/extension-image';
6
+ import Link from '@tiptap/extension-link';
7
+ import Subscript from '@tiptap/extension-subscript';
8
+ import Superscript from '@tiptap/extension-superscript';
9
+ import { Table, TableCell, TableHeader, TableRow } from '@tiptap/extension-table';
10
+ import TextAlign from '@tiptap/extension-text-align';
11
+ import { Mathematics } from '@tiptap/extension-mathematics';
12
+ import StarterKit from '@tiptap/starter-kit';
13
+ import { isRichtextEnvelopeV1 } from './richtext.js';
14
+ /**
15
+ * Allinea l'output HTML allo schema TipTap usato dall'editor dashboard.
16
+ * Mantieni sincronizzato con `apps/dashboard/src/features/richtext-editor/extensions/build-editor-extensions.ts`.
17
+ */
18
+ function createRichTextHtmlExtensions() {
19
+ return [
20
+ StarterKit.configure({
21
+ link: false,
22
+ codeBlock: {
23
+ HTMLAttributes: {
24
+ class: 'richtext-code-block',
25
+ },
26
+ },
27
+ }),
28
+ Link.configure({
29
+ openOnClick: false,
30
+ autolink: true,
31
+ defaultProtocol: 'https',
32
+ }),
33
+ Mathematics.configure({
34
+ katexOptions: {
35
+ throwOnError: false,
36
+ },
37
+ }),
38
+ Highlight,
39
+ Superscript,
40
+ Subscript,
41
+ Image.configure({
42
+ allowBase64: false,
43
+ }),
44
+ TextAlign.configure({
45
+ types: ['heading', 'paragraph'],
46
+ }),
47
+ Table.configure({
48
+ resizable: false,
49
+ }),
50
+ TableRow,
51
+ TableHeader,
52
+ TableCell,
53
+ ];
54
+ }
55
+ /**
56
+ * Accetta JSON TipTap (`{ type: 'doc', ... }`), envelope v1, o stringa HTML legacy.
57
+ */
58
+ export function normalizeRichtextForRender(value) {
59
+ if (value == null || value === '')
60
+ return null;
61
+ if (typeof value === 'string')
62
+ return value;
63
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
64
+ const o = value;
65
+ if (isRichtextEnvelopeV1(value)) {
66
+ return o.doc;
67
+ }
68
+ if (o.type === 'doc') {
69
+ return value;
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ /**
75
+ * Render deterministico JSON → HTML (per display, anteprime, API pubblica).
76
+ * Per stringhe HTML legacy restituisce la stringa sanificata come pass-through (nessun parse TipTap).
77
+ */
78
+ export function renderRichText(value) {
79
+ const normalized = normalizeRichtextForRender(value);
80
+ if (normalized == null)
81
+ return '';
82
+ if (typeof normalized === 'string') {
83
+ return normalized;
84
+ }
85
+ const extensions = createRichTextHtmlExtensions();
86
+ return generateHTML(normalized, extensions);
87
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Convenzione storage richtext TipTap nel Content Engine.
3
+ * @see docs/Sprints/tiptap-elevation.md
4
+ */
5
+ export declare const RICHTEXT_SCHEMA_VERSION: 1;
6
+ export type RichtextEnvelopeV1 = {
7
+ schemaVersion: typeof RICHTEXT_SCHEMA_VERSION;
8
+ doc: Record<string, unknown>;
9
+ };
10
+ export declare function isRichtextEnvelopeV1(value: unknown): value is RichtextEnvelopeV1;
11
+ //# sourceMappingURL=richtext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"richtext.d.ts","sourceRoot":"","sources":["../src/richtext.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAG,CAAU,CAAA;AAEjD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,aAAa,EAAE,OAAO,uBAAuB,CAAA;IAC7C,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B,CAAA;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAIhF"}
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * Convenzione storage richtext TipTap nel Content Engine.
5
+ * @see docs/Sprints/tiptap-elevation.md
6
+ */
7
+ export const RICHTEXT_SCHEMA_VERSION = 1;
8
+ export function isRichtextEnvelopeV1(value) {
9
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
10
+ return false;
11
+ const o = value;
12
+ return o.schemaVersion === RICHTEXT_SCHEMA_VERSION && typeof o.doc === 'object' && o.doc !== null;
13
+ }
@@ -0,0 +1,4 @@
1
+ export interface IScheduler {
2
+ waitUntil(promise: Promise<unknown>): void;
3
+ }
4
+ //# sourceMappingURL=scheduler.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.interface.d.ts","sourceRoot":"","sources":["../src/scheduler.interface.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;CAC3C"}
@@ -0,0 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { IScheduler } from './scheduler.interface.js';
2
+ export declare class NoOpScheduler implements IScheduler {
3
+ waitUntil(_promise: Promise<unknown>): void;
4
+ }
5
+ //# sourceMappingURL=scheduler.stub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.stub.d.ts","sourceRoot":"","sources":["../src/scheduler.stub.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE1D,qBAAa,aAAc,YAAW,UAAU;IAC9C,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;CAG5C"}