@michaelthielemann/kestrel 3.0.1 → 4.0.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 (341) hide show
  1. package/README.md +35 -110
  2. package/kestrel.config.ts +1 -1
  3. package/layers/access/server/middleware/00.ip-allowlist.ts +3 -18
  4. package/layers/access/server/middleware/access-guard.ts +25 -23
  5. package/layers/access/server/types.d.ts +1 -2
  6. package/layers/admin/app/components/AdminAccount.vue +1 -1
  7. package/layers/admin/app/components/BlockFields.vue +1 -2
  8. package/layers/admin/app/components/BlockPreview.vue +17 -5
  9. package/layers/admin/app/components/BlocksBody.vue +1 -1
  10. package/layers/admin/app/components/CollectionEditor.vue +35 -16
  11. package/layers/admin/app/components/CollectionList.vue +34 -3
  12. package/layers/admin/app/components/CollectionListBulkBar.vue +17 -3
  13. package/layers/admin/app/components/CollectionListFilterPanel.vue +1 -1
  14. package/layers/admin/app/components/CollectionListPager.vue +1 -1
  15. package/layers/admin/app/components/CollectionListTable.vue +41 -2
  16. package/layers/admin/app/components/EditorStatus.vue +8 -7
  17. package/layers/admin/app/components/LocaleBar.vue +3 -1
  18. package/layers/admin/app/components/PageFields.vue +2 -4
  19. package/layers/admin/app/components/SeoFields.vue +2 -4
  20. package/layers/admin/app/components/SingletonEditor.vue +3 -2
  21. package/layers/admin/app/composables/useAuth.ts +3 -3
  22. package/layers/admin/app/composables/useBlockTree.ts +1 -1
  23. package/layers/admin/app/composables/useBlocks.ts +1 -1
  24. package/layers/admin/app/composables/useCollectionOps.ts +45 -8
  25. package/layers/admin/app/composables/useCollections.ts +1 -2
  26. package/layers/admin/app/composables/useEditForm.ts +35 -17
  27. package/layers/admin/app/composables/useLinkResolver.ts +1 -1
  28. package/layers/admin/app/composables/useListBatchActions.ts +20 -3
  29. package/layers/admin/app/composables/useListColumns.ts +1 -1
  30. package/layers/admin/app/composables/useListFilterDraft.ts +3 -2
  31. package/layers/admin/app/composables/useListRows.ts +7 -2
  32. package/layers/admin/app/composables/useListUrlState.ts +1 -1
  33. package/layers/admin/app/composables/usePublishStatus.ts +2 -2
  34. package/layers/admin/app/layouts/admin.vue +0 -1
  35. package/layers/admin/app/pages/admin/[collection]/[id].vue +5 -4
  36. package/layers/admin/app/pages/admin/index.vue +1 -1
  37. package/layers/admin/app/pages/admin/references.vue +2 -2
  38. package/layers/admin/app/utils/block-tree.ts +1 -1
  39. package/layers/admin/app/utils/collection-ops.ts +28 -3
  40. package/layers/admin/app/utils/edit-form.ts +34 -2
  41. package/layers/admin/app/utils/editor-expose.ts +2 -0
  42. package/layers/admin/app/utils/editor-form-context.ts +1 -2
  43. package/layers/admin/app/utils/field-keys.ts +1 -1
  44. package/layers/admin/app/utils/list-columns.ts +3 -2
  45. package/layers/admin/app/utils/list-query.ts +2 -2
  46. package/layers/admin/app/utils/populate-blocks.ts +2 -2
  47. package/layers/admin/app/utils/reauth.ts +5 -6
  48. package/layers/auth/server/plugins/01.register-auth-pipelines.ts +7 -0
  49. package/layers/collections/server/plugins/01.register.ts +9 -12
  50. package/layers/collections/server/plugins/02.register-relation-populate.ts +5 -7
  51. package/layers/{fields → core}/app/utils/field-factories.ts +1 -1
  52. package/layers/core/modules/auto-discovery/extract-block.ts +3 -3
  53. package/layers/core/modules/auto-discovery/index.ts +68 -11
  54. package/layers/core/modules/auto-discovery/package-registry.ts +19 -0
  55. package/layers/core/modules/auto-discovery/scan.ts +77 -0
  56. package/layers/core/modules/auto-discovery/virtual.d.ts +5 -0
  57. package/layers/core/modules/component-namespace/index.ts +24 -0
  58. package/layers/core/modules/kestrel/index.ts +6 -1
  59. package/layers/core/modules/plugin-order/index.ts +69 -0
  60. package/layers/core/modules/plugin-order/plugin-order.ts +273 -0
  61. package/layers/core/nuxt.config.ts +1 -0
  62. package/layers/core/server/api/[...path].ts +98 -0
  63. package/layers/core/server/plugins/00.config.ts +12 -0
  64. package/layers/core/server/plugins/00.migrate.ts +1 -0
  65. package/layers/core/server/plugins/01.register-introspection-pipeline.ts +5 -0
  66. package/layers/core/server/plugins/01.register-openapi-pipeline.ts +5 -0
  67. package/layers/core/server/plugins/01.register-tooling-pipelines.ts +5 -0
  68. package/layers/core/server/plugins/02.schema-sync.ts +2 -7
  69. package/layers/core/server/plugins/04.outbox-worker.ts +31 -0
  70. package/layers/core/server/plugins/05.reindex-refs.ts +5 -0
  71. package/layers/core/server/routes/__kestrel/dashboard.get.ts +29 -0
  72. package/layers/core/server/tasks/db/migrate-module.ts +83 -0
  73. package/layers/core/server/tasks/db/migrate-revisions.ts +20 -0
  74. package/layers/core/server/tasks/db/migrate.ts +2 -6
  75. package/layers/core/server/utils/server-config.ts +66 -3
  76. package/layers/fields/server/plugins/01.register-blocks-pipeline.ts +7 -0
  77. package/layers/fields/server/plugins/01.register-field-populate.ts +2 -2
  78. package/layers/media/app/components/KestrelImg.vue +3 -3
  79. package/layers/media/app/components/MediaLibrary.vue +2 -2
  80. package/layers/media/app/components/field/Media.vue +1 -1
  81. package/layers/media/app/composables/useMediaResolver.ts +1 -1
  82. package/layers/media/app/composables/useMediaUpload.ts +1 -1
  83. package/layers/media/app/composables/useMediaVariant.ts +2 -2
  84. package/layers/media/app/utils/ai-disclosure.ts +1 -1
  85. package/layers/media/app/utils/library.ts +1 -1
  86. package/layers/media/app/utils/ops.ts +1 -3
  87. package/layers/media/app/utils/picture-model.ts +2 -2
  88. package/layers/media/app/utils/variant-name.ts +1 -1
  89. package/layers/media/server/middleware/ondemand-variants.ts +6 -5
  90. package/layers/media/server/plugins/01.register-media-pipelines.ts +7 -0
  91. package/layers/media/server/plugins/02.register-media.ts +10 -7
  92. package/layers/media/server/plugins/04.variant-capture.ts +12 -8
  93. package/layers/media/server/plugins/05.media-cleanup.ts +5 -0
  94. package/layers/media/server/tasks/media/backfill.ts +3 -4
  95. package/layers/public/app/components/KestrelLink.vue +1 -1
  96. package/layers/public/app/pages/[...slug].vue +1 -1
  97. package/layers/public/app/pages/__kestrel/preview.vue +2 -2
  98. package/layers/public/app/utils/json-ld.ts +1 -1
  99. package/layers/public/app/utils/link-href.ts +1 -1
  100. package/layers/public/app/utils/page-head.ts +1 -1
  101. package/layers/public/modules/deploy-output/index.ts +4 -6
  102. package/layers/public/modules/prerender-routes/index.ts +4 -4
  103. package/layers/public/modules/prerender-routes/routes.ts +1 -1
  104. package/layers/public/modules/prune-media/index.ts +2 -2
  105. package/layers/public/server/delivery-live/serve.ts +111 -0
  106. package/layers/public/server/middleware/delivery-live-catchall.ts +7 -0
  107. package/layers/public/server/pipelines/index.ts +23 -0
  108. package/layers/public/server/plugins/00.ensure-snapshot-triggers.ts +14 -0
  109. package/layers/public/server/plugins/01.register-public-pipelines.ts +7 -0
  110. package/layers/public/server/plugins/02.register-links.ts +2 -3
  111. package/layers/public/server/plugins/03.redirects.ts +41 -23
  112. package/layers/public/server/plugins/05.plan-publish.ts +5 -0
  113. package/layers/public/server/plugins/zz.publish.ts +79 -24
  114. package/layers/public/server/routes/llms-full.txt.get.ts +5 -5
  115. package/layers/public/server/routes/llms.txt.get.ts +4 -2
  116. package/layers/public/server/routes/redirects.json.get.ts +2 -2
  117. package/layers/public/server/routes/robots.txt.get.ts +2 -0
  118. package/layers/public/server/routes/sitemap.xml.get.ts +16 -6
  119. package/layers/public/server/tasks/publish/run.ts +9 -4
  120. package/layers/public/server/utils/publish/render-live.ts +26 -0
  121. package/layers/ui/app/components/field/Choice.vue +1 -1
  122. package/layers/ui/app/components/field/Datetime.vue +1 -1
  123. package/layers/ui/app/components/field/Json.vue +1 -2
  124. package/layers/ui/app/components/field/Layout.vue +2 -4
  125. package/layers/ui/app/components/field/Link.vue +1 -1
  126. package/layers/ui/app/components/field/LinkInternalPicker.vue +3 -3
  127. package/layers/ui/app/components/field/Number.vue +2 -2
  128. package/layers/ui/app/components/field/Relation.vue +1 -1
  129. package/layers/ui/app/components/field/Repeater.vue +1 -3
  130. package/layers/ui/app/components/field/Slug.vue +2 -3
  131. package/layers/ui/app/components/field/Text.vue +1 -1
  132. package/layers/ui/app/components/ui/Richtext.vue +1 -1
  133. package/layers/ui/app/components/ui/RichtextToolbar.vue +1 -3
  134. package/layers/ui/app/composables/useLinkField.ts +1 -1
  135. package/layers/ui/app/composables/useRepeater.ts +1 -1
  136. package/layers/ui/app/i18n/de.ts +7 -7
  137. package/layers/ui/app/i18n/en.ts +7 -39
  138. package/layers/ui/app/utils/field-component.ts +1 -1
  139. package/layers/ui/app/utils/field-registry.ts +1 -1
  140. package/layers/ui/app/utils/icons.ts +2 -6
  141. package/layers/ui/app/utils/localized.ts +1 -1
  142. package/nuxt.config.ts +1 -1
  143. package/package.json +53 -19
  144. package/scripts/consumer-template-ci.mjs +157 -0
  145. package/scripts/coverage-all.mjs +163 -0
  146. package/scripts/dashboard.mjs +89 -0
  147. package/scripts/hash-password.mjs +1 -1
  148. package/scripts/lib/coverage-model.mjs +51 -0
  149. package/scripts/port-graph.mjs +350 -0
  150. package/scripts/typecheck.mjs +11 -0
  151. package/templates/starter/app/blocks/Prose.vue +1 -1
  152. package/layers/access/server/utils/csrf.ts +0 -39
  153. package/layers/access/server/utils/grant-registry.ts +0 -36
  154. package/layers/access/server/utils/guard.ts +0 -44
  155. package/layers/access/server/utils/ip-allowlist.ts +0 -79
  156. package/layers/access/server/utils/policy.ts +0 -98
  157. package/layers/access/server/utils/public-resources.ts +0 -11
  158. package/layers/access/server/utils/render-context.ts +0 -41
  159. package/layers/access/server/utils/require-admin.ts +0 -15
  160. package/layers/admin/app/pages/admin/[collection]/[id].nuxt.test.ts +0 -200
  161. package/layers/admin/app/pages/admin/[collection]/publish-preview.nuxt.test.ts +0 -142
  162. package/layers/auth/server/api/auth/login.post.ts +0 -38
  163. package/layers/auth/server/api/auth/logout.post.ts +0 -9
  164. package/layers/auth/server/api/auth/session.get.ts +0 -1
  165. package/layers/auth/server/utils/admin-credential.ts +0 -42
  166. package/layers/auth/server/utils/client-ip.ts +0 -88
  167. package/layers/auth/server/utils/login-throttle.ts +0 -126
  168. package/layers/auth/server/utils/password.ts +0 -52
  169. package/layers/auth/server/utils/session-cookie.ts +0 -44
  170. package/layers/auth/server/utils/session-epoch.ts +0 -96
  171. package/layers/auth/server/utils/session.ts +0 -88
  172. package/layers/collections/server/collections/pages.ts +0 -19
  173. package/layers/collections/server/utils/populate-relations.ts +0 -79
  174. package/layers/core/app/utils/bulk-actions.ts +0 -9
  175. package/layers/core/app/utils/filter-ops.ts +0 -98
  176. package/layers/core/app/utils/list-limits.ts +0 -27
  177. package/layers/core/app/utils/locale-path.ts +0 -12
  178. package/layers/core/app/utils/slugify.ts +0 -16
  179. package/layers/core/server/api/[collection]/[id]/dead-refs.get.ts +0 -8
  180. package/layers/core/server/api/[collection]/[id]/translations.get.ts +0 -4
  181. package/layers/core/server/api/[collection]/[id].delete.ts +0 -5
  182. package/layers/core/server/api/[collection]/[id].get.ts +0 -11
  183. package/layers/core/server/api/[collection]/[id].patch.ts +0 -8
  184. package/layers/core/server/api/[collection]/bulk.post.ts +0 -37
  185. package/layers/core/server/api/[collection]/index.get.ts +0 -24
  186. package/layers/core/server/api/[collection]/index.post.ts +0 -8
  187. package/layers/core/server/api/[collection]/index.put.test.ts +0 -76
  188. package/layers/core/server/api/[collection]/index.put.ts +0 -24
  189. package/layers/core/server/api/[collection]/options.get.test.ts +0 -60
  190. package/layers/core/server/api/[collection]/options.get.ts +0 -18
  191. package/layers/core/server/api/[collection]/populate-scope.test.ts +0 -119
  192. package/layers/core/server/api/[collection]/translations.get.test.ts +0 -90
  193. package/layers/core/server/api/[collection]/translations.get.ts +0 -25
  194. package/layers/core/server/api/collections/[name].get.ts +0 -4
  195. package/layers/core/server/api/collections/index.get.ts +0 -3
  196. package/layers/core/server/api/references/broken.get.ts +0 -9
  197. package/layers/core/server/api/references/referrers.get.ts +0 -24
  198. package/layers/core/server/database/record-refs.ts +0 -20
  199. package/layers/core/server/plugins/03.record-refs.ts +0 -12
  200. package/layers/core/server/schema/bootstrap.ts +0 -41
  201. package/layers/core/server/schema/desired.ts +0 -99
  202. package/layers/core/server/schema/dev-sync.ts +0 -23
  203. package/layers/core/server/schema/dialect.ts +0 -61
  204. package/layers/core/server/schema/diff.ts +0 -110
  205. package/layers/core/server/schema/introspect.ts +0 -68
  206. package/layers/core/server/schema/model.ts +0 -61
  207. package/layers/core/server/schema/render-sqlite.ts +0 -89
  208. package/layers/core/server/schema/sync.ts +0 -201
  209. package/layers/core/server/utils/blocks.ts +0 -6
  210. package/layers/core/server/utils/collection-types.ts +0 -28
  211. package/layers/core/server/utils/crud.ts +0 -578
  212. package/layers/core/server/utils/db.ts +0 -26
  213. package/layers/core/server/utils/defineCollection.ts +0 -213
  214. package/layers/core/server/utils/duplicate.ts +0 -162
  215. package/layers/core/server/utils/field-layout.ts +0 -125
  216. package/layers/core/server/utils/filter-predicate.ts +0 -101
  217. package/layers/core/server/utils/http.ts +0 -50
  218. package/layers/core/server/utils/if-unmodified.ts +0 -13
  219. package/layers/core/server/utils/kestrel-config.ts +0 -451
  220. package/layers/core/server/utils/key-lock.ts +0 -33
  221. package/layers/core/server/utils/locale.ts +0 -53
  222. package/layers/core/server/utils/page-route.ts +0 -58
  223. package/layers/core/server/utils/page-slug.ts +0 -127
  224. package/layers/core/server/utils/picker.ts +0 -82
  225. package/layers/core/server/utils/populate.ts +0 -50
  226. package/layers/core/server/utils/prerender-memo.ts +0 -23
  227. package/layers/core/server/utils/read-capture.ts +0 -37
  228. package/layers/core/server/utils/record-ref-index.ts +0 -200
  229. package/layers/core/server/utils/registry.ts +0 -24
  230. package/layers/core/server/utils/resolve-scope.ts +0 -79
  231. package/layers/core/server/utils/seo.ts +0 -42
  232. package/layers/core/server/utils/serialize-collection.ts +0 -147
  233. package/layers/core/server/utils/sql.ts +0 -2
  234. package/layers/core/server/utils/storage.local.ts +0 -117
  235. package/layers/core/server/utils/storage.s3.ts +0 -197
  236. package/layers/core/server/utils/storage.ts +0 -90
  237. package/layers/core/server/utils/write-effects.ts +0 -40
  238. package/layers/core/server/utils/write-events.ts +0 -31
  239. package/layers/fields/app/utils/condition.ts +0 -71
  240. package/layers/fields/app/utils/define-block.ts +0 -13
  241. package/layers/fields/app/utils/field-constraints.ts +0 -17
  242. package/layers/fields/app/utils/field-meta.ts +0 -33
  243. package/layers/fields/app/utils/field-validate.ts +0 -75
  244. package/layers/fields/app/utils/field-value.ts +0 -7
  245. package/layers/fields/app/utils/richtext-links.ts +0 -48
  246. package/layers/fields/server/api/blocks/index.get.ts +0 -9
  247. package/layers/fields/server/field-registry/index.ts +0 -249
  248. package/layers/fields/server/field-registry/naming.ts +0 -10
  249. package/layers/fields/server/field-registry/sanitize.ts +0 -43
  250. package/layers/fields/server/field-registry/types.ts +0 -19
  251. package/layers/fields/server/utils/block-ids.ts +0 -43
  252. package/layers/fields/server/utils/block-populate.ts +0 -41
  253. package/layers/fields/server/utils/buildCollection.ts +0 -90
  254. package/layers/fields/server/utils/buildFieldSchema.ts +0 -22
  255. package/layers/fields/server/utils/buildTable.ts +0 -113
  256. package/layers/fields/server/utils/conditional-required.ts +0 -25
  257. package/layers/fields/server/utils/defineBlock.ts +0 -86
  258. package/layers/fields/server/utils/defineFieldType.ts +0 -33
  259. package/layers/fields/server/utils/extract-refs.ts +0 -152
  260. package/layers/fields/server/utils/field-populate.ts +0 -68
  261. package/layers/media/server/api/media/[id]/usages.get.ts +0 -8
  262. package/layers/media/server/api/media/[id].delete.ts +0 -18
  263. package/layers/media/server/api/media/[id].get.ts +0 -10
  264. package/layers/media/server/api/media/[id].patch.test.ts +0 -66
  265. package/layers/media/server/api/media/[id].patch.ts +0 -65
  266. package/layers/media/server/api/media/backfill.post.ts +0 -18
  267. package/layers/media/server/api/media/copy.post.ts +0 -7
  268. package/layers/media/server/api/media/delete.post.ts +0 -13
  269. package/layers/media/server/api/media/folders.post.ts +0 -18
  270. package/layers/media/server/api/media/index.get.ts +0 -15
  271. package/layers/media/server/api/media/index.post.ts +0 -173
  272. package/layers/media/server/api/media/library.get.ts +0 -17
  273. package/layers/media/server/api/media/move.post.ts +0 -7
  274. package/layers/media/server/api/media/rename.post.ts +0 -7
  275. package/layers/media/server/api/media/resolve.get.ts +0 -13
  276. package/layers/media/server/collections/media-settings.ts +0 -25
  277. package/layers/media/server/collections/media.ts +0 -43
  278. package/layers/media/server/database/folders.ts +0 -10
  279. package/layers/media/server/plugins/03.media-cleanup.ts +0 -20
  280. package/layers/media/server/schema-tables/folders.ts +0 -4
  281. package/layers/media/server/utils/ai-disclosure-enabled.ts +0 -16
  282. package/layers/media/server/utils/ai-signal-detect.ts +0 -155
  283. package/layers/media/server/utils/backfill.ts +0 -144
  284. package/layers/media/server/utils/derive.ts +0 -59
  285. package/layers/media/server/utils/folder-paths.ts +0 -42
  286. package/layers/media/server/utils/folders.ts +0 -12
  287. package/layers/media/server/utils/library.ts +0 -91
  288. package/layers/media/server/utils/media-cleanup.ts +0 -27
  289. package/layers/media/server/utils/media-enabled.ts +0 -23
  290. package/layers/media/server/utils/media-ops.ts +0 -118
  291. package/layers/media/server/utils/media-write.ts +0 -13
  292. package/layers/media/server/utils/naming.ts +0 -52
  293. package/layers/media/server/utils/ondemand.ts +0 -69
  294. package/layers/media/server/utils/persist-upload.ts +0 -62
  295. package/layers/media/server/utils/populate.ts +0 -47
  296. package/layers/media/server/utils/record.ts +0 -71
  297. package/layers/media/server/utils/relocate-ops.ts +0 -341
  298. package/layers/media/server/utils/relocate-plan.ts +0 -63
  299. package/layers/media/server/utils/resolve.ts +0 -98
  300. package/layers/media/server/utils/sanitize-svg.ts +0 -12
  301. package/layers/media/server/utils/sniff.ts +0 -68
  302. package/layers/media/server/utils/storage-relocate.ts +0 -139
  303. package/layers/media/server/utils/translations.ts +0 -19
  304. package/layers/media/server/utils/usages.ts +0 -66
  305. package/layers/media/server/utils/variant-capture.ts +0 -70
  306. package/layers/media/server/utils/variants.ts +0 -123
  307. package/layers/public/modules/deploy-output/deploy-output.ts +0 -384
  308. package/layers/public/server/api/links/resolve.get.ts +0 -19
  309. package/layers/public/server/api/preview.get.ts +0 -28
  310. package/layers/public/server/api/preview.post.ts +0 -93
  311. package/layers/public/server/api/publish-status.get.ts +0 -58
  312. package/layers/public/server/api/publish.post.ts +0 -84
  313. package/layers/public/server/api/route.get.ts +0 -54
  314. package/layers/public/server/collections/redirects.ts +0 -75
  315. package/layers/public/server/collections/site.ts +0 -44
  316. package/layers/public/server/database/publish-deps.ts +0 -12
  317. package/layers/public/server/database/publish-status.ts +0 -19
  318. package/layers/public/server/schema-tables/publish-deps.ts +0 -4
  319. package/layers/public/server/schema-tables/publish-status.ts +0 -4
  320. package/layers/public/server/utils/link-resolve.ts +0 -38
  321. package/layers/public/server/utils/llms-full.ts +0 -125
  322. package/layers/public/server/utils/llms.ts +0 -52
  323. package/layers/public/server/utils/page-resolve.ts +0 -208
  324. package/layers/public/server/utils/populate-links.ts +0 -66
  325. package/layers/public/server/utils/preview-token.ts +0 -109
  326. package/layers/public/server/utils/publish/coalesce.ts +0 -22
  327. package/layers/public/server/utils/publish/deps-persistence.ts +0 -43
  328. package/layers/public/server/utils/publish/deps.ts +0 -87
  329. package/layers/public/server/utils/publish/invalidation.ts +0 -225
  330. package/layers/public/server/utils/publish/pending.ts +0 -74
  331. package/layers/public/server/utils/publish/publish-runtime.ts +0 -28
  332. package/layers/public/server/utils/publish/publish-status.ts +0 -72
  333. package/layers/public/server/utils/publish/publisher.ts +0 -362
  334. package/layers/public/server/utils/publish/queue.ts +0 -67
  335. package/layers/public/server/utils/publish/redirect-rules.ts +0 -221
  336. package/layers/public/server/utils/publish/redirects-artifact.ts +0 -20
  337. package/layers/public/server/utils/publish/route-for-record.ts +0 -16
  338. package/layers/public/server/utils/publish/route-keys.ts +0 -13
  339. package/layers/public/server/utils/richtext-markdown.ts +0 -260
  340. package/layers/public/server/utils/site-url.ts +0 -40
  341. package/layers/public/server/utils/sitemap.ts +0 -99
