@beechcms/core 0.7.0 → 0.8.1

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 (370) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/antivirus/antivirus.interface.d.ts +12 -0
  3. package/dist/antivirus/antivirus.interface.d.ts.map +1 -0
  4. package/dist/antivirus/antivirus.interface.js +3 -0
  5. package/dist/antivirus/noop-antivirus.provider.d.ts +6 -0
  6. package/dist/antivirus/noop-antivirus.provider.d.ts.map +1 -0
  7. package/dist/antivirus/noop-antivirus.provider.js +8 -0
  8. package/dist/antivirus/virustotal-antivirus.provider.d.ts +8 -0
  9. package/dist/antivirus/virustotal-antivirus.provider.d.ts.map +1 -0
  10. package/dist/antivirus/virustotal-antivirus.provider.js +48 -0
  11. package/dist/automations-grammar-words.d.ts +2 -0
  12. package/dist/automations-grammar-words.d.ts.map +1 -0
  13. package/dist/automations-grammar-words.js +8 -0
  14. package/dist/automations.repository.interface.d.ts +19 -0
  15. package/dist/automations.repository.interface.d.ts.map +1 -0
  16. package/dist/automations.repository.interface.js +3 -0
  17. package/dist/automations.runner.interface.d.ts +10 -0
  18. package/dist/automations.runner.interface.d.ts.map +1 -0
  19. package/dist/automations.runner.interface.js +3 -0
  20. package/dist/automations.runner.stub.d.ts +5 -0
  21. package/dist/automations.runner.stub.d.ts.map +1 -0
  22. package/dist/automations.runner.stub.js +7 -0
  23. package/dist/automations.types.d.ts +75 -0
  24. package/dist/automations.types.d.ts.map +1 -0
  25. package/dist/automations.types.js +3 -0
  26. package/dist/clock.d.ts +25 -0
  27. package/dist/clock.d.ts.map +1 -0
  28. package/dist/clock.js +11 -0
  29. package/dist/common/canonical-json.d.ts +30 -0
  30. package/dist/common/canonical-json.d.ts.map +1 -0
  31. package/dist/common/canonical-json.js +89 -0
  32. package/dist/common/hooks.d.ts +3 -0
  33. package/dist/common/hooks.d.ts.map +1 -1
  34. package/dist/content/content.repository.d.ts +2 -2
  35. package/dist/content/content.repository.d.ts.map +1 -1
  36. package/dist/content/deletion-ledger.d.ts +39 -0
  37. package/dist/content/deletion-ledger.d.ts.map +1 -0
  38. package/dist/content/deletion-ledger.js +3 -0
  39. package/dist/content/richtext/richtext-render.d.ts.map +1 -1
  40. package/dist/content/richtext/richtext-render.js +14 -1
  41. package/dist/content/seed.repository.d.ts +22 -0
  42. package/dist/content/seed.repository.d.ts.map +1 -1
  43. package/dist/content-scan.repository.d.ts +9 -0
  44. package/dist/content-scan.repository.d.ts.map +1 -0
  45. package/dist/content-scan.repository.js +3 -0
  46. package/dist/content.repository.d.ts +247 -0
  47. package/dist/content.repository.d.ts.map +1 -0
  48. package/dist/content.repository.js +59 -0
  49. package/dist/dashboard-layout/seed-layout.d.ts.map +1 -1
  50. package/dist/dashboard-layout/seed-layout.js +13 -6
  51. package/dist/dashboard-layout.d.ts +154 -0
  52. package/dist/dashboard-layout.d.ts.map +1 -0
  53. package/dist/dashboard-layout.js +186 -0
  54. package/dist/dashboard-layout.repository.d.ts +18 -0
  55. package/dist/dashboard-layout.repository.d.ts.map +1 -0
  56. package/dist/dashboard-layout.repository.js +3 -0
  57. package/dist/dashboard-permissions.d.ts +3 -0
  58. package/dist/dashboard-permissions.d.ts.map +1 -0
  59. package/dist/dashboard-permissions.js +11 -0
  60. package/dist/dashboard-scopes.d.ts +12 -0
  61. package/dist/dashboard-scopes.d.ts.map +1 -0
  62. package/dist/dashboard-scopes.js +30 -0
  63. package/dist/define-seed.d.ts +3 -0
  64. package/dist/define-seed.d.ts.map +1 -0
  65. package/dist/define-seed.js +5 -0
  66. package/dist/demo-data.repository.d.ts +5 -0
  67. package/dist/demo-data.repository.d.ts.map +1 -0
  68. package/dist/demo-data.repository.js +3 -0
  69. package/dist/email.provider.d.ts +32 -0
  70. package/dist/email.provider.d.ts.map +1 -0
  71. package/dist/email.provider.js +4 -0
  72. package/dist/engine/ddl/ddl.d.ts +216 -0
  73. package/dist/engine/ddl/ddl.d.ts.map +1 -0
  74. package/dist/engine/ddl/ddl.js +574 -0
  75. package/dist/engine/ddl/schema-mutator.d.ts +26 -0
  76. package/dist/engine/ddl/schema-mutator.d.ts.map +1 -0
  77. package/dist/engine/ddl/schema-mutator.js +3 -0
  78. package/dist/engine/ddl/seed-ddl-destructive.d.ts +40 -0
  79. package/dist/engine/ddl/seed-ddl-destructive.d.ts.map +1 -0
  80. package/dist/engine/ddl/seed-ddl-destructive.js +149 -0
  81. package/dist/engine/ddl/seed-ddl.d.ts +43 -0
  82. package/dist/engine/ddl/seed-ddl.d.ts.map +1 -0
  83. package/dist/engine/ddl/seed-ddl.js +115 -0
  84. package/dist/engine/ddl.d.ts +15 -0
  85. package/dist/engine/ddl.d.ts.map +1 -1
  86. package/dist/engine/ddl.js +30 -1
  87. package/dist/engine/introspection/introspection.d.ts +101 -0
  88. package/dist/engine/introspection/introspection.d.ts.map +1 -0
  89. package/dist/engine/introspection/introspection.js +127 -0
  90. package/dist/engine/introspection/schema-fingerprint.d.ts +73 -0
  91. package/dist/engine/introspection/schema-fingerprint.d.ts.map +1 -0
  92. package/dist/engine/introspection/schema-fingerprint.js +97 -0
  93. package/dist/engine/introspection.d.ts +101 -0
  94. package/dist/engine/introspection.d.ts.map +1 -0
  95. package/dist/engine/introspection.js +127 -0
  96. package/dist/engine/localization/localization.d.ts +127 -0
  97. package/dist/engine/localization/localization.d.ts.map +1 -0
  98. package/dist/engine/localization/localization.js +212 -0
  99. package/dist/engine/localization.d.ts +127 -0
  100. package/dist/engine/localization.d.ts.map +1 -0
  101. package/dist/engine/localization.js +212 -0
  102. package/dist/engine/policies.d.ts.map +1 -1
  103. package/dist/engine/policies.js +5 -0
  104. package/dist/engine/privacy/policies.d.ts +58 -0
  105. package/dist/engine/privacy/policies.d.ts.map +1 -0
  106. package/dist/engine/privacy/policies.js +185 -0
  107. package/dist/engine/privacy/privacy.service.d.ts +65 -0
  108. package/dist/engine/privacy/privacy.service.d.ts.map +1 -0
  109. package/dist/engine/privacy/privacy.service.js +114 -0
  110. package/dist/engine/privacy.service.d.ts.map +1 -1
  111. package/dist/engine/query/query.d.ts +23 -0
  112. package/dist/engine/query/query.d.ts.map +1 -0
  113. package/dist/engine/query/query.js +301 -0
  114. package/dist/engine/query/relations.d.ts +28 -0
  115. package/dist/engine/query/relations.d.ts.map +1 -0
  116. package/dist/engine/query/relations.js +25 -0
  117. package/dist/engine/query/serialize.d.ts +22 -0
  118. package/dist/engine/query/serialize.d.ts.map +1 -0
  119. package/dist/engine/query/serialize.js +175 -0
  120. package/dist/engine/schema-fingerprint.d.ts +73 -0
  121. package/dist/engine/schema-fingerprint.d.ts.map +1 -0
  122. package/dist/engine/schema-fingerprint.js +97 -0
  123. package/dist/engine/seed-registry.d.ts.map +1 -1
  124. package/dist/engine/seed-registry.js +23 -4
  125. package/dist/engine/seed-types-generator.d.ts.map +1 -1
  126. package/dist/engine/seed-types-generator.js +8 -5
  127. package/dist/engine/seed-validation.d.ts +7 -0
  128. package/dist/engine/seed-validation.d.ts.map +1 -1
  129. package/dist/engine/seed-validation.js +59 -1
  130. package/dist/engine/seeds/define-seed.d.ts +3 -0
  131. package/dist/engine/seeds/define-seed.d.ts.map +1 -0
  132. package/dist/engine/seeds/define-seed.js +5 -0
  133. package/dist/engine/seeds/seed-registry.d.ts +71 -0
  134. package/dist/engine/seeds/seed-registry.d.ts.map +1 -0
  135. package/dist/engine/seeds/seed-registry.js +167 -0
  136. package/dist/engine/seeds/seed-types-generator.d.ts +25 -0
  137. package/dist/engine/seeds/seed-types-generator.d.ts.map +1 -0
  138. package/dist/engine/seeds/seed-types-generator.js +117 -0
  139. package/dist/engine/seeds/seed-validation.d.ts +30 -0
  140. package/dist/engine/seeds/seed-validation.d.ts.map +1 -0
  141. package/dist/engine/seeds/seed-validation.js +364 -0
  142. package/dist/engine/seeds/seeds.d.ts +20 -0
  143. package/dist/engine/seeds/seeds.d.ts.map +1 -0
  144. package/dist/engine/seeds/seeds.js +21 -0
  145. package/dist/engine/types.d.ts +7 -0
  146. package/dist/engine/types.d.ts.map +1 -1
  147. package/dist/engine/validation/emptiness.d.ts +12 -0
  148. package/dist/engine/validation/emptiness.d.ts.map +1 -0
  149. package/dist/engine/validation/emptiness.js +33 -0
  150. package/dist/engine/validation/index.d.ts +1 -1
  151. package/dist/engine/validation/index.d.ts.map +1 -1
  152. package/dist/engine/validation/richtext-sanitizer.d.ts.map +1 -1
  153. package/dist/engine/validation/richtext-sanitizer.js +2 -1
  154. package/dist/engine.d.ts +144 -0
  155. package/dist/engine.d.ts.map +1 -0
  156. package/dist/engine.js +741 -0
  157. package/dist/file-types.d.ts +13 -0
  158. package/dist/file-types.d.ts.map +1 -0
  159. package/dist/file-types.js +85 -0
  160. package/dist/hooks.d.ts +29 -0
  161. package/dist/hooks.d.ts.map +1 -0
  162. package/dist/hooks.js +3 -0
  163. package/dist/id-generator.d.ts +26 -0
  164. package/dist/id-generator.d.ts.map +1 -0
  165. package/dist/id-generator.js +12 -0
  166. package/dist/idempotency.repository.d.ts +13 -0
  167. package/dist/idempotency.repository.d.ts.map +1 -0
  168. package/dist/idempotency.repository.js +3 -0
  169. package/dist/index.d.ts +16 -1
  170. package/dist/index.d.ts.map +1 -1
  171. package/dist/index.js +16 -1
  172. package/dist/kanban-position.repository.d.ts +19 -0
  173. package/dist/kanban-position.repository.d.ts.map +1 -0
  174. package/dist/kanban-position.repository.js +3 -0
  175. package/dist/kanban.d.ts +75 -0
  176. package/dist/kanban.d.ts.map +1 -0
  177. package/dist/kanban.js +82 -0
  178. package/dist/layout-permissions.d.ts +3 -0
  179. package/dist/layout-permissions.d.ts.map +1 -0
  180. package/dist/layout-permissions.js +11 -0
  181. package/dist/media/file-types.d.ts +103 -9
  182. package/dist/media/file-types.d.ts.map +1 -1
  183. package/dist/media/file-types.js +336 -52
  184. package/dist/media/image-transformer.d.ts +34 -0
  185. package/dist/media/image-transformer.d.ts.map +1 -0
  186. package/dist/media/image-transformer.js +3 -0
  187. package/dist/media/magic-bytes.d.ts +21 -0
  188. package/dist/media/magic-bytes.d.ts.map +1 -0
  189. package/dist/media/magic-bytes.js +66 -0
  190. package/dist/media/media-transform.d.ts +88 -0
  191. package/dist/media/media-transform.d.ts.map +1 -0
  192. package/dist/media/media-transform.js +193 -0
  193. package/dist/media.repository.d.ts +61 -0
  194. package/dist/media.repository.d.ts.map +1 -0
  195. package/dist/media.repository.js +3 -0
  196. package/dist/notifications/notification-service.d.ts +1 -1
  197. package/dist/oauth/authorization-code.repository.d.ts +33 -0
  198. package/dist/oauth/authorization-code.repository.d.ts.map +1 -0
  199. package/dist/oauth/authorization-code.repository.js +3 -0
  200. package/dist/oauth/client.repository.d.ts +17 -0
  201. package/dist/oauth/client.repository.d.ts.map +1 -0
  202. package/dist/oauth/client.repository.js +3 -0
  203. package/dist/oauth/consent.repository.d.ts +25 -0
  204. package/dist/oauth/consent.repository.d.ts.map +1 -0
  205. package/dist/oauth/consent.repository.js +3 -0
  206. package/dist/oauth/pkce.d.ts +21 -0
  207. package/dist/oauth/pkce.d.ts.map +1 -0
  208. package/dist/oauth/pkce.js +47 -0
  209. package/dist/oauth/role-guard.d.ts +32 -0
  210. package/dist/oauth/role-guard.d.ts.map +1 -0
  211. package/dist/oauth/role-guard.js +14 -0
  212. package/dist/oauth/scopes.d.ts +27 -0
  213. package/dist/oauth/scopes.d.ts.map +1 -0
  214. package/dist/oauth/scopes.js +41 -0
  215. package/dist/oauth/token.repository.d.ts +46 -0
  216. package/dist/oauth/token.repository.d.ts.map +1 -0
  217. package/dist/oauth/token.repository.js +3 -0
  218. package/dist/observability/activity-logger.d.ts +1 -1
  219. package/dist/observability/activity-logger.d.ts.map +1 -1
  220. package/dist/policies.d.ts +10 -0
  221. package/dist/policies.d.ts.map +1 -0
  222. package/dist/policies.js +33 -0
  223. package/dist/queue/queue.stub.d.ts.map +1 -1
  224. package/dist/queue/scheduler.stub.d.ts.map +1 -1
  225. package/dist/queue.interface.d.ts +39 -0
  226. package/dist/queue.interface.d.ts.map +1 -0
  227. package/dist/queue.interface.js +3 -0
  228. package/dist/queue.stub.d.ts +6 -0
  229. package/dist/queue.stub.d.ts.map +1 -0
  230. package/dist/queue.stub.js +8 -0
  231. package/dist/rate-limit/rate-limiter.d.ts +13 -5
  232. package/dist/rate-limit/rate-limiter.d.ts.map +1 -1
  233. package/dist/rate-limit/token-bucket-rate-limiter.d.ts +20 -0
  234. package/dist/rate-limit/token-bucket-rate-limiter.d.ts.map +1 -0
  235. package/dist/rate-limit/token-bucket-rate-limiter.js +63 -0
  236. package/dist/rbac/evaluate.d.ts +57 -0
  237. package/dist/rbac/evaluate.d.ts.map +1 -0
  238. package/dist/rbac/evaluate.js +113 -0
  239. package/dist/rbac/invitation.repository.d.ts +66 -0
  240. package/dist/rbac/invitation.repository.d.ts.map +1 -0
  241. package/dist/rbac/invitation.repository.js +3 -0
  242. package/dist/rbac/permissions.d.ts +39 -0
  243. package/dist/rbac/permissions.d.ts.map +1 -0
  244. package/dist/rbac/permissions.js +43 -0
  245. package/dist/rbac/types.d.ts +118 -0
  246. package/dist/rbac/types.d.ts.map +1 -0
  247. package/dist/rbac/types.js +3 -0
  248. package/dist/relations.d.ts +28 -0
  249. package/dist/relations.d.ts.map +1 -0
  250. package/dist/relations.js +25 -0
  251. package/dist/richtext-render.d.ts +11 -0
  252. package/dist/richtext-render.d.ts.map +1 -0
  253. package/dist/richtext-render.js +87 -0
  254. package/dist/richtext.d.ts +11 -0
  255. package/dist/richtext.d.ts.map +1 -0
  256. package/dist/richtext.js +13 -0
  257. package/dist/scheduler.interface.d.ts +4 -0
  258. package/dist/scheduler.interface.d.ts.map +1 -0
  259. package/dist/scheduler.interface.js +3 -0
  260. package/dist/scheduler.stub.d.ts +5 -0
  261. package/dist/scheduler.stub.d.ts.map +1 -0
  262. package/dist/scheduler.stub.js +7 -0
  263. package/dist/schema/canonical.d.ts +15 -0
  264. package/dist/schema/canonical.d.ts.map +1 -0
  265. package/dist/schema/canonical.js +37 -0
  266. package/dist/schema/define.d.ts +42 -0
  267. package/dist/schema/define.d.ts.map +1 -0
  268. package/dist/schema/define.js +56 -0
  269. package/dist/schema/emit.d.ts +14 -0
  270. package/dist/schema/emit.d.ts.map +1 -0
  271. package/dist/schema/emit.js +43 -0
  272. package/dist/schema/index.d.ts +12 -0
  273. package/dist/schema/index.d.ts.map +1 -0
  274. package/dist/schema/index.js +13 -0
  275. package/dist/schema/manifest-seeds.d.ts +12 -0
  276. package/dist/schema/manifest-seeds.d.ts.map +1 -0
  277. package/dist/schema/manifest-seeds.js +48 -0
  278. package/dist/schema/manifest-validation.d.ts +13 -0
  279. package/dist/schema/manifest-validation.d.ts.map +1 -0
  280. package/dist/schema/manifest-validation.js +41 -0
  281. package/dist/schema/manifest.types.d.ts +54 -0
  282. package/dist/schema/manifest.types.d.ts.map +1 -0
  283. package/dist/schema/manifest.types.js +7 -0
  284. package/dist/schema-mutator.d.ts +26 -0
  285. package/dist/schema-mutator.d.ts.map +1 -0
  286. package/dist/schema-mutator.js +3 -0
  287. package/dist/search/vector-extractor.d.ts +11 -0
  288. package/dist/search/vector-extractor.d.ts.map +1 -0
  289. package/dist/search/vector-extractor.js +25 -0
  290. package/dist/search/vector.repository.d.ts +13 -0
  291. package/dist/search/vector.repository.d.ts.map +1 -0
  292. package/dist/search/vector.repository.js +3 -0
  293. package/dist/security/time-trap-token.repository.d.ts +9 -0
  294. package/dist/security/time-trap-token.repository.d.ts.map +1 -0
  295. package/dist/security/time-trap-token.repository.js +3 -0
  296. package/dist/security/time-trap.d.ts +7 -0
  297. package/dist/security/time-trap.d.ts.map +1 -0
  298. package/dist/security/time-trap.js +49 -0
  299. package/dist/seed-ddl-destructive.d.ts +40 -0
  300. package/dist/seed-ddl-destructive.d.ts.map +1 -0
  301. package/dist/seed-ddl-destructive.js +149 -0
  302. package/dist/seed-ddl.d.ts +40 -0
  303. package/dist/seed-ddl.d.ts.map +1 -0
  304. package/dist/seed-ddl.js +100 -0
  305. package/dist/seed-layout.d.ts +145 -0
  306. package/dist/seed-layout.d.ts.map +1 -0
  307. package/dist/seed-layout.js +192 -0
  308. package/dist/seed-layout.repository.d.ts +22 -0
  309. package/dist/seed-layout.repository.d.ts.map +1 -0
  310. package/dist/seed-layout.repository.js +3 -0
  311. package/dist/seed-registry.d.ts +71 -0
  312. package/dist/seed-registry.d.ts.map +1 -0
  313. package/dist/seed-registry.js +143 -0
  314. package/dist/seed-types-generator.d.ts +1 -1
  315. package/dist/seed-types-generator.d.ts.map +1 -1
  316. package/dist/seed-validation.d.ts +23 -0
  317. package/dist/seed-validation.d.ts.map +1 -0
  318. package/dist/seed-validation.js +224 -0
  319. package/dist/seed.repository.d.ts +37 -0
  320. package/dist/seed.repository.d.ts.map +1 -0
  321. package/dist/seed.repository.js +3 -0
  322. package/dist/seeds.d.ts +20 -0
  323. package/dist/seeds.d.ts.map +1 -0
  324. package/dist/seeds.js +21 -0
  325. package/dist/site-settings.repository.d.ts +16 -0
  326. package/dist/site-settings.repository.d.ts.map +1 -0
  327. package/dist/site-settings.repository.js +3 -0
  328. package/dist/slug-utils.d.ts +18 -0
  329. package/dist/slug-utils.d.ts.map +1 -0
  330. package/dist/slug-utils.js +32 -0
  331. package/dist/storage.d.ts +46 -0
  332. package/dist/storage.d.ts.map +1 -0
  333. package/dist/storage.js +3 -0
  334. package/dist/transfer/csv.d.ts +34 -0
  335. package/dist/transfer/csv.d.ts.map +1 -0
  336. package/dist/transfer/csv.js +135 -0
  337. package/dist/transfer/flat-seed.d.ts +13 -0
  338. package/dist/transfer/flat-seed.d.ts.map +1 -0
  339. package/dist/transfer/flat-seed.js +45 -0
  340. package/dist/transfer/index.d.ts +7 -0
  341. package/dist/transfer/index.d.ts.map +1 -0
  342. package/dist/transfer/index.js +8 -0
  343. package/dist/transfer/ndjson.d.ts +25 -0
  344. package/dist/transfer/ndjson.d.ts.map +1 -0
  345. package/dist/transfer/ndjson.js +62 -0
  346. package/dist/transfer/row-mapping.d.ts +36 -0
  347. package/dist/transfer/row-mapping.d.ts.map +1 -0
  348. package/dist/transfer/row-mapping.js +90 -0
  349. package/dist/transfer/transfer.constants.d.ts +20 -0
  350. package/dist/transfer/transfer.constants.d.ts.map +1 -0
  351. package/dist/transfer/transfer.constants.js +21 -0
  352. package/dist/transfer/transfer.types.d.ts +46 -0
  353. package/dist/transfer/transfer.types.d.ts.map +1 -0
  354. package/dist/transfer/transfer.types.js +6 -0
  355. package/dist/types.d.ts +243 -0
  356. package/dist/types.d.ts.map +1 -0
  357. package/dist/types.js +3 -0
  358. package/dist/validation.d.ts +50 -0
  359. package/dist/validation.d.ts.map +1 -0
  360. package/dist/validation.js +660 -0
  361. package/dist/webhook-crypto.d.ts +2 -0
  362. package/dist/webhook-crypto.d.ts.map +1 -1
  363. package/dist/webhook-crypto.js +2 -2
  364. package/dist/webhook-validation.d.ts +3 -0
  365. package/dist/webhook-validation.d.ts.map +1 -0
  366. package/dist/webhook-validation.js +6 -0
  367. package/dist/webhooks/webhook-crypto.d.ts +2 -0
  368. package/dist/webhooks/webhook-crypto.d.ts.map +1 -1
  369. package/dist/webhooks/webhook-crypto.js +2 -2
  370. package/package.json +23 -15
