@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,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,22 @@
1
+ import type { Branch } from '../types.js';
2
+ /**
3
+ * Serializes a value for writing to the DB.
4
+ * boolean → 0/1 | date → Unix timestamp | json/tags/richtext/repeater → JSON string
5
+ * Localized branches: locale dictionary ↔ compact JSON.
6
+ *
7
+ * @param branch The branch definition.
8
+ * @param value The value to serialize.
9
+ * @returns The serialized DB value (string, number, or null).
10
+ */
11
+ export declare function serializeForDb(branch: Branch, value: unknown): string | number | null;
12
+ /**
13
+ * Deserializes a value read from the DB to its API/JS representation.
14
+ * 0/1 → boolean | Unix timestamp → ISO 8601 | JSON string → object/array
15
+ * Localized branches: locale dictionary ↔ compact JSON.
16
+ *
17
+ * @param branch The branch definition.
18
+ * @param value The raw database value.
19
+ * @returns The deserialized value.
20
+ */
21
+ export declare function deserializeFromDb(branch: Branch, value: unknown): unknown;
22
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/engine/query/serialize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,MAAM,EAOP,MAAM,aAAa,CAAC;AAoErB;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CA6CrF;AAGD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CA0CzE"}
@@ -0,0 +1,175 @@
1
+ import { compactLocalizedDictionary, isLocaleDictionary, isLocalizedBranch } from '../localization/localization.js';
2
+ /**
3
+ * Checks if a branch represents a multiple asset list field.
4
+ *
5
+ * @param branch The branch definition.
6
+ * @returns True if it's an asset list, false otherwise.
7
+ */
8
+ function isAssetListBranch(branch) {
9
+ return branch.type === 'file' && (branch.multiple === true || branch.format === 'asset-list');
10
+ }
11
+ /**
12
+ * Normalizes an unknown value to a valid HTTP URL string, or null.
13
+ *
14
+ * @param value The value to normalize.
15
+ * @returns The normalized URL string, or null if invalid.
16
+ */
17
+ function normalizeHttpUrl(value) {
18
+ if (typeof value !== 'string')
19
+ return null;
20
+ const cleaned = value.trim();
21
+ if (!cleaned)
22
+ return null;
23
+ try {
24
+ const parsed = new URL(cleaned);
25
+ return parsed.protocol.startsWith('http') ? cleaned : null;
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ /**
32
+ * Safely parses a JSON string, falling back to the raw string on error.
33
+ *
34
+ * @param value The string to parse.
35
+ * @returns The parsed object, or the original string.
36
+ */
37
+ function parseJsonSafe(value) {
38
+ try {
39
+ return JSON.parse(value);
40
+ }
41
+ catch {
42
+ return value;
43
+ }
44
+ }
45
+ /**
46
+ * Normalizes raw asset list values to a flat list of valid URL strings.
47
+ *
48
+ * @param rawValue The raw value (string, array, or object) to normalize.
49
+ * @returns An array of unique normalized URL strings.
50
+ */
51
+ function normalizeAssetListValue(rawValue) {
52
+ const input = typeof rawValue === 'string' ? parseJsonSafe(rawValue) : rawValue;
53
+ const values = Array.isArray(input) ? input : [input];
54
+ const normalized = [];
55
+ for (const item of values) {
56
+ if (item == null)
57
+ continue;
58
+ const direct = normalizeHttpUrl(item);
59
+ if (direct) {
60
+ normalized.push(direct);
61
+ continue;
62
+ }
63
+ if (typeof item === 'object' && !Array.isArray(item)) {
64
+ const fromObj = normalizeHttpUrl(item.url);
65
+ if (fromObj)
66
+ normalized.push(fromObj);
67
+ }
68
+ }
69
+ return [...new Set(normalized)];
70
+ }
71
+ /**
72
+ * Serializes a value for writing to the DB.
73
+ * boolean → 0/1 | date → Unix timestamp | json/tags/richtext/repeater → JSON string
74
+ * Localized branches: locale dictionary ↔ compact JSON.
75
+ *
76
+ * @param branch The branch definition.
77
+ * @param value The value to serialize.
78
+ * @returns The serialized DB value (string, number, or null).
79
+ */
80
+ export function serializeForDb(branch, value) {
81
+ if (value === null || value === undefined)
82
+ return null;
83
+ // Must precede the type switch: its `text` case returns null for any object, which would silently
84
+ // erase a dictionary on a localized text branch.
85
+ if (isLocalizedBranch(branch) && isLocaleDictionary(value)) {
86
+ const compact = compactLocalizedDictionary(value);
87
+ return compact === null ? null : JSON.stringify(compact);
88
+ }
89
+ switch (branch.type) {
90
+ case 'boolean':
91
+ return value ? 1 : 0;
92
+ case 'json':
93
+ case 'tags':
94
+ case 'richtext':
95
+ return typeof value === 'string' ? value : JSON.stringify(value);
96
+ case 'date': {
97
+ if (typeof value === 'number')
98
+ return value;
99
+ if (typeof value === 'string') {
100
+ const d = new Date(value);
101
+ if (Number.isNaN(d.getTime()))
102
+ return null;
103
+ if (branch.format === 'date') {
104
+ const midnight = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
105
+ return Math.floor(midnight / 1000);
106
+ }
107
+ return Math.floor(d.getTime() / 1000);
108
+ }
109
+ return null;
110
+ }
111
+ case 'file':
112
+ if (isAssetListBranch(branch)) {
113
+ return Array.isArray(value) ? JSON.stringify(value) : typeof value === 'string' ? value : null;
114
+ }
115
+ return typeof value === 'string' ? value : null;
116
+ case 'repeater':
117
+ return JSON.stringify(Array.isArray(value) ? value : []);
118
+ default:
119
+ return typeof value === 'string' ? value : typeof value === 'number' ? value : null;
120
+ }
121
+ }
122
+ /**
123
+ * Deserializes a value read from the DB to its API/JS representation.
124
+ * 0/1 → boolean | Unix timestamp → ISO 8601 | JSON string → object/array
125
+ * Localized branches: locale dictionary ↔ compact JSON.
126
+ *
127
+ * @param branch The branch definition.
128
+ * @param value The raw database value.
129
+ * @returns The deserialized value.
130
+ */
131
+ export function deserializeFromDb(branch, value) {
132
+ if (branch.type === 'repeater') {
133
+ if (typeof value !== 'string' || value.length === 0)
134
+ return [];
135
+ const parsed = parseJsonSafe(value);
136
+ return Array.isArray(parsed) ? parsed : [];
137
+ }
138
+ if (value === null || value === undefined)
139
+ return null;
140
+ // richtext/json already JSON.parse below; text must opt in. A legacy plain string written before the
141
+ // branch became localized is returned unchanged — the read-side fallback chain handles it.
142
+ if (branch.type === 'text' && isLocalizedBranch(branch) && typeof value === 'string' && value.startsWith('{')) {
143
+ const parsed = parseJsonSafe(value);
144
+ return isLocaleDictionary(parsed) ? parsed : value;
145
+ }
146
+ switch (branch.type) {
147
+ case 'boolean':
148
+ return value === 1 || value === true;
149
+ case 'json':
150
+ case 'tags':
151
+ case 'richtext': {
152
+ if (typeof value === 'string') {
153
+ try {
154
+ return JSON.parse(value);
155
+ }
156
+ catch {
157
+ return value;
158
+ }
159
+ }
160
+ return value;
161
+ }
162
+ case 'date': {
163
+ if (typeof value !== 'number')
164
+ return null;
165
+ const d = new Date(value * 1000);
166
+ return branch.format === 'date' ? d.toISOString().slice(0, 10) : d.toISOString();
167
+ }
168
+ case 'file':
169
+ if (isAssetListBranch(branch))
170
+ return normalizeAssetListValue(value);
171
+ return typeof value === 'string' ? value : null;
172
+ default:
173
+ return value;
174
+ }
175
+ }
@@ -0,0 +1,73 @@
1
+ import type { Branch, Seed } from './types.js';
2
+ /**
3
+ * Bumped ONLY when the projection below or the canonical byte format changes — i.e. when
4
+ * fingerprints computed by two builds are no longer comparable. It is carried in the fingerprint
5
+ * string itself so a version skew reads as a mismatch instead of as an accidental match.
6
+ */
7
+ export declare const SCHEMA_FINGERPRINT_VERSION = 1;
8
+ /** The response-shape-bearing subset of a `Branch`. */
9
+ export interface ContractBranch {
10
+ alias: string;
11
+ type: Branch['type'];
12
+ format?: Branch['format'];
13
+ multiple?: boolean;
14
+ options?: string[];
15
+ requiredOnCreate: boolean;
16
+ requiredOnUpdate: boolean;
17
+ targetSeed?: string;
18
+ /** From `resolvePolicies`, so an explicitly-written default hashes like an omitted one. */
19
+ visibility: 'full' | 'masked' | 'hidden';
20
+ publicRead: boolean;
21
+ publicEdit: boolean;
22
+ minItems?: number;
23
+ maxItems?: number;
24
+ /** Present only when true: the dictionary shape is part of the public contract (`?lang=all`, writes). */
25
+ localized?: boolean;
26
+ /** Repeater sub-fields, same projection, recursively. */
27
+ fields?: ContractBranch[];
28
+ }
29
+ /** The response-shape-bearing subset of a `Seed`. */
30
+ export interface ContractSeed {
31
+ slug: string;
32
+ displayNameAlias: string;
33
+ allowDrafts: boolean;
34
+ allowPublicRead: boolean;
35
+ allowPublicPost: boolean;
36
+ allowPublicEdit: boolean;
37
+ branches: ContractBranch[];
38
+ }
39
+ /** The exact value that gets canonicalized and hashed. */
40
+ export interface SchemaContract {
41
+ fingerprintVersion: number;
42
+ seeds: ContractSeed[];
43
+ }
44
+ /**
45
+ * Reduces seeds to what a response shape depends on.
46
+ *
47
+ * Deliberately EXCLUDED, and each for a reason a future reader must not "fix":
48
+ * - `id` (`br_XX`) — a stable internal handle; it never appears in a payload, and minting order
49
+ * differs between an environment built by migration and one grown through the dashboard.
50
+ * - `label`, `labelPlural`, `hint`, `dashboard`, `layout` — presentation, never response shape.
51
+ * - `retentionDays`, `onDelete`, `policies.search|filter|sort`, `numberOptions`, `fileOptions`,
52
+ * `policies.classification|privacy` — behaviour and storage concerns that leave the response
53
+ * shape identical. (`privacy` DOES change a stored value's encoding, but the API type stays
54
+ * `string`; drift there is a data concern, not a type concern.)
55
+ * - anything physical (column order, index names) — see the VETO Audit.
56
+ *
57
+ * Seeds are sorted by slug; BRANCH ORDER IS PRESERVED, because it is the declared field order the
58
+ * generated types and the dashboard form both follow.
59
+ */
60
+ export declare function projectSchemaContract(seeds: Seed[]): SchemaContract;
61
+ /**
62
+ * `v{VERSION}:{32 lowercase hex}` — SHA-256 over the canonical JSON of the contract projection,
63
+ * truncated to 128 bits.
64
+ *
65
+ * Truncation is deliberate: this value travels on EVERY public response as `X-Schema-Revision`,
66
+ * and 128 bits of a SHA-256 digest carries no realistic collision risk for a value space of a few
67
+ * hundred schema revisions. It is a revision marker, never a security token.
68
+ *
69
+ * Web Crypto only — the same API the Worker and Node ≥ 18 both expose, as `webhook-crypto.ts`
70
+ * already relies on. `@beechcms/core` gains no dependency.
71
+ */
72
+ export declare function computeSchemaFingerprint(seeds: Seed[]): Promise<string>;
73
+ //# sourceMappingURL=schema-fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-fingerprint.d.ts","sourceRoot":"","sources":["../../src/engine/schema-fingerprint.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,gBAAgB,EAAE,OAAO,CAAA;IACzB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2FAA2F;IAC3F,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACxC,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yGAAyG;IACzG,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yDAAyD;IACzD,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;CAC1B;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;IACpB,eAAe,EAAE,OAAO,CAAA;IACxB,eAAe,EAAE,OAAO,CAAA;IACxB,eAAe,EAAE,OAAO,CAAA;IACxB,QAAQ,EAAE,cAAc,EAAE,CAAA;CAC3B;AAED,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,YAAY,EAAE,CAAA;CACtB;AAyBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,cAAc,CAenE;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7E"}
@@ -0,0 +1,97 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * @module engine/schema-fingerprint
5
+ * A deterministic name for "the shape this API answers in".
6
+ *
7
+ * Computed from live seed definitions (`introspectSeedDefinitions`), embedded in generated client
8
+ * types at build time (sprint 3), returned on every public response as `X-Schema-Revision`
9
+ * (sprint 4), and compared by the client at request time (sprint 5). Both ends MUST compute it
10
+ * with this function — two implementations would be free to disagree, and a drift detector whose
11
+ * ends disagree is worse than none.
12
+ *
13
+ * What is hashed is a CONTRACT PROJECTION, not the whole seed definition: labels, hints, dashboard
14
+ * icons and layout cannot change a single response byte, and hashing them would fire a hard
15
+ * `BeechProblem` in someone else's production client over a typo fix.
16
+ */
17
+ import { canonicalStringify } from '../common/canonical-json.js';
18
+ import { resolvePolicies } from './policies.js';
19
+ /**
20
+ * Bumped ONLY when the projection below or the canonical byte format changes — i.e. when
21
+ * fingerprints computed by two builds are no longer comparable. It is carried in the fingerprint
22
+ * string itself so a version skew reads as a mismatch instead of as an accidental match.
23
+ */
24
+ export const SCHEMA_FINGERPRINT_VERSION = 1;
25
+ function projectBranch(branch) {
26
+ const policies = resolvePolicies(branch);
27
+ return {
28
+ alias: branch.alias,
29
+ type: branch.type,
30
+ ...(branch.format !== undefined ? { format: branch.format } : {}),
31
+ ...(branch.multiple !== undefined ? { multiple: branch.multiple } : {}),
32
+ // Option order is the contract: it is the order a select renders and a union type lists.
33
+ ...(branch.options !== undefined ? { options: [...branch.options] } : {}),
34
+ requiredOnCreate: branch.requiredOnCreate ?? false,
35
+ requiredOnUpdate: branch.requiredOnUpdate ?? false,
36
+ ...(branch.targetSeed !== undefined ? { targetSeed: branch.targetSeed } : {}),
37
+ visibility: policies.visibility,
38
+ publicRead: policies.public,
39
+ publicEdit: policies.publicEdit,
40
+ ...(branch.minItems !== undefined ? { minItems: branch.minItems } : {}),
41
+ ...(branch.maxItems !== undefined ? { maxItems: branch.maxItems } : {}),
42
+ // Spread only when true so every schema without localized branches keeps its fingerprint.
43
+ ...(branch.localized === true ? { localized: true } : {}),
44
+ ...(branch.fields ? { fields: branch.fields.map(projectBranch) } : {}),
45
+ };
46
+ }
47
+ /**
48
+ * Reduces seeds to what a response shape depends on.
49
+ *
50
+ * Deliberately EXCLUDED, and each for a reason a future reader must not "fix":
51
+ * - `id` (`br_XX`) — a stable internal handle; it never appears in a payload, and minting order
52
+ * differs between an environment built by migration and one grown through the dashboard.
53
+ * - `label`, `labelPlural`, `hint`, `dashboard`, `layout` — presentation, never response shape.
54
+ * - `retentionDays`, `onDelete`, `policies.search|filter|sort`, `numberOptions`, `fileOptions`,
55
+ * `policies.classification|privacy` — behaviour and storage concerns that leave the response
56
+ * shape identical. (`privacy` DOES change a stored value's encoding, but the API type stays
57
+ * `string`; drift there is a data concern, not a type concern.)
58
+ * - anything physical (column order, index names) — see the VETO Audit.
59
+ *
60
+ * Seeds are sorted by slug; BRANCH ORDER IS PRESERVED, because it is the declared field order the
61
+ * generated types and the dashboard form both follow.
62
+ */
63
+ export function projectSchemaContract(seeds) {
64
+ return {
65
+ fingerprintVersion: SCHEMA_FINGERPRINT_VERSION,
66
+ seeds: [...seeds]
67
+ .sort((a, b) => a.slug.localeCompare(b.slug))
68
+ .map(seed => ({
69
+ slug: seed.slug,
70
+ displayNameAlias: seed.displayNameAlias,
71
+ allowDrafts: seed.allowDrafts ?? false,
72
+ allowPublicRead: seed.allowPublicRead ?? false,
73
+ allowPublicPost: seed.allowPublicPost ?? false,
74
+ allowPublicEdit: seed.allowPublicEdit ?? false,
75
+ branches: seed.branches.map(projectBranch),
76
+ })),
77
+ };
78
+ }
79
+ function toHex(buffer) {
80
+ return Array.from(new Uint8Array(buffer), byte => byte.toString(16).padStart(2, '0')).join('');
81
+ }
82
+ /**
83
+ * `v{VERSION}:{32 lowercase hex}` — SHA-256 over the canonical JSON of the contract projection,
84
+ * truncated to 128 bits.
85
+ *
86
+ * Truncation is deliberate: this value travels on EVERY public response as `X-Schema-Revision`,
87
+ * and 128 bits of a SHA-256 digest carries no realistic collision risk for a value space of a few
88
+ * hundred schema revisions. It is a revision marker, never a security token.
89
+ *
90
+ * Web Crypto only — the same API the Worker and Node ≥ 18 both expose, as `webhook-crypto.ts`
91
+ * already relies on. `@beechcms/core` gains no dependency.
92
+ */
93
+ export async function computeSchemaFingerprint(seeds) {
94
+ const bytes = new TextEncoder().encode(canonicalStringify(projectSchemaContract(seeds)));
95
+ const digest = await crypto.subtle.digest('SHA-256', bytes);
96
+ return `v${SCHEMA_FINGERPRINT_VERSION}:${toHex(digest).slice(0, 32)}`;
97
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"seed-registry.d.ts","sourceRoot":"","sources":["../../src/engine/seed-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAI9C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,IAAI,IAAI,EAAE,CAAA;IAEb;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAE9B;;;;;OAKG;IACH,kBAAkB,IAAI,IAAI,EAAE,CAAA;IAE5B;;;OAGG;IACH,cAAc,IAAI,IAAI,EAAE,CAAA;IAExB;;;OAGG;IACH,YAAY,IAAI,IAAI,EAAE,CAAA;CACvB;AAID,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;gBAEzB,KAAK,EAAE,IAAI,EAAE;IAkCzB,GAAG,IAAI,IAAI,EAAE;IAIb,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI9B,kBAAkB,IAAI,IAAI,EAAE;IAI5B,cAAc,IAAI,IAAI,EAAE;IAIxB,YAAY,IAAI,IAAI,EAAE;CAGvB;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;CAAG;AAEzD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,MAAM,CAQjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CA0F1E"}
1
+ {"version":3,"file":"seed-registry.d.ts","sourceRoot":"","sources":["../../src/engine/seed-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAI9C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,IAAI,IAAI,EAAE,CAAA;IAEb;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAE9B;;;;;OAKG;IACH,kBAAkB,IAAI,IAAI,EAAE,CAAA;IAE5B;;;OAGG;IACH,cAAc,IAAI,IAAI,EAAE,CAAA;IAExB;;;OAGG;IACH,YAAY,IAAI,IAAI,EAAE,CAAA;CACvB;AAID,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IAErC,YAAY,KAAK,EAAE,IAAI,EAAE,EAgCxB;IAED,GAAG,IAAI,IAAI,EAAE,CAEZ;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE7B;IAED,kBAAkB,IAAI,IAAI,EAAE,CAE3B;IAED,cAAc,IAAI,IAAI,EAAE,CAEvB;IAED,YAAY,IAAI,IAAI,EAAE,CAErB;CACF;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;CAAG;AAEzD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,MAAM,CAQjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CA0F1E"}
@@ -0,0 +1,14 @@
1
+ import type { Seed } from '../types.js';
2
+ /**
3
+ * Fills the id of every branch (and repeater sub-field) that lacks one.
4
+ *
5
+ * The stored id wins by alias match; only an alias the stored definition does not know gets a fresh
6
+ * `nextBranchId`, minted past every stored id and every explicit id anywhere in the candidate, so it
7
+ * never collides with a later explicit id nor recycles the id of a branch the candidate omits. An id
8
+ * already present on the candidate is kept as-is: callers that author without ids (hand-written
9
+ * manifests) must send none rather than invented ones.
10
+ */
11
+ export declare function resolveCandidateIds<T extends {
12
+ branches?: unknown;
13
+ }>(candidate: T, stored: Seed | null): T;
14
+ //# sourceMappingURL=candidate-ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidate-ids.d.ts","sourceRoot":"","sources":["../../../src/engine/seeds/candidate-ids.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,aAAa,CAAA;AAE/C;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,CAAC,CAM1G"}
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ /**
4
+ * @module engine/seeds/candidate-ids
5
+ * Resolves branch ids on a candidate seed definition against the stored one.
6
+ */
7
+ import { nextBranchId } from './seed-registry.js';
8
+ /**
9
+ * Fills the id of every branch (and repeater sub-field) that lacks one.
10
+ *
11
+ * The stored id wins by alias match; only an alias the stored definition does not know gets a fresh
12
+ * `nextBranchId`, minted past every stored id and every explicit id anywhere in the candidate, so it
13
+ * never collides with a later explicit id nor recycles the id of a branch the candidate omits. An id
14
+ * already present on the candidate is kept as-is: callers that author without ids (hand-written
15
+ * manifests) must send none rather than invented ones.
16
+ */
17
+ export function resolveCandidateIds(candidate, stored) {
18
+ const storedBranches = stored?.branches ?? [];
19
+ return {
20
+ ...candidate,
21
+ branches: assignIds(Array.isArray(candidate.branches) ? candidate.branches : [], storedBranches),
22
+ };
23
+ }
24
+ function assignIds(branches, stored) {
25
+ const storedByAlias = new Map(stored.map(b => [b.alias, b]));
26
+ const taken = [...stored, ...branches.filter(b => b.id)];
27
+ const resolved = [];
28
+ for (const source of branches) {
29
+ const match = source.alias === undefined ? undefined : storedByAlias.get(source.alias);
30
+ const branch = { ...source };
31
+ if (!branch.id) {
32
+ branch.id = match?.id || nextBranchId({ branches: taken });
33
+ taken.push(branch);
34
+ }
35
+ if (Array.isArray(source.fields))
36
+ branch.fields = assignIds(source.fields, match?.fields ?? []);
37
+ resolved.push(branch);
38
+ }
39
+ return resolved;
40
+ }
@@ -0,0 +1,3 @@
1
+ import type { Seed } from '../types.js';
2
+ export declare function defineSeed(seed: Seed): Seed;
3
+ //# sourceMappingURL=define-seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-seed.d.ts","sourceRoot":"","sources":["../../../src/engine/seeds/define-seed.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAE3C"}
@@ -0,0 +1,5 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export function defineSeed(seed) {
4
+ return seed;
5
+ }
@@ -0,0 +1,38 @@
1
+ import type { Branch, Seed } from '../types.js';
2
+ /** A branch as either side of a comparison carries it: stored (`Branch`, with id) or manifest-authored (id optional). */
3
+ export type BranchDefinitionLike = Omit<Branch, 'id' | 'fields'> & {
4
+ id?: string;
5
+ fields?: BranchDefinitionLike[];
6
+ };
7
+ /** A seed as either side of a comparison carries it: stored (`Seed`) or manifest-authored (no layout). */
8
+ export type SeedDefinitionLike = Omit<Seed, 'branches' | 'layout'> & {
9
+ branches: BranchDefinitionLike[];
10
+ layout?: unknown;
11
+ };
12
+ /** Seed-level flags the engine treats as `false` when omitted. */
13
+ export declare const SEED_DEFINITION_FLAGS: readonly ["allowDrafts", "allowPublicRead", "allowPublicPost", "allowPublicEdit", "softDelete"];
14
+ /** Branch-level flags the engine treats as `false` when omitted. `multiple` is resolved separately (see normalizeBranchDefinition). */
15
+ export declare const BRANCH_DEFINITION_FLAGS: readonly ["requiredOnCreate", "requiredOnUpdate"];
16
+ /**
17
+ * Comparable form of one branch definition. Two branches are the same definition iff their canonicalStringify bytes match.
18
+ *
19
+ * - `id` is dropped, recursively through `fields`.
20
+ * - `requiredOnCreate` / `requiredOnUpdate` omitted ≡ `false`.
21
+ * - `multiple` omitted ≡ `true` on `tags` (single source of truth: `isSingleChoiceTags`), ≡ `false` on every other type.
22
+ * - Every other key, unknown ones included, is copied unchanged: `options` is compared as declared (values, colors, order).
23
+ */
24
+ export declare function normalizeBranchDefinition(branch: BranchDefinitionLike): Record<string, unknown>;
25
+ /** Comparable form of one seed definition (branches normalized, order kept). `layout` is server-populated and dropped. */
26
+ export declare function normalizeSeedDefinition(seed: SeedDefinitionLike): Record<string, unknown>;
27
+ export interface SeedDefinitionDiff {
28
+ /** True when the candidate's comparable definition differs from the stored one. Always true when nothing is stored. */
29
+ changed: boolean;
30
+ /**
31
+ * Aliases, in candidate order, of candidate branches that are new (no stored branch with the same id) or whose
32
+ * comparable definition differs from the stored branch with the same id. `[]` when nothing is stored.
33
+ */
34
+ changedBranches: string[];
35
+ }
36
+ /** Compares a stored seed definition with a candidate whose ids were already resolved ({@link resolveCandidateIds}). Pure. */
37
+ export declare function diffSeedDefinition(stored: Seed | null, candidate: Seed): SeedDefinitionDiff;
38
+ //# sourceMappingURL=seed-definition-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-definition-diff.d.ts","sourceRoot":"","sources":["../../../src/engine/seeds/seed-definition-diff.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAI/C,yHAAyH;AACzH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAA;CAAE,CAAA;AAEnH,0GAA0G;AAC1G,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC,GAAG;IAAE,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE3H,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,iGAAkG,CAAA;AAEpI,uIAAuI;AACvI,eAAO,MAAM,uBAAuB,mDAAoD,CAAA;AAExF;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO/F;AAED,0HAA0H;AAC1H,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzF;AAED,MAAM,WAAW,kBAAkB;IACjC,uHAAuH;IACvH,OAAO,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,8HAA8H;AAC9H,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,kBAAkB,CAe3F"}
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ import { canonicalStringify } from '../../common/canonical-json.js';
4
+ import { isSingleChoiceTags } from './tag-options.js';
5
+ /** Seed-level flags the engine treats as `false` when omitted. */
6
+ export const SEED_DEFINITION_FLAGS = ['allowDrafts', 'allowPublicRead', 'allowPublicPost', 'allowPublicEdit', 'softDelete'];
7
+ /** Branch-level flags the engine treats as `false` when omitted. `multiple` is resolved separately (see normalizeBranchDefinition). */
8
+ export const BRANCH_DEFINITION_FLAGS = ['requiredOnCreate', 'requiredOnUpdate'];
9
+ /**
10
+ * Comparable form of one branch definition. Two branches are the same definition iff their canonicalStringify bytes match.
11
+ *
12
+ * - `id` is dropped, recursively through `fields`.
13
+ * - `requiredOnCreate` / `requiredOnUpdate` omitted ≡ `false`.
14
+ * - `multiple` omitted ≡ `true` on `tags` (single source of truth: `isSingleChoiceTags`), ≡ `false` on every other type.
15
+ * - Every other key, unknown ones included, is copied unchanged: `options` is compared as declared (values, colors, order).
16
+ */
17
+ export function normalizeBranchDefinition(branch) {
18
+ const { id: _id, fields, ...rest } = branch;
19
+ const normalized = { ...rest };
20
+ for (const flag of BRANCH_DEFINITION_FLAGS)
21
+ normalized[flag] = branch[flag] === true;
22
+ normalized.multiple = branch.type === 'tags' ? !isSingleChoiceTags(branch) : branch.multiple === true;
23
+ if (fields !== undefined)
24
+ normalized.fields = fields.map(normalizeBranchDefinition);
25
+ return normalized;
26
+ }
27
+ /** Comparable form of one seed definition (branches normalized, order kept). `layout` is server-populated and dropped. */
28
+ export function normalizeSeedDefinition(seed) {
29
+ const { layout: _layout, branches, ...rest } = seed;
30
+ const normalized = { ...rest };
31
+ for (const flag of SEED_DEFINITION_FLAGS)
32
+ normalized[flag] = seed[flag] === true;
33
+ normalized.branches = (branches ?? []).map(normalizeBranchDefinition);
34
+ return normalized;
35
+ }
36
+ /** Compares a stored seed definition with a candidate whose ids were already resolved ({@link resolveCandidateIds}). Pure. */
37
+ export function diffSeedDefinition(stored, candidate) {
38
+ if (stored === null)
39
+ return { changed: true, changedBranches: [] };
40
+ const storedById = new Map(stored.branches.map(branch => [branch.id, branch]));
41
+ const changedBranches = candidate.branches
42
+ .filter(branch => {
43
+ const previous = storedById.get(branch.id);
44
+ return previous === undefined
45
+ || canonicalStringify(normalizeBranchDefinition(branch)) !== canonicalStringify(normalizeBranchDefinition(previous));
46
+ })
47
+ .map(branch => branch.alias);
48
+ const changed = changedBranches.length > 0
49
+ || canonicalStringify(normalizeSeedDefinition(candidate)) !== canonicalStringify(normalizeSeedDefinition(stored));
50
+ return { changed, changedBranches };
51
+ }