@@ -7,7 +7,7 @@ import UiButtonGroup from '../ui/ButtonGroup.vue'
7
7
  import UiCheckboxGroup from '../ui/CheckboxGroup.vue'
8
8
  import { resolveLocalized } from '../../utils/localized'
9
9
  import type { FieldComponentProps } from '../../utils/field-component'
10
- import type { FieldOf } from '../../../../core/server/utils/defineCollection'
10
+ import type { FieldOf } from '@michaelthielemann/kestrel-core'
11
11
 
12
12
  const props = defineProps<FieldComponentProps>()
13
13
  const model = defineModel<string | string[] | null>()
@@ -6,7 +6,7 @@ import UiTimeInput from '../ui/TimeInput.vue'
6
6
  import UiDatePicker from '../ui/DatePicker.vue'
7
7
  import UiDateRangePicker from '../ui/DateRangePicker.vue'
8
8
  import type { FieldComponentProps } from '../../utils/field-component'
9
- import type { FieldOf } from '../../../../core/server/utils/defineCollection'
9
+ import type { FieldOf } from '@michaelthielemann/kestrel-core'
10
10
 
11
11
  const { t } = useT()
12
12
  const props = defineProps<FieldComponentProps>()
@@ -2,8 +2,7 @@
2
2
  import { computed, ref, watch } from 'vue'