@@ -0,0 +1,66 @@
1
+ import type { Scope } from './permissions.js';
2
+ /** One invitation row. `tokenHash` is deliberately absent: nothing above the storage
3
+ * boundary ever needs it, and an administration listing must not carry credential
4
+ * material (same rule as AccountSummary omitting passwordHash). */
5
+ export interface InvitationRecord {
6
+ id: string;
7
+ email: string;
8
+ roleId: string;
9
+ scope: Scope;
10
+ invitedBy: string;
11
+ expiresAt: number;
12
+ createdAt: number;
13
+ /** Non-null once redeemed. Single-use is enforced by {@link IInvitationRepository.markUsed}. */
14
+ usedAt: number | null;
15
+ }
16
+ export interface NewInvitationInput {
17
+ email: string;
18
+ tokenHash: string;
19
+ roleId: string;
20
+ scope: Scope;
21
+ invitedBy: string;
22
+ expiresAt: number;
23
+ }
24
+ /** A live invitation resolved from a bearer token, with the pre-assignment it carries. */
25
+ export interface ValidatedInvitation {
26
+ id: string;
27
+ email: string;
28
+ roleId: string;
29
+ scope: Scope;
30
+ invitedBy: string;
31
+ }
32
+ /**
33
+ * Storage contract for onboarding invitations.
34
+ *
35
+ * Deliberately shaped after {@link IPasswordResetTokenRepository}: a single-use,
36
+ * expiring, hash-only bearer credential is the same lifecycle, and the codebase keeps
37
+ * exactly one shape for it.
38
+ */
39
+ export interface IInvitationRepository {
40
+ /** Consumes every pending invitation for an email before a new one is issued, so at
41
+ * most one live token per address exists at any time. */
42
+ invalidatePending(email: string, nowTimestamp: number): Promise<void>;
43
+ /** Stores a new invitation. Only the hash is persisted, never the plaintext.
44
+ * Returns the new invitation id. */
45
+ create(input: NewInvitationInput): Promise<string>;
46
+ /** Resolves a live (unused, unexpired) invitation by token hash. Null otherwise —
47
+ * expired, already used and unknown are deliberately indistinguishable. */
48
+ findValidByHash(tokenHash: string, nowTimestamp: number): Promise<ValidatedInvitation | null>;
49
+ /**
50
+ * Consumes an invitation. Returns TRUE only when THIS call performed the transition
51
+ * (`used_at IS NULL` at write time), which is what makes redemption single-use under
52
+ * concurrency. A second concurrent redeem gets false and must be refused.
53
+ */
54
+ markUsed(invitationId: string, nowTimestamp: number): Promise<boolean>;
55
+ /** One invitation by id, regardless of state. Null when absent. */
56
+ findById(invitationId: string): Promise<InvitationRecord | null>;
57
+ /** Every invitation, newest first. Administration tables are small by nature. */
58
+ listAll(): Promise<InvitationRecord[]>;
59
+ /** Replaces the token and expiry of an existing PENDING-or-EXPIRED invitation,
60
+ * preserving its (role, scope, email) pre-assignment. Returns false when the row is
61
+ * absent or already used — a consumed invitation is never re-armed. */
62
+ regenerate(invitationId: string, tokenHash: string, expiresAt: number): Promise<boolean>;
63
+ /** Revokes (hard-deletes) an invitation. Returns false when it did not exist. */
64
+ delete(invitationId: string): Promise<boolean>;
65
+ }
66
+ //# 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,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,gGAAgG;IAChG,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;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;8DAC0D;IAC1D,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAErE;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;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAEtE,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAEhE,iFAAiF;IACjF,OAAO,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAEtC;;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,118 @@
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
+ /** Storage contract for roles and their permission bundles. */
45
+ export interface IRoleRepository {
46
+ /** Retrieves a role with its permissions, or null when it does not exist. */
47
+ findById(roleId: string): Promise<RoleRecord | null>;
48
+ /** Retrieves several roles in one round trip. Missing ids are simply absent. */
49
+ findByIds(roleIds: readonly string[]): Promise<RoleRecord[]>;
50
+ /** Lists every role, system roles included, ordered by name. */
51
+ listAll(): Promise<RoleRecord[]>;
52
+ /** Creates a role and its permission rows atomically. Returns the new role id. */
53
+ create(input: NewRoleInput): Promise<string>;
54
+ /**
55
+ * Replaces a role's name, description and full permission set atomically.
56
+ *
57
+ * Returns false — changing NOTHING, permissions included — when the role does not
58
+ * exist or is a system role. System roles are seeded by migration and are immutable
59
+ * in both halves of the write, which is the guarantee callers rely on to keep
60
+ * `SuperAdmin` intact.
61
+ */
62
+ update(roleId: string, input: NewRoleInput): Promise<boolean>;
63
+ /**
64
+ * Deletes a non-system role and, by cascade, its permissions and assignments.
65
+ * Returns false when the role does not exist or is a system role.
66
+ */
67
+ delete(roleId: string): Promise<boolean>;
68
+ }
69
+ /** Storage contract for (user, role, scope) assignments. */
70
+ export interface IRoleAssignmentRepository {
71
+ /**
72
+ * Lists a user's assignments that currently grant anything.
73
+ *
74
+ * An assignment is skipped when its scope names a seed that is absent or
75
+ * `status != 'active'`, so scopes decay with their seed and revive with it.
76
+ * {@link GLOBAL_SCOPE} assignments are always returned.
77
+ */
78
+ listActiveForUser(userId: string): Promise<PermissionAssignment[]>;
79
+ /** Lists every assignment referencing a role, decay filter NOT applied. */
80
+ listByRole(roleId: string): Promise<PermissionAssignment[]>;
81
+ /** Creates an assignment. Returns its id; an existing identical triple is a no-op. */
82
+ create(input: NewAssignmentInput): Promise<string>;
83
+ /** Removes one assignment. Returns false when it did not exist. */
84
+ delete(assignmentId: string): Promise<boolean>;
85
+ /**
86
+ * Counts accounts holding `manage_users` at {@link GLOBAL_SCOPE} and still active.
87
+ * Backs the last-SuperAdmin guardrail consumed by a later sprint.
88
+ */
89
+ countActiveGlobalAdmins(): Promise<number>;
90
+ /** One assignment by id, decay filter NOT applied. Null when absent. */
91
+ findById(assignmentId: string): Promise<PermissionAssignment | null>;
92
+ /**
93
+ * Every assignment in the system, decay filter NOT applied.
94
+ *
95
+ * Exists so the account-list endpoint can resolve each account's scopes in ONE round
96
+ * trip instead of one query per account. Administration tables are small by nature;
97
+ * content never flows through here.
98
+ */
99
+ listAll(): Promise<PermissionAssignment[]>;
100
+ /**
101
+ * Every assignment of one user, decay filter NOT applied — administration screens must
102
+ * see (and be able to remove) a row whose seed is currently deleted, which
103
+ * {@link listActiveForUser} deliberately hides.
104
+ */
105
+ listAllForUser(userId: string): Promise<PermissionAssignment[]>;
106
+ /**
107
+ * {@link countActiveGlobalAdmins} ignoring one user. `0` means that user is the last
108
+ * account able to administer the platform, and any operation revoking their authority
109
+ * must be refused.
110
+ */
111
+ countActiveGlobalAdminsExcludingUser(userId: string): Promise<number>;
112
+ /**
113
+ * {@link countActiveGlobalAdmins} ignoring every assignment that goes through one role.
114
+ * `0` means mutating that role would strip the platform of its last administrator.
115
+ */
116
+ countActiveGlobalAdminsExcludingRole(roleId: string): Promise<number>;
117
+ }
118
+ //# 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,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export {};
@@ -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"}
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export class NoOpScheduler {
4
+ waitUntil(_promise) {
5
+ // intentionally empty
6
+ }
7
+ }
@@ -0,0 +1,15 @@
1
+ import type { BeechSchemaManifest } from './manifest.types.js';
2
+ /**
3
+ * Thrown when a manifest carries a value that cannot survive a JSON round-trip.
4
+ * Re-exported under its historical name: it is the SAME class object as
5
+ * `CanonicalSerializationError`, so existing `instanceof` checks keep working.
6
+ */
7
+ export { CanonicalSerializationError as ManifestSerializationError } from '../common/canonical-json.js';
8
+ /**
9
+ * Serializes a manifest to its canonical form: seeds sorted by slug, keys sorted, two-space
10
+ * indentation, trailing newline. Stable across authoring order and across key insertion order.
11
+ */
12
+ export declare function toCanonicalJson(manifest: BeechSchemaManifest): string;
13
+ /** Parses canonical JSON back into a manifest, refusing an unknown format version. */
14
+ export declare function fromCanonicalJson(json: string): BeechSchemaManifest;
15
+ //# sourceMappingURL=canonical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/schema/canonical.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D;;;;GAIG;AACH,OAAO,EAAE,2BAA2B,IAAI,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AAEvG;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAGrE;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CASnE"}
@@ -0,0 +1,37 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * @module schema/canonical
5
+ * Deterministic serialization of a manifest. The bytes produced here are the input the schema
6
+ * fingerprint hashes, so this format is a compatibility surface: changing it invalidates every
7
+ * already-published client. Treat it as frozen.
8
+ *
9
+ * The serializer itself moved to `common/canonical-json.ts` in sprint 2 so the Worker-side
10
+ * fingerprint can share it without importing this authoring-only module.
11
+ */
12
+ import { canonicalStringify } from '../common/canonical-json.js';
13
+ import { MANIFEST_VERSION } from './manifest.types.js';
14
+ /**
15
+ * Thrown when a manifest carries a value that cannot survive a JSON round-trip.
16
+ * Re-exported under its historical name: it is the SAME class object as
17
+ * `CanonicalSerializationError`, so existing `instanceof` checks keep working.
18
+ */
19
+ export { CanonicalSerializationError as ManifestSerializationError } from '../common/canonical-json.js';
20
+ /**
21
+ * Serializes a manifest to its canonical form: seeds sorted by slug, keys sorted, two-space
22
+ * indentation, trailing newline. Stable across authoring order and across key insertion order.
23
+ */
24
+ export function toCanonicalJson(manifest) {
25
+ const seeds = [...manifest.seeds].sort((a, b) => a.slug.localeCompare(b.slug));
26
+ return canonicalStringify({ version: manifest.version, seeds });
27
+ }
28
+ /** Parses canonical JSON back into a manifest, refusing an unknown format version. */
29
+ export function fromCanonicalJson(json) {
30
+ const parsed = JSON.parse(json);
31
+ if (parsed.version !== MANIFEST_VERSION) {
32
+ throw new Error(`Unsupported manifest version ${String(parsed.version)}; this build understands ${MANIFEST_VERSION}.`);
33
+ }
34
+ if (!Array.isArray(parsed.seeds))
35
+ throw new Error('Manifest is missing a `seeds` array.');
36
+ return { version: MANIFEST_VERSION, seeds: parsed.seeds };
37
+ }
@@ -0,0 +1,42 @@
1
+ import type { BeechSchemaManifest, FieldGroup, ManifestBranch, ManifestSeed } from './manifest.types.js';
2
+ /** A field bundle, or the fields themselves, as accepted by `defineSeed`. */
3
+ type BranchInput = ManifestBranch | FieldGroup;
4
+ /**
5
+ * Declares the root manifest. Seeds are stored in authoring order here; canonical ordering is
6
+ * applied by `toCanonicalJson`, so a reordered manifest file produces byte-identical canonical JSON.
7
+ */
8
+ export declare function defineSchema(input: {
9
+ seeds: ManifestSeed[];
10
+ }): BeechSchemaManifest;
11
+ /**
12
+ * Declares one content type, flattening any `defineGroup()` bundles into the branch list.
13
+ * Branch ORDER is preserved: it is the physical column order `planCreateSeed` will emit.
14
+ */
15
+ export declare function defineSeed(input: Omit<ManifestSeed, 'branches'> & {
16
+ branches: BranchInput[];
17
+ }): ManifestSeed;
18
+ /** Declares a reusable field bundle. Expanded at author time by `defineSeed`; never persisted. */
19
+ export declare function defineGroup(name: string, branches: ManifestBranch[]): FieldGroup;
20
+ /**
21
+ * Typed field constructors. `relation` and `repeater` narrow their input because the engine treats
22
+ * `targetSeed` / `fields` as required for those types — making the compiler enforce what
23
+ * `validateSeedDefinitions` would otherwise only catch at apply time.
24
+ */
25
+ export declare const defineField: {
26
+ readonly text: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
27
+ readonly number: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
28
+ readonly boolean: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
29
+ readonly json: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
30
+ readonly date: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
31
+ readonly richtext: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
32
+ readonly file: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
33
+ readonly tags: (input: Omit<ManifestBranch, "type">) => ManifestBranch;
34
+ readonly relation: (input: Omit<ManifestBranch, "type" | "targetSeed"> & {
35
+ targetSeed: string;
36
+ }) => ManifestBranch;
37
+ readonly repeater: (input: Omit<ManifestBranch, "type" | "fields"> & {
38
+ fields: ManifestBranch[];
39
+ }) => ManifestBranch;
40
+ };
41
+ export {};
42
+ //# sourceMappingURL=define.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/schema/define.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,YAAY,EACb,MAAM,qBAAqB,CAAA;AAE5B,6EAA6E;AAC7E,KAAK,WAAW,GAAG,cAAc,GAAG,UAAU,CAAA;AAM9C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,YAAY,EAAE,CAAA;CAAE,GAAG,mBAAmB,CAElF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAA;CAAE,GAClE,YAAY,CAOd;AAED,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,UAAU,CAEhF;AAMD;;;;GAIG;AACH,eAAO,MAAM,WAAW;2BARP,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;6BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;8BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;2BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;2BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;+BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;2BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;2BAA7C,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,KAAG,cAAc;+BAkBnD,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY,CAAC,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,KAC1E,cAAc;+BAER,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG;QAAE,MAAM,EAAE,cAAc,EAAE,CAAA;KAAE,KAC5E,cAAc;CACT,CAAA"}