3
3
  import UiField from '../ui/Field.vue'
4
4
  import UiTextarea from '../ui/Textarea.vue'
5
- import { fieldConstraints } from '../../../../fields/app/utils/field-meta'
6
- import { tryParseJson } from '../../../../fields/app/utils/field-value'
5
+ import { fieldConstraints, tryParseJson } from '@michaelthielemann/kestrel-fields/client'
7
6
  import type { FieldComponentProps } from '../../utils/field-component'
8
7
 
9
8
  const props = defineProps<FieldComponentProps>()
@@ -2,11 +2,9 @@
2
2
  import { computed } from 'vue'
3
3
  import FieldRenderer from './Renderer.vue'
4
4
  import FieldDeadRefNote from './DeadRefNote.vue'
5
- import { isFieldVisible } from '../../../../fields/app/utils/condition'
5
+ import { isFieldVisible } from '@michaelthielemann/kestrel-core/client'
6
+ import type { FieldDef, LayoutNode, LayoutTrack, Localized } from '@michaelthielemann/kestrel-core'
6
7
  import { resolveLocalized } from '../../utils/localized'
7
- import type { FieldDef, Localized } from '../../../../core/server/utils/defineCollection'
8
- import type { LayoutNode, LayoutTrack } from '../../../../core/server/utils/field-layout'
9
-
10
8
  // The ONE shared field-list renderer, reused by every field-list surface (collection page fields, block
11
9
  // fields, repeater sub-fields). A FRAGMENT (no wrapper root) so its rows/groups drop straight into the
12
10
  // caller's existing gapped flex column — the per-context vertical rhythm is preserved. Imports are
@@ -6,7 +6,7 @@ import UiTextInput from '../ui/TextInput.vue'
6
6
  import LinkInternalPicker from './LinkInternalPicker.vue'
7
7
  import { useLinkField } from '../../composables/useLinkField'
8
8
  import type { FieldComponentProps } from '../../utils/field-component'
9
- import type { FieldOf, LinkType, LinkValue } from '../../../../core/server/utils/defineCollection'
9
+ import type { FieldOf, LinkType, LinkValue } from '@michaelthielemann/kestrel-core'
10
10
 
11
11
  const ALL: LinkType[] = ['external', 'email', 'tel', 'internal']
12
12
  const TYPE_KEYS: Record<LinkType, string> = {
@@ -4,7 +4,7 @@ import UiSelect from '../ui/Select.vue'
4
4
  import UiCombobox from '../ui/Combobox.vue'
5
5
  import { useRecordOptions } from '../../composables/useRecordOptions'
6
6
  import { resolveLocalized } from '../../utils/localized'
7
- import type { SerializedCollection } from '../../../../core/server/utils/serialize-collection'
7
+ import type { SerializedCollection } from '@michaelthielemann/kestrel-core'
8
8
 
9
9
  const { t, lang } = useT()
10
10
 
@@ -85,8 +85,8 @@ const { options, selected, loading, onSearch } = useRecordOptions(coll, ids, toR
85
85
  </template>
86
86
 
87
87
  <style lang="scss">
88
- // The internal arm stacks two block controls (collection select + record combobox) plus an error line;
89
- // without this they touched. Matches the `--space-1` rhythm the hash/label rows already use.
88
+ // The internal arm stacks two block controls (collection select + record combobox) plus an error line.
89
+ // Matches the `--space-1` rhythm the hash/label rows already use.
90
90
  .ui-link-internal {
91
91
  display: flex;
92
92
  flex-direction: column;
@@ -2,9 +2,9 @@
2
2
  import { computed } from 'vue'
3
3
  import UiField from '../ui/Field.vue'
4
4
  import UiNumberInput from '../ui/NumberInput.vue'
5
- import { fieldConstraints } from '../../../../fields/app/utils/field-meta'
5
+ import { fieldConstraints } from '@michaelthielemann/kestrel-fields/client'
6
6
  import type { FieldComponentProps } from '../../utils/field-component'
7
- import type { FieldOf } from '../../../../core/server/utils/defineCollection'
7
+ import type { FieldOf } from '@michaelthielemann/kestrel-core'
8
8
 
9
9
  const props = defineProps<FieldComponentProps>()
10
10
  const model = defineModel<number | null>()
@@ -4,7 +4,7 @@ import UiField from '../ui/Field.vue'
4
4
  import UiCombobox from '../ui/Combobox.vue'
5
5
  import { useRecordOptions } from '../../composables/useRecordOptions'
6
6
  import type { FieldComponentProps } from '../../utils/field-component'
7
- import type { FieldOf } from '../../../../core/server/utils/defineCollection'
7
+ import type { FieldOf } from '@michaelthielemann/kestrel-core'
8
8
 
9
9
  const props = defineProps<FieldComponentProps>()
10
10
  const model = defineModel<number | number[] | null>()
@@ -5,9 +5,7 @@ import FieldLayout from './Layout.vue'
5
5
  import { useRepeater } from '../../composables/useRepeater'
6
6
  import { useFieldA11y } from '../../utils/useFieldA11y'
7
7
  import type { FieldComponentProps } from '../../utils/field-component'
8
- import type { FieldDef, FieldOf } from '../../../../core/server/utils/defineCollection'
9
- import type { LayoutNode } from '../../../../core/server/utils/field-layout'
10
-
8
+ import type { FieldDef, FieldOf, LayoutNode } from '@michaelthielemann/kestrel-core'
11
9
  const props = defineProps<FieldComponentProps>()
12
10
  const model = defineModel<Record<string, unknown>[] | null>()
13
11
 
@@ -1,9 +1,8 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
- import { slugify } from '../../../../core/app/utils/slugify'
3
+ import { slugify } from '@michaelthielemann/kestrel-core/client'
4
+ import type { FieldOf } from '@michaelthielemann/kestrel-core'
4
5
  import type { FieldComponentProps } from '../../utils/field-component'
5
- import type { FieldOf } from '../../../../core/server/utils/defineCollection'
6
-
7
6
  // Editor widget for the `slug` field type. Shows the (display-only) `prefix` before an editable slug input,
8
7
  // and normalizes the value to a real slug on blur. Leaving it blank is fine — the server auto-generates it
9
8
  // from `options.from` (e.g. the title) on save. `options.from`/`prefix` come from the field def.
@@ -3,7 +3,7 @@ import { computed } from 'vue'
3
3
  import UiField from '../ui/Field.vue'
4
4
  import UiTextInput from '../ui/TextInput.vue'
5
5
  import UiTextarea from '../ui/Textarea.vue'
6
- import { fieldConstraints } from '../../../../fields/app/utils/field-meta'
6
+ import { fieldConstraints } from '@michaelthielemann/kestrel-fields/client'
7
7
  import type { FieldComponentProps } from '../../utils/field-component'
8
8
 
9
9
  const props = defineProps<FieldComponentProps>()
@@ -8,7 +8,7 @@ import { Superscript } from '@tiptap/extension-superscript'
8
8
  import { TextAlign } from '@tiptap/extension-text-align'
9
9
  import RichtextToolbar from './RichtextToolbar.vue'
10
10
  import { RichtextSpanClass, RichtextBlockClass } from '../../utils/richtext-preserve-class'
11
- import { RICHTEXT_LINK_SCHEME } from '../../../../fields/app/utils/richtext-links'
11
+ import { RICHTEXT_LINK_SCHEME } from '@michaelthielemann/kestrel-core/client'
12
12
 
13
13
  const props = withDefaults(
14
14
  defineProps<{
@@ -7,7 +7,7 @@ import UiSelect from './Select.vue'
7
7
  import UiTextInput from './TextInput.vue'
8
8
  import LinkInternalPicker from '../field/LinkInternalPicker.vue'
9
9
  import type { IconName } from '../../utils/icons'
10
- import { richtextLinkHref, parseRichtextLinkHref } from '../../../../fields/app/utils/richtext-links'
10
+ import { richtextLinkHref, parseRichtextLinkHref } from '@michaelthielemann/kestrel-core/client'
11
11
 
12
12
  const props = defineProps<{ editor: Editor | undefined; locale?: string; disabled?: boolean }>()
13
13
 
@@ -236,8 +236,6 @@ function applyInternalLink() {
236
236
  align-items: center;
237
237
  }
238
238
 
239
- // Active toggle: a calm neutral fill with the accent carried only by the icon — matching the
240
- // calmed active-nav treatment, instead of a solid-indigo button per active mark.
241
239
  &__group .ui-button.rt-on {
242
240
  background: var(--color-active, var(--color-surface-2));
243
241
  color: var(--color-text);
@@ -1,7 +1,7 @@
1
1
  import { ref, computed, watch } from 'vue'
2
2
  import type { Ref } from 'vue'
3
3
  import { useEchoGuard } from './useEchoGuard'
4
- import type { LinkValue, LinkType } from '../../../core/server/utils/defineCollection'
4
+ import type { LinkValue, LinkType } from '@michaelthielemann/kestrel-core'
5
5
 
6
6
  export function useLinkField(
7
7
  model: Ref<LinkValue | null | undefined>,
@@ -1,6 +1,6 @@
1
1
  import { ref } from 'vue'
2
2
  import type { Ref } from 'vue'
3
- import type { FieldDef } from '../../../core/server/utils/defineCollection'
3
+ import type { FieldDef } from '@michaelthielemann/kestrel-core'
4
4
  import { reorder } from '../utils/reorder'
5
5
  import { useEchoGuard } from './useEchoGuard'
6
6
 
@@ -23,11 +23,9 @@ export const de: Catalog = {
23
23
  'a11y.rowActions': 'Aktionen',
24
24
  'lang.label': 'Sprache',
25
25
 
26
- // account menu (rail foot)
27
26
  'account.label': 'Konto',
28
27
  'account.name': 'Admin',
29
28
 
30
- // text input (password reveal)
31
29
  'input.showPassword': 'Passwort anzeigen',
32
30
  'input.hidePassword': 'Passwort verbergen',
33
31
 
@@ -53,6 +51,8 @@ export const de: Catalog = {
53
51
  'editor.fixBlockContent': 'Einige Block-Inhalte sind ungültig. Prüfe die markierten Block-Felder.',
54
52
  'editor.saveConflict': 'Das steht im Konflikt mit einem vorhandenen Datensatz.',
55
53
  'editor.saveFailed': 'Speichern fehlgeschlagen.',
54
+ 'editor.quarantined.title': 'Datensatz in Quarantäne',
55
+ 'editor.quarantined.desc': 'Dieser Datensatz entspricht nicht mehr dem Schema seiner Collection und wird schreibgeschützt angezeigt. Er kann erst bearbeitet oder gespeichert werden, wenn die zugrunde liegenden Daten korrigiert sind.',
56
56
  'toast.saved': 'Gespeichert',
57
57
  'toast.deleted': 'Gelöscht',
58
58
  'toast.duplicated': 'Dupliziert',
@@ -104,7 +104,9 @@ export const de: Catalog = {
104
104
  'list.result': '{total} Ergebnis',
105
105
  'list.results': '{total} Ergebnisse',
106
106
  'list.loadError': 'Diese Collection konnte nicht geladen werden.',
107
- // Zeilenauswahl + Sammelaktionen
107
+ 'list.quarantined': 'In Quarantäne',
108
+ 'list.quarantinedOne': '{n} Datensatz in Quarantäne',
109
+ 'list.quarantinedCount': '{n} Datensätze in Quarantäne',
108
110
  'list.selectAll': 'Alle Zeilen auf dieser Seite auswählen',
109
111
  'list.selectRow': '{name} auswählen',
110
112
  'list.selected': '{n} ausgewählt',
@@ -120,6 +122,8 @@ export const de: Catalog = {
120
122
  'list.deleteRefsUnverified': 'Verweise konnten nicht geprüft werden — einige Datensätze könnten mit einem defekten Verweis zurückbleiben. Mit Vorsicht fortfahren.',
121
123
  'list.opFailed': 'Die Aktion konnte nicht abgeschlossen werden.',
122
124
  'list.refCheckFailed': 'Verweise konnten nicht geprüft werden.',
125
+ 'list.actionConfirm': '"{name}" für {n} Datensatz/-sätze ausführen?',
126
+ 'list.actionDone': '{name} ausgeführt',
123
127
 
124
128
  'preview.ariaLabel': 'Live-Vorschau',
125
129
  'preview.label': 'Vorschau',
@@ -222,7 +226,6 @@ export const de: Catalog = {
222
226
  'blocks.fieldsLabel': 'Block-Felder',
223
227
  'blocks.treeLabel': 'Block-Struktur',
224
228
 
225
- // dead references (derived warnings)
226
229
  'deadRefs.listWarning': 'Verweist auf einen gelöschten oder unveröffentlichten Datensatz',
227
230
  'deadRefs.blockBadge': 'Defekter Verweis',
228
231
  'deadRefs.fieldNote': 'Verweist auf einen gelöschten oder unveröffentlichten Datensatz.',
@@ -247,7 +250,6 @@ export const de: Catalog = {
247
250
  'media.title': 'Medien',
248
251
  'media.picker.titleSingle': 'Datei auswählen',
249
252
  'media.picker.titleMultiple': 'Medien auswählen',
250
- // media — right-click context menu
251
253
  'media.menu.cut': 'Ausschneiden',
252
254
  'media.menu.copy': 'Kopieren',
253
255
  'media.menu.paste': 'Einfügen',
@@ -327,7 +329,6 @@ export const de: Catalog = {
327
329
  'mediaViewer.aiNote': 'Hinweis zur Kennzeichnung',
328
330
  'mediaViewer.aiNoteHint': 'Freitext, z. B. das verwendete Werkzeug. Beim Upload gefundene KI-Signale werden vorausgefüllt — nur Indizien, kein geprüfter Nachweis.',
329
331
 
330
- // richtext toolbar
331
332
  'richtext.bold': 'Fett',
332
333
  'richtext.italic': 'Kursiv',
333
334
  'richtext.underline': 'Unterstrichen',
@@ -362,7 +363,6 @@ export const de: Catalog = {
362
363
  'richtext.linkUrl': 'Link-URL',
363
364
  'richtext.apply': 'Übernehmen',
364
365
 
365
- // media toolbar
366
366
  'mediaToolbar.searchPlaceholder': 'Suchen…',
367
367
  'mediaToolbar.searchAriaLabel': 'Medien durchsuchen',
368
368
  'mediaToolbar.viewGrid': 'Raster',
@@ -4,7 +4,6 @@ import type { Catalog } from '../composables/useT'
4
4
  // carry `{name}` placeholders interpolated by `useT().t`. Content (collection data) is NOT translated
5
5
  // here — only the dashboard chrome. Keep `en` the complete set; other catalogs may be partial.
6
6
  export const en: Catalog = {
7
- // common / shared
8
7
  'common.new': 'New {label}',
9
8
  'common.save': 'Save',
10
9
  'common.publish': 'Publish',
@@ -14,7 +13,6 @@ export const en: Catalog = {
14
13
  'common.close': 'Close',
15
14
  'common.retry': 'Retry',
16
15
 
17
- // navigation rail + shell
18
16
  'nav.dashboard': 'Dashboard',
19
17
  'nav.signOut': 'Sign out',
20
18
  'theme.dark': 'Dark mode',
@@ -27,21 +25,17 @@ export const en: Catalog = {
27
25
  'a11y.rowActions': 'Actions',
28
26
  'lang.label': 'Language',
29
27
 
30
- // account menu (rail foot)
31
28
  'account.label': 'Account',
32
29
  'account.name': 'Admin',
33
30
 
34
- // text input (password reveal)
35
31
  'input.showPassword': 'Show password',
36
32
  'input.hidePassword': 'Hide password',
37
33
 
38
- // login
39
34
  'login.signIn': 'Sign in',
40
35
  'login.password': 'Password',
41
36
  'login.invalid': 'Invalid credentials',
42
37
  'login.error': 'Something went wrong — please try again',
43
38
 
44
- // dashboard
45
39
  'dash.title': 'Dashboard',
46
40
  'dash.lede': 'Choose a collection to manage its content.',
47
41
  'dash.empty.title': 'No collections yet',
@@ -49,10 +43,8 @@ export const en: Catalog = {
49
43
  'dash.mode.singleton': 'Singleton',
50
44
  'dash.mode.collection': 'Collection',
51
45
 
52
- // collection (list page wrapper)
53
46
  'collection.unknown': 'Unknown collection: {name}',
54
47
 
55
- // record editor page + toasts
56
48
  'editor.back': '{collection}',
57
49
  'editor.newRecord': 'New {collection}',
58
50
  'editor.editRecord': 'Edit {collection} #{id}',
@@ -61,6 +53,8 @@ export const en: Catalog = {
61
53
  'editor.fixBlockContent': 'Some block content is invalid. Check the highlighted block fields.',
62
54
  'editor.saveConflict': 'This conflicts with an existing record.',
63
55
  'editor.saveFailed': 'Save failed.',
56
+ 'editor.quarantined.title': 'Record quarantined',
57
+ 'editor.quarantined.desc': 'This record no longer matches its collection’s schema and is shown read-only. It cannot be edited or saved until the underlying data is fixed.',
64
58
  'toast.saved': 'Saved',
65
59
  'toast.deleted': 'Deleted',
66
60
  'toast.duplicated': 'Duplicated',
@@ -69,7 +63,6 @@ export const en: Catalog = {
69
63
  'toast.region': 'Notifications',
70
64
  'toast.dismiss': 'Dismiss',
71
65
 
72
- // collection list
73
66
  'list.translations': 'Translations',
74
67
  'list.deadRefs': 'Refs',
75
68
  'list.filter': 'Filter',
@@ -113,7 +106,9 @@ export const en: Catalog = {
113
106
  'list.result': '{total} result',
114
107
  'list.results': '{total} results',
115
108
  'list.loadError': "Couldn't load this collection.",
116
- // row selection + bulk actions
109
+ 'list.quarantined': 'Quarantined',
110
+ 'list.quarantinedOne': '{n} quarantined record',
111
+ 'list.quarantinedCount': '{n} quarantined records',
117
112
  'list.selectAll': 'Select all rows on this page',
118
113
  'list.selectRow': 'Select {name}',
119
114
  'list.selected': '{n} selected',
@@ -129,8 +124,9 @@ export const en: Catalog = {
129
124
  'list.deleteRefsUnverified': 'References could not be verified — some records may be left with a broken link. Proceed with caution.',
130
125
  'list.opFailed': 'The action could not be completed.',
131
126
  'list.refCheckFailed': 'References could not be checked.',
127
+ 'list.actionConfirm': 'Run "{name}" on {n} record(s)?',
128
+ 'list.actionDone': '{name} done',
132
129
 
133
- // editor preview pane
134
130
  'preview.ariaLabel': 'Live preview',
135
131
  'preview.label': 'Preview',
136
132
  'preview.deviceLabel': 'Preview size',
@@ -142,7 +138,6 @@ export const en: Catalog = {
142
138
  'preview.width': 'Width',
143
139
  'preview.height': 'Height',
144
140
 
145
- // page settings (system fields on pageLike collections)
146
141
  'pageSettings.slugLabel': 'Slug',
147
142
  'pageSettings.slugHint': 'URL path, e.g. /about (blank = auto-generated from the title)',
148
143
  'pageSettings.layoutLabel': 'Layout',
@@ -153,7 +148,6 @@ export const en: Catalog = {
153
148
  'pageSettings.statusDraft': 'Draft',
154
149
  'pageSettings.statusPublished': 'Published',
155
150
 
156
- // editor action bar — live preview + status "Ampel"
157
151
  'editor.openInNewTab': 'Open in new tab',
158
152
  'editor.previewUnsaved': 'Preview unsaved changes in a new tab',
159
153
  'editor.previewFailed': 'Could not open the preview.',
@@ -189,7 +183,6 @@ export const en: Catalog = {
189
183
  'editorStatus.live.draft': 'Draft — not generated. It stays off the live site until published.',
190
184
  'editorStatus.live.updatedAt': 'Last published {time}',
191
185
 
192
- // SEO section + Google preview
193
186
  'seo.sectionLabel': 'SEO',
194
187
  'seo.metaTitle': 'Meta title',
195
188
  'seo.metaDescription': 'Meta description',
@@ -208,7 +201,6 @@ export const en: Catalog = {
208
201
  'seo.keywords': 'Keywords',
209
202
  'seo.keywordsHint': 'Comma-separated topics for this page.',
210
203
 
211
- // locale bar (translations)
212
204
  'localeBar.fieldLabel': 'Locale',
213
205
  'localeBar.groupLabel': 'Content locale',
214
206
  'localeBar.editLocale': 'Edit {loc}',
@@ -216,12 +208,10 @@ export const en: Catalog = {
216
208
  'localeBar.createTranslation': 'Create {loc} translation',
217
209
  'localeBar.copyFailed': "Couldn't copy from {locale}.",
218
210
 
219
- // editor history (undo/redo)
220
211
  'history.label': 'Edit history',
221
212
  'history.undo': 'Undo',
222
213
  'history.redo': 'Redo',
223
214
 
224
- // block editor
225
215
  'blocks.empty': 'No blocks yet.',
226
216
  'blocks.moveUp': 'Move block {n} up',
227
217
  'blocks.moveDown': 'Move block {n} down',
@@ -238,7 +228,6 @@ export const en: Catalog = {
238
228
  'blocks.fieldsLabel': 'Block fields',
239
229
  'blocks.treeLabel': 'Block structure',
240
230
 
241
- // dead references (derived stale-reference warnings)
242
231
  'deadRefs.listWarning': 'Links to a deleted or unpublished record',
243
232
  'deadRefs.blockBadge': 'Broken reference',
244
233
  'deadRefs.fieldNote': 'Points at a deleted or unpublished record.',
@@ -256,16 +245,13 @@ export const en: Catalog = {
256
245
  'refs.reason.unpublished': 'Unpublished',
257
246
  'refs.dashAlert': '{n} broken reference(s) — review',
258
247
 
259
- // field gallery
260
248
  'gallery.title': 'Field gallery',
261
249
  'gallery.lede.before': 'Every implemented field widget, live. The relation and internal-link pickers query ',
262
250
  'gallery.lede.after': ' — create a post or two to see results.',
263
251
 
264
- // media library
265
252
  'media.title': 'Media',
266
253
  'media.picker.titleSingle': 'Select a file',
267
254
  'media.picker.titleMultiple': 'Select media',
268
- // media — right-click context menu
269
255
  'media.menu.cut': 'Cut',
270
256
  'media.menu.copy': 'Copy',
271
257
  'media.menu.paste': 'Paste',
@@ -295,7 +281,6 @@ export const en: Catalog = {
295
281
  'media.selected': 'selected',
296
282
  'media.useSelected': 'Use selected',
297
283
  'media.dropToUpload': 'Drop files to upload',
298
- // media — upload conflict resolution
299
284
  'media.conflicts.title': 'Resolve upload conflicts',
300
285
  'media.conflicts.desc': '{count} file(s) already exist. Choose how to resolve each.',
301
286
  'media.conflicts.applyAll': 'Apply to all:',
@@ -306,20 +291,17 @@ export const en: Catalog = {
306
291
  'media.conflicts.overwrite': 'Overwrite',
307
292
  'media.conflicts.rename': 'Rename',
308
293
  'media.conflicts.skip': 'Skip',
309
- // media — new folder / rename dialogs
310
294
  'media.newFolder': 'New folder',
311
295
  'media.folderName': 'Folder name',
312
296
  'media.folderNamePlaceholder': 'e.g. holiday',
313
297
  'media.rename': 'Rename',
314
298
  'media.newName': 'New name',
315
- // media — delete dialog
316
299
  'media.deleteSummary': 'Delete {files} {filesUnit} and {folders} {foldersUnit} — {size}.',
317
300
  'media.file': 'file',
318
301
  'media.files': 'files',
319
302
  'media.folder': 'folder',
320
303
  'media.folders': 'folders',
321
304
  'media.usageWarning': 'These files are used by published content and links will break:',
322
- // media — move/copy conflict dialog
323
305
  'media.conflictTitleMove': 'Move — conflicts',
324
306
  'media.conflictTitleCopy': 'Copy — conflicts',
325
307
  'media.conflictItems': '{count} item(s) already exist in "{dest}":',
@@ -329,7 +311,6 @@ export const en: Catalog = {
329
311
  'media.skip': 'Skip',
330
312
  'media.replace': 'Replace',
331
313
  'media.keepBoth': 'Keep both',
332
- // media — table view
333
314
  'media.colName': 'Name',
334
315
  'media.colType': 'Type',
335
316
  'media.colSize': 'Size',
@@ -337,7 +318,6 @@ export const en: Catalog = {
337
318
  'media.typeFolder': 'Folder',
338
319
  'media.parentFolder': 'Go to the parent folder',
339
320
 
340
- // media — viewer
341
321
  'mediaViewer.folder': 'Folder',
342
322
  'mediaViewer.uploaded': 'Uploaded',
343
323
  'mediaViewer.alt': 'Alt text',
@@ -351,7 +331,6 @@ export const en: Catalog = {
351
331
  'mediaViewer.aiNote': 'Disclosure note',
352
332
  'mediaViewer.aiNoteHint': 'Free text, e.g. the tool used. Pre-filled with any AI signals found in the file at upload — evidence only, not a verified claim.',
353
333
 
354
- // richtext toolbar
355
334
  'richtext.bold': 'Bold',
356
335
  'richtext.italic': 'Italic',
357
336
  'richtext.underline': 'Underline',
@@ -386,7 +365,6 @@ export const en: Catalog = {
386
365
  'richtext.linkUrl': 'Link URL',
387
366
  'richtext.apply': 'Apply',
388
367
 
389
- // media toolbar
390
368
  'mediaToolbar.searchPlaceholder': 'Search…',
391
369
  'mediaToolbar.searchAriaLabel': 'Search media',
392
370
  'mediaToolbar.viewGrid': 'Grid',
@@ -395,18 +373,14 @@ export const en: Catalog = {
395
373
  'mediaToolbar.upload': 'Upload',
396
374
  'mediaToolbar.newFolder': 'New folder',
397
375
 
398
- // media path bar
399
376
  'mediaPath.navAriaLabel': 'Path',
400
377
  'mediaPath.editAriaLabel': 'Edit path',
401
378
  'mediaPath.inputAriaLabel': 'Enter path',
402
379
 
403
- // collections nav
404
380
  'nav.collections': 'Collections',
405
381
 
406
- // field widgets — datetime
407
382
  'field.datetime.range_start': 'Start',
408
383
  'field.datetime.range_end': 'End',
409
- // field widgets — link
410
384
  'field.link.type_internal': 'Internal',
411
385
  'field.link.type_url': 'URL',
412
386
  'field.link.type_email': 'Email',
@@ -415,14 +389,11 @@ export const en: Catalog = {
415
389
  'field.link.url_placeholder': 'https://…',
416
390
  'field.link.label_placeholder': 'Link text (optional)',
417
391
  'field.link.hash_placeholder': 'Anchor (optional, e.g. section-id)',
418
- // field widgets — relation
419
392
  'field.relation.placeholder': 'Search…',
420
- // field widgets — internal-link picker
421
393
  'field.linkPicker.loadError': 'Could not load collections.',
422
394
  'field.linkPicker.chooseCollection': 'Choose a collection…',
423
395
  'field.linkPicker.collectionLabel': 'Collection',
424
396
  'field.linkPicker.searchRecords': 'Search records…',
425
- // field widgets — repeater
426
397
  'field.repeater.moved': 'Moved item to position {n} of {total}',
427
398
  'field.repeater.removed': 'Item {n} removed, {remaining} remaining',
428
399
  'field.repeater.duplicated': 'Duplicated item {n}',
@@ -435,7 +406,6 @@ export const en: Catalog = {
435
406
  'field.repeater.remove_label': 'Remove item {n}',
436
407
  'field.repeater.empty': 'No items yet.',
437
408
  'field.repeater.add': 'Add item',
438
- // field widgets — media
439
409
  'field.media.empty': 'No media selected.',
440
410
  'field.media.add': 'Add media',
441
411
  'field.media.replace': 'Replace',
@@ -446,7 +416,6 @@ export const en: Catalog = {
446
416
  'field.media.move_later': 'Move {name} later',
447
417
  'field.media.moved': 'Moved {name} to position {pos} of {total}',
448
418
 
449
- // combobox
450
419
  'combobox.moved': 'Moved {label} to position {pos} of {total}',
451
420
  'combobox.move_earlier': 'Move {label} earlier',
452
421
  'combobox.move_later': 'Move {label} later',
@@ -456,7 +425,6 @@ export const en: Catalog = {
456
425
  'combobox.loading': 'Loading…',
457
426
  'combobox.no_results': 'No results',
458
427
 
459
- // date pickers
460
428
  'datePicker.openCalendar': 'Open calendar',
461
429
  'datePicker.previousMonth': 'Previous month',
462
430
  'datePicker.nextMonth': 'Next month',
@@ -1,4 +1,4 @@
1
- import type { FieldDef } from '../../../core/server/utils/defineCollection'
1
+ import type { FieldDef } from '@michaelthielemann/kestrel-core'
2
2
 
3
3
  /** A record reference: its id plus a human label. Shared by UiCombobox and FieldRelation. */
4
4
  export interface FieldOption { value: number; label: string }
@@ -1,5 +1,5 @@
1
1
  import { defineAsyncComponent, type Component } from 'vue'
2
- import type { FieldType } from '../../../core/server/utils/defineCollection'
2
+ import type { FieldType } from '@michaelthielemann/kestrel-core'
3
3
  import FieldText from '../components/field/Text.vue'
4
4
  import FieldNumber from '../components/field/Number.vue'
5
5
  import FieldBoolean from '../components/field/Boolean.vue'
@@ -3,19 +3,14 @@ export type IconName =
3
3
  | 'copy' | 'trash' | 'x' | 'plus' | 'pencil' | 'check'
4
4
  | 'home' | 'file-text' | 'folder' | 'folder-plus' | 'panel-left-close' | 'panel-left-open' | 'log-out'
5
5
  | 'sun' | 'moon' | 'calendar' | 'upload' | 'layout-grid' | 'table'
6
- // collection icons + list toolbar
7
6
  | 'settings' | 'image' | 'newspaper' | 'columns' | 'filter' | 'search' | 'sliders'
8
- // richtext toolbar
9
7
  | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'code' | 'square-code' | 'highlighter'
10
8
  | 'subscript' | 'superscript' | 'list' | 'list-ordered' | 'quote' | 'minus' | 'message-square'
11
9
  | 'align-left' | 'align-center' | 'align-right' | 'align-justify'
12
10
  | 'eraser' | 'undo' | 'redo' | 'link' | 'link-2'
13
- | 'external-link' | 'triangle-alert'
14
- // password reveal
11
+ | 'external-link' | 'triangle-alert' | 'globe'
15
12
  | 'eye' | 'eye-off'
16
- // preview device widths + reload
17
13
  | 'monitor' | 'tablet' | 'smartphone' | 'rotate-cw'
18
- // block-type tiles
19
14
  | 'clock' | 'user'
20
15
 
21
16
  export const icons: Record<IconName, string> = {
@@ -74,6 +69,7 @@ export const icons: Record<IconName, string> = {
74
69
  'link': '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
75
70
  'link-2': '<path d="M9 17H7A5 5 0 0 1 7 7h2"/><path d="M15 7h2a5 5 0 1 1 0 10h-2"/><line x1="8" x2="16" y1="12" y2="12"/>',
76
71
  'external-link': '<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h6"/>',
72
+ 'globe': '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',
77
73
  'triangle-alert': '<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
78
74
  'settings': '<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>',
79
75
  'image': '<rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>',
@@ -1,4 +1,4 @@
1
- import type { Localized } from '../../../core/server/utils/defineCollection'
1
+ import type { Localized } from '@michaelthielemann/kestrel-core'
2
2
 
3
3
  /**
4
4
  * Resolve a (possibly localized) label for the active admin language. A plain string is returned as-is
package/nuxt.config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import kestrel from './kestrel.config'
2
- import { layerKestrelOption } from './layers/core/server/utils/kestrel-config'
2
+ import { layerKestrelOption } from '@michaelthielemann/kestrel-core'
3
3
 
4
4
  // Silence known-harmless, un-actionable THIRD-PARTY build noise (output unaffected — applied to both the
5
5
  // Vite client and the Nitro server Rollup passes). Everything else still surfaces — crucially, any