@lupinum/ginko-content 0.2.1 → 0.3.0-rc.2

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 (525) hide show
  1. package/README.md +4 -4
  2. package/compatibility.json +11 -11
  3. package/dist/cli.mjs +90 -16
  4. package/dist/cms-contract/asset-bytes.d.ts +10 -0
  5. package/dist/cms-contract/asset-bytes.js +266 -0
  6. package/dist/cms-contract/build.d.ts +9 -38
  7. package/dist/cms-contract/build.js +313 -437
  8. package/dist/cms-contract/hash.d.ts +16 -0
  9. package/dist/cms-contract/hash.js +248 -0
  10. package/dist/cms-contract/index.d.ts +11 -4
  11. package/dist/cms-contract/index.js +29 -3
  12. package/dist/cms-contract/limits.d.ts +14 -0
  13. package/dist/cms-contract/limits.js +13 -0
  14. package/dist/cms-contract/provider-wire.d.ts +1074 -0
  15. package/dist/cms-contract/provider-wire.js +303 -0
  16. package/dist/cms-contract/render-policy.d.ts +22 -0
  17. package/dist/cms-contract/render-policy.js +319 -0
  18. package/dist/cms-contract/types.d.ts +77 -164
  19. package/dist/cms-contract/validate.d.ts +3 -0
  20. package/dist/cms-contract/validate.js +274 -0
  21. package/dist/config.d.mts +2 -2
  22. package/dist/config.mjs +3 -3
  23. package/dist/core/cache.d.ts +7 -7
  24. package/dist/core/content/graph.d.ts +11 -4
  25. package/dist/core/content/graph.js +73 -35
  26. package/dist/core/content/path.d.ts +0 -1
  27. package/dist/core/content/path.js +0 -12
  28. package/dist/core/content/snapshot.d.ts +11 -1
  29. package/dist/core/content/snapshot.js +5 -58
  30. package/dist/core/content/structural.d.ts +7 -0
  31. package/dist/core/content/structural.js +1 -0
  32. package/dist/core/errors.d.ts +1 -1
  33. package/dist/core/json-value.d.ts +41 -0
  34. package/dist/core/json-value.js +99 -0
  35. package/dist/core/markdown/tree.js +5 -3
  36. package/dist/core/provider-errors.d.ts +1 -1
  37. package/dist/core/provider-errors.js +2 -1
  38. package/dist/core/query/execute.js +59 -18
  39. package/dist/core/query/lower.js +3 -1
  40. package/dist/core/query/operators.d.ts +2 -1
  41. package/dist/core/query/operators.js +2 -1
  42. package/dist/core/query/params.js +7 -3
  43. package/dist/core/query/plan.d.ts +52 -1
  44. package/dist/core/references/schema.js +1 -1
  45. package/dist/core/visibility.d.ts +64 -0
  46. package/dist/core/visibility.js +18 -0
  47. package/dist/features/agent/agent-markdown.js +3 -8
  48. package/dist/features/agent/walker.js +24 -11
  49. package/dist/features/collections/resolve.js +1 -1
  50. package/dist/features/localization/links.js +1 -1
  51. package/dist/features/localization/locale-policy.d.ts +95 -0
  52. package/dist/features/localization/locale-policy.js +128 -0
  53. package/dist/features/localization/path.d.ts +14 -2
  54. package/dist/features/localization/path.js +25 -4
  55. package/dist/features/localization/results.d.ts +81 -2
  56. package/dist/features/localization/results.js +112 -8
  57. package/dist/features/localization/route-projector.d.ts +147 -0
  58. package/dist/features/localization/route-projector.js +150 -0
  59. package/dist/features/localization/translated-slugs.js +2 -2
  60. package/dist/features/navigation/build.js +1 -1
  61. package/dist/features/navigation/query.d.ts +9 -4
  62. package/dist/features/navigation/query.js +1 -8
  63. package/dist/features/navigation/resolve.d.ts +3 -5
  64. package/dist/features/navigation/resolve.js +3 -4
  65. package/dist/features/query/backlinks.js +5 -6
  66. package/dist/features/query/context.d.ts +8 -0
  67. package/dist/features/query/documents.js +3 -4
  68. package/dist/features/query/localized-docs.d.ts +2 -6
  69. package/dist/features/query/localized-docs.js +10 -11
  70. package/dist/features/query/navigation.d.ts +20 -11
  71. package/dist/features/query/navigation.js +24 -11
  72. package/dist/features/query/pagination.d.ts +6 -0
  73. package/dist/features/query/pagination.js +61 -18
  74. package/dist/features/query/populate.js +1 -1
  75. package/dist/features/query/responses.d.ts +7 -0
  76. package/dist/features/query/responses.js +13 -0
  77. package/dist/features/query/routes.js +11 -3
  78. package/dist/features/query/unified.d.ts +23 -29
  79. package/dist/features/query/unified.js +5 -9
  80. package/dist/features/search/navigation.js +1 -2
  81. package/dist/features/search/records.d.ts +9 -0
  82. package/dist/features/search/records.js +18 -0
  83. package/dist/features/search/snippet.d.ts +6 -0
  84. package/dist/features/search/snippet.js +52 -0
  85. package/dist/features/sitemap/counts.d.ts +32 -0
  86. package/dist/features/sitemap/counts.js +50 -0
  87. package/dist/features/sitemap/query.d.ts +28 -1
  88. package/dist/features/sitemap/query.js +82 -46
  89. package/dist/features/validation/links.d.ts +16 -0
  90. package/dist/features/validation/links.js +171 -0
  91. package/dist/features/validation/report.d.ts +14 -0
  92. package/dist/features/validation/report.js +10 -0
  93. package/dist/integrations/nitro/build.d.ts +57 -0
  94. package/dist/integrations/nitro/build.js +245 -0
  95. package/dist/integrations/nitro/ingest.js +10 -6
  96. package/dist/integrations/nitro/storage.js +1 -1
  97. package/dist/integrations/vue/markdown-refs.js +1 -1
  98. package/dist/module.d.mts +112 -75
  99. package/dist/module.json +2 -2
  100. package/dist/module.mjs +391 -415
  101. package/dist/parsers/markdown.js +9 -3
  102. package/dist/parsers/path-meta.js +9 -6
  103. package/dist/parsers/yaml.js +15 -0
  104. package/dist/portability/assets.d.ts +17 -0
  105. package/dist/portability/assets.js +190 -0
  106. package/dist/portability/documents.d.ts +6 -0
  107. package/dist/portability/documents.js +307 -0
  108. package/dist/portability/errors.d.ts +26 -0
  109. package/dist/portability/errors.js +22 -0
  110. package/dist/portability/index.d.ts +13 -0
  111. package/dist/portability/index.js +32 -0
  112. package/dist/portability/json.d.ts +2 -0
  113. package/dist/portability/json.js +97 -0
  114. package/dist/portability/manifest.d.ts +16 -0
  115. package/dist/portability/manifest.js +72 -0
  116. package/dist/portability/mdc.d.ts +31 -0
  117. package/dist/portability/mdc.js +92 -0
  118. package/dist/portability/model.d.ts +70 -0
  119. package/dist/portability/model.js +0 -0
  120. package/dist/portability/references.d.ts +4 -0
  121. package/dist/portability/references.js +61 -0
  122. package/dist/portability/segments.d.ts +2 -0
  123. package/dist/portability/segments.js +45 -0
  124. package/dist/portability/semantic-equality.d.ts +3 -0
  125. package/dist/portability/semantic-equality.js +12 -0
  126. package/dist/portability/yaml.d.ts +3 -0
  127. package/dist/portability/yaml.js +53 -0
  128. package/dist/portability-node/index.d.ts +3 -0
  129. package/dist/portability-node/index.js +9 -0
  130. package/dist/portability-node/read-directory.d.ts +23 -0
  131. package/dist/portability-node/read-directory.js +320 -0
  132. package/dist/portability-node/safe-path.d.ts +3 -0
  133. package/dist/portability-node/safe-path.js +29 -0
  134. package/dist/portability-node/streams.d.ts +2 -0
  135. package/dist/portability-node/streams.js +26 -0
  136. package/dist/portability-node/write-directory.d.ts +11 -0
  137. package/dist/portability-node/write-directory.js +92 -0
  138. package/dist/public/agent-paths.d.ts +2 -0
  139. package/dist/public/agent-paths.js +5 -0
  140. package/dist/public/agent-registry.d.ts +4 -0
  141. package/dist/public/agent-registry.js +11 -0
  142. package/dist/public/agent.d.ts +2 -2
  143. package/dist/public/agent.js +6 -14
  144. package/dist/public/client.d.ts +13 -11
  145. package/dist/public/client.js +6 -18
  146. package/dist/public/data-source.d.ts +92 -0
  147. package/dist/public/data-source.js +16 -0
  148. package/dist/public/provider-binder.d.ts +7 -0
  149. package/dist/public/provider-binder.js +324 -0
  150. package/dist/public/provider-errors.js +1 -1
  151. package/dist/public/provider-query.d.ts +26 -25
  152. package/dist/public/provider-query.js +1 -1
  153. package/dist/public/provider.d.ts +63 -30
  154. package/dist/public/provider.js +4 -2
  155. package/dist/public/server.d.ts +4 -7
  156. package/dist/public/server.js +3 -8
  157. package/dist/runtime/app/components/ContentRenderer.d.vue.ts +2 -2
  158. package/dist/runtime/app/components/ContentRenderer.vue.d.ts +2 -2
  159. package/dist/runtime/app/components/ContentRendererInline.d.vue.ts +1 -1
  160. package/dist/runtime/app/components/ContentRendererInline.vue.d.ts +1 -1
  161. package/dist/runtime/app/components/Prose/ProsePre.d.vue.ts +2 -2
  162. package/dist/runtime/app/components/Prose/ProsePre.vue.d.ts +2 -2
  163. package/dist/runtime/app/components/internal/ContentRendererMarkdown.d.vue.ts +1 -1
  164. package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue +10 -6
  165. package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue.d.ts +1 -1
  166. package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +19 -5
  167. package/dist/runtime/app/components/internal/MarkdownRenderer.js +9 -1
  168. package/dist/runtime/app/composables/content-i18n.d.ts +1 -3
  169. package/dist/runtime/app/composables/content-i18n.js +1 -1
  170. package/dist/runtime/app/composables/locale.js +1 -1
  171. package/dist/runtime/app/composables/preview.d.ts +1 -1
  172. package/dist/runtime/app/composables/preview.js +12 -29
  173. package/dist/runtime/app/composables/query-api.d.ts +13 -17
  174. package/dist/runtime/app/composables/query-api.js +14 -13
  175. package/dist/runtime/app/composables/search.d.ts +26 -19
  176. package/dist/runtime/app/composables/search.js +59 -66
  177. package/dist/runtime/app/composables/toc.d.ts +0 -2
  178. package/dist/runtime/app/composables/toc.js +0 -8
  179. package/dist/runtime/app/composables/use-content-page.d.ts +21 -19
  180. package/dist/runtime/app/composables/use-content-page.js +46 -97
  181. package/dist/runtime/app/composables/utils.d.ts +2 -1
  182. package/dist/runtime/app/composables/utils.js +1 -1
  183. package/dist/runtime/app/pagefind-client.d.ts +32 -0
  184. package/dist/runtime/app/pagefind-client.js +100 -0
  185. package/dist/runtime/markdown/plugins.js +1 -1
  186. package/dist/runtime/pagefind-manifest.d.ts +8 -0
  187. package/dist/runtime/pagefind-manifest.js +15 -0
  188. package/dist/runtime/server/agent-markdown.d.ts +2 -8
  189. package/dist/runtime/server/agent-markdown.js +94 -56
  190. package/dist/runtime/server/agent-registry.d.ts +7 -0
  191. package/dist/runtime/server/agent-registry.js +10 -0
  192. package/dist/runtime/server/agent-site.js +22 -18
  193. package/dist/runtime/server/api/agent-raw.js +1 -1
  194. package/dist/runtime/server/api/cache.d.ts +41 -4
  195. package/dist/runtime/server/api/cache.js +76 -53
  196. package/dist/runtime/server/api/locales.js +8 -5
  197. package/dist/runtime/server/api/navigation.d.ts +1 -1
  198. package/dist/runtime/server/api/navigation.js +10 -3
  199. package/dist/runtime/server/api/query.js +18 -2
  200. package/dist/runtime/server/api/revalidate.js +3 -15
  201. package/dist/runtime/server/api/search.js +16 -9
  202. package/dist/runtime/server/api/site-data.js +1 -1
  203. package/dist/runtime/server/api/sitemap.js +1 -1
  204. package/dist/runtime/server/cache-adapters.d.ts +0 -9
  205. package/dist/runtime/server/cache-adapters.js +0 -26
  206. package/dist/runtime/server/cache-hints.js +3 -3
  207. package/dist/runtime/server/collection-helpers.js +1 -1
  208. package/dist/runtime/server/index.d.ts +2 -8
  209. package/dist/runtime/server/index.js +2 -11
  210. package/dist/runtime/server/middleware/agent-link-headers.js +2 -2
  211. package/dist/runtime/server/middleware/agent-markdown.js +1 -1
  212. package/dist/runtime/server/navigation-query.js +15 -18
  213. package/dist/runtime/server/pagefind.d.ts +1 -1
  214. package/dist/runtime/server/pagefind.js +53 -24
  215. package/dist/runtime/server/preview.js +1 -1
  216. package/dist/runtime/server/provider-document.d.ts +12 -33
  217. package/dist/runtime/server/provider-document.js +35 -20
  218. package/dist/runtime/server/provider-query-wire.d.ts +6 -8
  219. package/dist/runtime/server/provider-query-wire.js +10 -9
  220. package/dist/runtime/server/provider-query.d.ts +18 -6
  221. package/dist/runtime/server/provider-query.js +147 -18
  222. package/dist/runtime/server/provider-result.d.ts +8 -15
  223. package/dist/runtime/server/provider-result.js +2 -8
  224. package/dist/runtime/server/provider-route-facts.d.ts +9 -0
  225. package/dist/runtime/server/provider-route-facts.js +160 -0
  226. package/dist/runtime/server/providers/filesystem.js +155 -28
  227. package/dist/runtime/server/providers/index.d.ts +1 -0
  228. package/dist/runtime/server/providers/index.js +37 -75
  229. package/dist/runtime/server/query-api.d.ts +13 -18
  230. package/dist/runtime/server/query-api.js +41 -15
  231. package/dist/runtime/server/query-executor.js +24 -13
  232. package/dist/runtime/server/query-http-validation.d.ts +50 -0
  233. package/dist/runtime/server/query-http-validation.js +371 -0
  234. package/dist/runtime/server/runtime-config.js +1 -1
  235. package/dist/runtime/server/search.d.ts +2 -9
  236. package/dist/runtime/server/search.js +18 -103
  237. package/dist/runtime/server/sitemap-provider.d.ts +2 -7
  238. package/dist/runtime/server/sitemap-provider.js +68 -42
  239. package/dist/runtime/server/sitemap.js +2 -2
  240. package/dist/runtime/server/storage-access.js +3 -3
  241. package/dist/runtime/server/storage.js +2 -2
  242. package/dist/runtime/server/validation.d.ts +1 -1
  243. package/dist/runtime/server/validation.js +3 -2
  244. package/dist/runtime/shared/search.d.ts +10 -1
  245. package/dist/runtime/shared/search.js +45 -51
  246. package/dist/runtime/transformers/component-resolver.js +1 -1
  247. package/dist/runtime/transformers/csv/from-csv.js +1 -1
  248. package/dist/runtime/transformers/csv/index.js +1 -1
  249. package/dist/runtime/transformers/define.js +1 -1
  250. package/dist/runtime/transformers/index.js +1 -1
  251. package/dist/runtime/transformers/json.js +1 -1
  252. package/dist/runtime/transformers/markdown.js +1 -1
  253. package/dist/runtime/transformers/path-meta.js +2 -2
  254. package/dist/runtime/transformers/utils.js +1 -1
  255. package/dist/runtime/transformers/yaml.js +1 -1
  256. package/dist/runtime/utils/query.js +1 -1
  257. package/dist/runtime/virtual.d.ts +7 -5
  258. package/dist/storage/cache.d.ts +5 -12
  259. package/dist/storage/cache.js +4 -24
  260. package/dist/storage/content.d.ts +2 -2
  261. package/dist/storage/content.js +17 -11
  262. package/dist/storage/contents.js +7 -17
  263. package/dist/storage/driver.js +2 -2
  264. package/dist/storage/graph.d.ts +35 -0
  265. package/dist/storage/graph.js +57 -2
  266. package/dist/storage/references.js +51 -29
  267. package/dist/storage/snapshot-runtime.js +8 -2
  268. package/dist/storage/validation.d.ts +14 -0
  269. package/dist/storage/validation.js +54 -15
  270. package/dist/testing/data-source-contract.d.ts +6 -0
  271. package/dist/testing/data-source-contract.js +36 -0
  272. package/dist/testing/portability-contract.d.ts +45 -0
  273. package/dist/testing/portability-contract.js +150 -0
  274. package/dist/testing/provider-contract.d.ts +16 -49
  275. package/dist/testing/provider-contract.js +46 -381
  276. package/dist/testing/provider-fixture.d.ts +1 -1
  277. package/dist/testing/provider-fixture.js +100 -284
  278. package/dist/types/api.d.ts +26 -2
  279. package/dist/types/component-policy.d.ts +16 -0
  280. package/dist/types/component-policy.js +0 -0
  281. package/dist/types/config.d.ts +30 -15
  282. package/dist/types/config.js +2 -0
  283. package/dist/types/content.d.ts +12 -14
  284. package/dist/types/fields.d.ts +2 -19
  285. package/dist/types/fields.js +41 -16
  286. package/dist/types/module.d.ts +62 -40
  287. package/dist/types/query-parts/public.d.ts +108 -36
  288. package/dist/types/query-parts/results.d.ts +40 -0
  289. package/dist/types/query-parts/transport.d.ts +14 -2
  290. package/dist/types/runtime.d.ts +6 -0
  291. package/dist/types/search.d.ts +2 -1
  292. package/dist/types/virtual.d.ts +2 -0
  293. package/dist/types.d.mts +1 -1
  294. package/dist/web-types.json +9 -1
  295. package/package.json +43 -29
  296. package/dist/cms-contract/build +0 -1
  297. package/dist/cms-contract/index +0 -1
  298. package/dist/cms-contract/mdc +0 -1
  299. package/dist/cms-contract/path +0 -1
  300. package/dist/cms-contract/schema +0 -1
  301. package/dist/cms-contract/types +0 -1
  302. package/dist/cms-import/index +0 -1
  303. package/dist/cms-import/index.d.ts +0 -21
  304. package/dist/cms-import/index.js +0 -61
  305. package/dist/core/cache +0 -1
  306. package/dist/core/cache-hints +0 -1
  307. package/dist/core/content/collection +0 -1
  308. package/dist/core/content/document +0 -1
  309. package/dist/core/content/graph +0 -1
  310. package/dist/core/content/ignore +0 -1
  311. package/dist/core/content/locale +0 -1
  312. package/dist/core/content/path +0 -1
  313. package/dist/core/content/slug +0 -1
  314. package/dist/core/content/snapshot +0 -1
  315. package/dist/core/content/sources +0 -1
  316. package/dist/core/errors +0 -1
  317. package/dist/core/markdown/tree +0 -1
  318. package/dist/core/provider-errors +0 -1
  319. package/dist/core/query/builder +0 -1
  320. package/dist/core/query/execute +0 -1
  321. package/dist/core/query/filter +0 -1
  322. package/dist/core/query/json +0 -1
  323. package/dist/core/query/json.d.ts +0 -2
  324. package/dist/core/query/json.js +0 -20
  325. package/dist/core/query/lower +0 -1
  326. package/dist/core/query/operators +0 -1
  327. package/dist/core/query/params +0 -1
  328. package/dist/core/query/plan +0 -1
  329. package/dist/core/references/resolve +0 -1
  330. package/dist/core/references/schema +0 -1
  331. package/dist/core/result +0 -1
  332. package/dist/features/agent/agent-markdown +0 -1
  333. package/dist/features/agent/agent-paths +0 -1
  334. package/dist/features/agent/walker +0 -1
  335. package/dist/features/collections/resolve +0 -1
  336. package/dist/features/localization/config +0 -1
  337. package/dist/features/localization/links +0 -1
  338. package/dist/features/localization/path +0 -1
  339. package/dist/features/localization/results +0 -1
  340. package/dist/features/localization/translated-slugs +0 -1
  341. package/dist/features/navigation/build +0 -1
  342. package/dist/features/navigation/canonical +0 -1
  343. package/dist/features/navigation/query +0 -1
  344. package/dist/features/navigation/resolve +0 -1
  345. package/dist/features/navigation/tree +0 -1
  346. package/dist/features/query/backlinks +0 -1
  347. package/dist/features/query/context +0 -1
  348. package/dist/features/query/documents +0 -1
  349. package/dist/features/query/errors +0 -1
  350. package/dist/features/query/handles +0 -1
  351. package/dist/features/query/locale-options +0 -1
  352. package/dist/features/query/localized-docs +0 -1
  353. package/dist/features/query/navigation +0 -1
  354. package/dist/features/query/pagination +0 -1
  355. package/dist/features/query/populate +0 -1
  356. package/dist/features/query/public-limits +0 -1
  357. package/dist/features/query/resolve +0 -1
  358. package/dist/features/query/resolve.d.ts +0 -5
  359. package/dist/features/query/resolve.js +0 -9
  360. package/dist/features/query/responses +0 -1
  361. package/dist/features/query/routes +0 -1
  362. package/dist/features/query/unified +0 -1
  363. package/dist/features/query/variants +0 -1
  364. package/dist/features/query/variants.d.ts +0 -11
  365. package/dist/features/query/variants.js +0 -36
  366. package/dist/features/search/navigation +0 -1
  367. package/dist/features/search/sections +0 -1
  368. package/dist/features/sitemap/query +0 -1
  369. package/dist/integrations/nitro/context +0 -1
  370. package/dist/integrations/nitro/ingest +0 -1
  371. package/dist/integrations/nitro/preview +0 -1
  372. package/dist/integrations/nitro/runtime-config +0 -1
  373. package/dist/integrations/nitro/storage +0 -1
  374. package/dist/integrations/vue/content-components +0 -1
  375. package/dist/integrations/vue/html-tags +0 -1
  376. package/dist/integrations/vue/markdown-refs +0 -1
  377. package/dist/parsers/csv +0 -1
  378. package/dist/parsers/from-csv +0 -1
  379. package/dist/parsers/index +0 -1
  380. package/dist/parsers/json +0 -1
  381. package/dist/parsers/markdown +0 -1
  382. package/dist/parsers/markdown-plugins +0 -1
  383. package/dist/parsers/path-meta +0 -1
  384. package/dist/parsers/reserved +0 -1
  385. package/dist/parsers/utils +0 -1
  386. package/dist/parsers/yaml +0 -1
  387. package/dist/public/agent +0 -1
  388. package/dist/public/client +0 -1
  389. package/dist/public/provider +0 -1
  390. package/dist/public/provider-errors +0 -1
  391. package/dist/public/provider-query +0 -1
  392. package/dist/public/server +0 -1
  393. package/dist/runtime/app/components/internal/MarkdownRenderer +0 -1
  394. package/dist/runtime/app/composables/async-data +0 -1
  395. package/dist/runtime/app/composables/async-data.d.ts +0 -2
  396. package/dist/runtime/app/composables/async-data.js +0 -4
  397. package/dist/runtime/app/composables/content-i18n +0 -1
  398. package/dist/runtime/app/composables/head +0 -1
  399. package/dist/runtime/app/composables/head.d.ts +0 -38
  400. package/dist/runtime/app/composables/head.js +0 -103
  401. package/dist/runtime/app/composables/hot-reload +0 -1
  402. package/dist/runtime/app/composables/locale +0 -1
  403. package/dist/runtime/app/composables/locale-context +0 -1
  404. package/dist/runtime/app/composables/navigation +0 -1
  405. package/dist/runtime/app/composables/navigation.d.ts +0 -3
  406. package/dist/runtime/app/composables/navigation.js +0 -7
  407. package/dist/runtime/app/composables/preview +0 -1
  408. package/dist/runtime/app/composables/query-api +0 -1
  409. package/dist/runtime/app/composables/route +0 -1
  410. package/dist/runtime/app/composables/route.d.ts +0 -11
  411. package/dist/runtime/app/composables/route.js +0 -150
  412. package/dist/runtime/app/composables/runtime +0 -1
  413. package/dist/runtime/app/composables/search +0 -1
  414. package/dist/runtime/app/composables/site-data +0 -1
  415. package/dist/runtime/app/composables/toc +0 -1
  416. package/dist/runtime/app/composables/use-content +0 -1
  417. package/dist/runtime/app/composables/use-content-document +0 -1
  418. package/dist/runtime/app/composables/use-content-document.d.ts +0 -29
  419. package/dist/runtime/app/composables/use-content-document.js +0 -44
  420. package/dist/runtime/app/composables/use-content-list +0 -1
  421. package/dist/runtime/app/composables/use-content-list.d.ts +0 -43
  422. package/dist/runtime/app/composables/use-content-list.js +0 -98
  423. package/dist/runtime/app/composables/use-content-navigation +0 -1
  424. package/dist/runtime/app/composables/use-content-navigation.d.ts +0 -40
  425. package/dist/runtime/app/composables/use-content-navigation.js +0 -102
  426. package/dist/runtime/app/composables/use-content-page +0 -1
  427. package/dist/runtime/app/composables/use-content-shared +0 -1
  428. package/dist/runtime/app/composables/use-content.d.ts +0 -13
  429. package/dist/runtime/app/composables/use-content.js +0 -4
  430. package/dist/runtime/app/composables/useUnwrap +0 -1
  431. package/dist/runtime/app/composables/utils +0 -1
  432. package/dist/runtime/app/pages/content.d.vue.ts +0 -3
  433. package/dist/runtime/app/pages/content.vue +0 -15
  434. package/dist/runtime/app/pages/content.vue.d.ts +0 -3
  435. package/dist/runtime/app/plugins/hot-reload +0 -1
  436. package/dist/runtime/markdown/plugins +0 -1
  437. package/dist/runtime/server/agent-http +0 -1
  438. package/dist/runtime/server/agent-markdown +0 -1
  439. package/dist/runtime/server/agent-site +0 -1
  440. package/dist/runtime/server/api/agent-llms +0 -1
  441. package/dist/runtime/server/api/agent-llms-full +0 -1
  442. package/dist/runtime/server/api/agent-raw +0 -1
  443. package/dist/runtime/server/api/cache +0 -1
  444. package/dist/runtime/server/api/locales +0 -1
  445. package/dist/runtime/server/api/navigation +0 -1
  446. package/dist/runtime/server/api/query +0 -1
  447. package/dist/runtime/server/api/revalidate +0 -1
  448. package/dist/runtime/server/api/search +0 -1
  449. package/dist/runtime/server/api/search-index +0 -1
  450. package/dist/runtime/server/api/site-data +0 -1
  451. package/dist/runtime/server/api/sitemap +0 -1
  452. package/dist/runtime/server/cache-adapter +0 -1
  453. package/dist/runtime/server/cache-adapters +0 -1
  454. package/dist/runtime/server/cache-hints +0 -1
  455. package/dist/runtime/server/collection-helpers +0 -1
  456. package/dist/runtime/server/index +0 -1
  457. package/dist/runtime/server/manifest +0 -1
  458. package/dist/runtime/server/manifest.d.ts +0 -1
  459. package/dist/runtime/server/manifest.js +0 -1
  460. package/dist/runtime/server/middleware/agent-link-headers +0 -1
  461. package/dist/runtime/server/middleware/agent-markdown +0 -1
  462. package/dist/runtime/server/navigation +0 -1
  463. package/dist/runtime/server/navigation-query +0 -1
  464. package/dist/runtime/server/navigation.d.ts +0 -2
  465. package/dist/runtime/server/navigation.js +0 -9
  466. package/dist/runtime/server/pagefind +0 -1
  467. package/dist/runtime/server/plugins/cache +0 -1
  468. package/dist/runtime/server/plugins/sitemap +0 -1
  469. package/dist/runtime/server/preview +0 -1
  470. package/dist/runtime/server/provider-document +0 -1
  471. package/dist/runtime/server/provider-query +0 -1
  472. package/dist/runtime/server/provider-query-wire +0 -1
  473. package/dist/runtime/server/provider-result +0 -1
  474. package/dist/runtime/server/providers/filesystem +0 -1
  475. package/dist/runtime/server/providers/index +0 -1
  476. package/dist/runtime/server/query-api +0 -1
  477. package/dist/runtime/server/query-executor +0 -1
  478. package/dist/runtime/server/runtime-config +0 -1
  479. package/dist/runtime/server/search +0 -1
  480. package/dist/runtime/server/sitemap +0 -1
  481. package/dist/runtime/server/sitemap-provider +0 -1
  482. package/dist/runtime/server/storage +0 -1
  483. package/dist/runtime/server/storage-access +0 -1
  484. package/dist/runtime/server/validation +0 -1
  485. package/dist/runtime/shared/search +0 -1
  486. package/dist/runtime/transformers/component-resolver +0 -1
  487. package/dist/runtime/transformers/csv/from-csv +0 -1
  488. package/dist/runtime/transformers/csv/index +0 -1
  489. package/dist/runtime/transformers/define +0 -1
  490. package/dist/runtime/transformers/index +0 -1
  491. package/dist/runtime/transformers/json +0 -1
  492. package/dist/runtime/transformers/markdown +0 -1
  493. package/dist/runtime/transformers/path-meta +0 -1
  494. package/dist/runtime/transformers/utils +0 -1
  495. package/dist/runtime/transformers/yaml +0 -1
  496. package/dist/runtime/utils/content-components +0 -1
  497. package/dist/runtime/utils/query +0 -1
  498. package/dist/runtime/utils/sitemap-source +0 -1
  499. package/dist/storage/cache +0 -1
  500. package/dist/storage/content +0 -1
  501. package/dist/storage/contents +0 -1
  502. package/dist/storage/driver +0 -1
  503. package/dist/storage/graph +0 -1
  504. package/dist/storage/manifest +0 -1
  505. package/dist/storage/manifest.d.ts +0 -18
  506. package/dist/storage/manifest.js +0 -70
  507. package/dist/storage/references +0 -1
  508. package/dist/storage/snapshot-runtime +0 -1
  509. package/dist/storage/validation +0 -1
  510. package/dist/testing/provider-contract +0 -1
  511. package/dist/testing/provider-fixture +0 -1
  512. package/dist/types/api +0 -1
  513. package/dist/types/config +0 -1
  514. package/dist/types/content +0 -1
  515. package/dist/types/fields +0 -1
  516. package/dist/types/index +0 -1
  517. package/dist/types/module +0 -1
  518. package/dist/types/query +0 -1
  519. package/dist/types/query-parts/collections +0 -1
  520. package/dist/types/query-parts/public +0 -1
  521. package/dist/types/query-parts/results +0 -1
  522. package/dist/types/query-parts/transport +0 -1
  523. package/dist/types/reference +0 -1
  524. package/dist/types/runtime +0 -1
  525. package/dist/types/search +0 -1
package/README.md CHANGED
@@ -12,8 +12,8 @@ and server-side reads.
12
12
 
13
13
  ## Requirements
14
14
 
15
- - Node.js 20 or later
16
- - Nuxt 4.4.7 or later
15
+ - Node.js 22 or later
16
+ - Nuxt 4.4.7 through Nuxt 4.x
17
17
  - Vue 3.5 or later
18
18
 
19
19
  ## Install
@@ -113,7 +113,7 @@ For localized Nuxt apps, keep one source of truth per route type:
113
113
 
114
114
  Do not duplicate docs, blog, pricing, privacy, or translated locale paths in
115
115
  `sitemap.urls` or app-owned `nitro.prerender.routes` arrays. Use
116
- `@nuxtjs/sitemap >= 8.0.15` when translated static app slugs such as `/preise`
116
+ `@nuxtjs/sitemap >= 8.0.15 < 9` when translated static app slugs such as `/preise`
117
117
  and `/en/pricing` need cross-locale sitemap alternates.
118
118
 
119
119
  See the public guide: [Sitemap and prerender](../../docs/content/docs/6.i18n/4.sitemap-prerender.md).
@@ -126,7 +126,7 @@ See the public guide: [Sitemap and prerender](../../docs/content/docs/6.i18n/4.s
126
126
  | MiniSearch backend | Included as a runtime dependency and used by the default search backend. |
127
127
  | Pagefind backend | Included as a runtime dependency and used when `content.search.engine` is `'pagefind'`. |
128
128
  | Provider-owned search | No extra package. The active content provider must advertise and implement `search`. |
129
- | Content i18n | Install and configure `@nuxtjs/i18n` when the app uses Nuxt locale routes. |
129
+ | Content i18n | Install and configure `@nuxtjs/i18n` 10.x when the app uses Nuxt locale routes. |
130
130
  | Sitemap XML output | Install and configure `@nuxtjs/sitemap`; Ginko contributes the content sitemap source. |
131
131
 
132
132
  ## Scope
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "Ginko Content release compatibility",
3
3
  "releaseStack": {
4
- "@lupinum/ginko-content": "0.2.1",
5
- "@lupinum/ginko-cms": "0.1.2",
6
- "@lupinum/ginko-cms-convex": "0.1.1",
7
- "@lupinum/ginko-cms-contract": "0.1.1"
4
+ "@lupinum/ginko-content": "0.3.0-rc.2",
5
+ "@lupinum/ginko-cms": "0.2.0-rc.1",
6
+ "@lupinum/ginko-cms-convex": "0.2.0-rc.1",
7
+ "@lupinum/ginko-cms-contract": "0.2.0-rc.1"
8
8
  },
9
9
  "tracked": {
10
- "@convex-dev/better-auth": ["^0.12.2", "0.12.2"],
10
+ "@convex-dev/better-auth": ["^0.12.5", "0.12.5"],
11
11
  "@nuxtjs/mcp-toolkit": ["^0.16.1", "0.16.1"],
12
- "better-auth": ["1.6.11"],
12
+ "better-auth": ["1.6.23"],
13
13
  "convex": ["1.38.0", "^1.38.0"],
14
14
  "convex-helpers": ["^0.1.117", "0.1.117"],
15
15
  "h3": ["1.15.11"],
16
- "nuxt": ["^4.4.7", "4.4.7", ">=4.4.7"],
17
- "typescript": ["~6.0.3", "^6.0.3", "6.0.3"],
18
- "vite": ["^7.3.3", "7.3.3"],
19
- "vitest": ["^4.1.6", ">=4.1.6"],
20
- "vue-tsc": ["^3.2.9", "3.2.9"],
16
+ "nuxt": ["^4.4.8", "4.4.8", ">=4.4.7 <5"],
17
+ "typescript": ["~5.9.3", "5.9.3"],
18
+ "vite": ["^7.3.6", "7.3.6"],
19
+ "vitest": ["^4.1.10", ">=4.1.6 <5"],
20
+ "vue-tsc": ["^3.3.7", "3.3.7"],
21
21
  "zod": ["4.4.3", "^4.4.3"]
22
22
  },
23
23
  "intentionalHolds": [
package/dist/cli.mjs CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { existsSync } from 'node:fs';
3
3
  import { stat, readFile, readdir } from 'node:fs/promises';
4
- import { join, extname, relative } from 'node:path';
4
+ import { join, extname, relative, resolve, isAbsolute } from 'node:path';
5
+ import { loadNuxtConfig } from '@nuxt/kit';
6
+ import { isContentValidationReport } from '../dist/features/validation/report.js';
5
7
 
6
8
  const ignoredDirs = /* @__PURE__ */ new Set([
7
9
  ".git",
@@ -27,7 +29,7 @@ const sourceExtensions = /* @__PURE__ */ new Set([
27
29
  ".yml",
28
30
  ".yaml"
29
31
  ]);
30
- const toRelativePath = (rootDir, file) => relative(rootDir, file) || ".";
32
+ const toRelativePath = (rootDir, file) => relative(rootDir, file).replace(/\\/g, "/") || ".";
31
33
  async function collectFiles(dir, rootDir, files = []) {
32
34
  const entries = await readdir(dir, { withFileTypes: true });
33
35
  for (const entry of entries) {
@@ -436,7 +438,7 @@ async function inspectI18nSourceSmells(rootDir, locales) {
436
438
  severity: "error",
437
439
  file: relativeFile,
438
440
  message: "Hardcoded locale route branch found.",
439
- suggestion: "Use @nuxtjs/i18n route helpers, useContentNavigation('docs'), or useContentMany('docs', options) item paths instead of branching on locale codes."
441
+ suggestion: "Use @nuxtjs/i18n route helpers, navigation('docs', options), or many('docs', options) item route paths instead of branching on locale codes."
440
442
  });
441
443
  }
442
444
  if (/<(?:NuxtLink|U[A-Za-z]+)\b[^>]*:to\s*=\s*["'][^"']+\._path["']/.test(text)) {
@@ -444,7 +446,7 @@ async function inspectI18nSourceSmells(rootDir, locales) {
444
446
  severity: "error",
445
447
  file: relativeFile,
446
448
  message: "UI link is bound to raw content _path.",
447
- suggestion: "Use useContentMany('docs', options) for localized list pages and bind item.path."
449
+ suggestion: "Use many('docs', options) from @lupinum/ginko-content/client for localized list pages and bind item.route.resolvedPath."
448
450
  });
449
451
  }
450
452
  }
@@ -505,7 +507,7 @@ async function inspectRepeatedLocalePrefixes(rootDir, locales) {
505
507
  severity: "error",
506
508
  file: relativeFile,
507
509
  message: `Repeated locale prefix "${repeatedPath}" found in generated output.`,
508
- suggestion: "Bind route-ready item.path values from useContentMany(), navigation, or search results instead of manually prefixing locale paths."
510
+ suggestion: "Bind route-ready item.route.resolvedPath values from many(), navigation(), or search results instead of manually prefixing locale paths."
509
511
  });
510
512
  break;
511
513
  }
@@ -580,7 +582,7 @@ async function inspectI18nSearchIndex(rootDir, locales) {
580
582
  severity: "error",
581
583
  file: ".output/public/api/_content/search/index.json",
582
584
  message: `Search index has no records for locale "${locale}".`,
583
- suggestion: "Use useContentSearchData() with i18n collections and verify the prerendered search payload includes every locale."
585
+ suggestion: "Use useContentSearch() with i18n collections and verify the prerendered search payload includes every locale."
584
586
  });
585
587
  }
586
588
  }
@@ -688,7 +690,7 @@ async function inspectSourceChecks(rootDir, checks) {
688
690
  for (const check of checks) {
689
691
  if (check.pattern.test(text)) {
690
692
  findings.push({
691
- severity: "error",
693
+ severity: check.severity ?? "error",
692
694
  file: toRelativePath(rootDir, file),
693
695
  message: check.message,
694
696
  suggestion: check.suggestion
@@ -719,27 +721,41 @@ async function inspectPublicApiUsage(rootDir) {
719
721
  {
720
722
  pattern: /\bqueryCollectionSearchSections\s*\(/,
721
723
  message: "Nuxt Content v3 search sections helper found.",
722
- suggestion: "Use useContentSearchData('docs') for UI search data."
724
+ suggestion: "Use useContentSearch({ collection: docs }) for UI search data."
723
725
  },
724
726
  {
725
727
  pattern: /\bqueryCollectionNavigation\s*\(/,
726
728
  message: "Nuxt Content v3 navigation helper found.",
727
- suggestion: "Use useContentNavigation('docs') for layout navigation."
729
+ suggestion: "Use navigation('docs', options) from @lupinum/ginko-content/client inside useAsyncData for layout navigation."
728
730
  },
729
731
  {
730
732
  pattern: /\bqueryCollection\s*\(/,
731
733
  message: "Removed collection query helper found.",
732
- suggestion: "Use one('docs', options), many('docs', options), paginate('docs', options), or the matching useContent* composable."
734
+ suggestion: "Use one('docs', options), many('docs', options), or paginate('docs', options) from @lupinum/ginko-content/client inside useAsyncData."
733
735
  },
734
736
  {
735
737
  pattern: /\buseContentList\s*\(/,
736
738
  message: "Removed content list composable found.",
737
- suggestion: "Use useContentMany('docs', options) or many('docs', options)."
739
+ suggestion: "Use many('docs', options) from @lupinum/ginko-content/client inside useAsyncData."
738
740
  },
739
741
  {
740
- pattern: /\bcontent\.(database|preview|build)\b/,
742
+ pattern: /\bcontent\.(database|build)\b/,
741
743
  message: "Nuxt Content v3 runtime config key found.",
742
- suggestion: "Remove content.database/content.preview/content.build and configure Ginko runtime options instead."
744
+ suggestion: "Remove content.database/content.build and configure Ginko runtime options instead."
745
+ },
746
+ {
747
+ // `content.preview` is a real Ginko option (ContentPreviewOptions), unlike
748
+ // `content.database`/`content.build`, so it is not flagged as a v3
749
+ // leftover. This rule only reminds authors of its actual scope: the
750
+ // filesystem provider always shows drafts/partials in development, and a
751
+ // configured token additionally unlocks visibility for files already
752
+ // present in a deployed filesystem checkout. It does not fetch
753
+ // not-yet-published content — that kind of production preview workflow
754
+ // is owned by a CMS provider, not the filesystem provider.
755
+ pattern: /\bcontent\.preview\b/,
756
+ message: "content.preview configuration found.",
757
+ suggestion: "content.preview only gates draft/partial visibility for the filesystem provider; it always applies in development. In production it unlocks drafts already present in the deployed content directory \u2014 it is not a substitute for a provider-owned preview workflow that fetches unpublished content.",
758
+ severity: "info"
743
759
  },
744
760
  {
745
761
  pattern: /\.editor\s*\(/,
@@ -759,7 +775,7 @@ async function inspectRenderingUsage(rootDir) {
759
775
  {
760
776
  pattern: /<NuxtLink\b[^>]*:to\s*=\s*["'][^"']+\._path["']/,
761
777
  message: "NuxtLink is using raw content _path.",
762
- suggestion: "Use useContentMany('docs', options) for list pages and bind the route-safe item.path field."
778
+ suggestion: "Use many('docs', options) from @lupinum/ginko-content/client for list pages and bind the route-safe item.route.resolvedPath field."
763
779
  }
764
780
  ]);
765
781
  }
@@ -834,6 +850,53 @@ async function runDoctor(options = {}) {
834
850
  };
835
851
  }
836
852
 
853
+ const runContentValidation = async (options = {}) => {
854
+ const rootDir = resolve(options.rootDir || process.cwd());
855
+ const nuxtConfig = await loadNuxtConfig({ cwd: rootDir });
856
+ const buildDir = isAbsolute(nuxtConfig.buildDir) ? nuxtConfig.buildDir : resolve(rootDir, nuxtConfig.buildDir);
857
+ const reportPath = join(buildDir, "content-cache/validation.json");
858
+ let report;
859
+ try {
860
+ report = JSON.parse(await readFile(reportPath, "utf8"));
861
+ } catch {
862
+ report = void 0;
863
+ }
864
+ if (!isContentValidationReport(report)) {
865
+ return {
866
+ rootDir,
867
+ findings: [{
868
+ severity: "error",
869
+ file: relative(rootDir, reportPath),
870
+ message: "Generated content validation report not found or invalid.",
871
+ suggestion: "Run a Nuxt build with this Ginko Content version before `ginko-content validate`."
872
+ }],
873
+ exitCode: 1
874
+ };
875
+ }
876
+ return {
877
+ rootDir,
878
+ findings: report.findings,
879
+ exitCode: report.findings.some((finding) => finding.severity === "error") ? 1 : 0
880
+ };
881
+ };
882
+ const formatContentValidationResult = (result) => {
883
+ const errors = result.findings.filter((finding) => finding.severity === "error");
884
+ const infos = result.findings.filter((finding) => finding.severity === "info");
885
+ const lines = [
886
+ `Ginko Content validation: ${errors.length ? "issues found" : "ok"}`,
887
+ `Root: ${result.rootDir}`
888
+ ];
889
+ for (const [label, findings] of [["Errors", errors], ["Info", infos]]) {
890
+ if (!findings.length) continue;
891
+ lines.push("", `${label} (${findings.length})`);
892
+ for (const finding of findings) {
893
+ lines.push(`- ${finding.file}: ${finding.message}`, ` Fix: ${finding.suggestion}`);
894
+ }
895
+ }
896
+ return `${lines.join("\n")}
897
+ `;
898
+ };
899
+
837
900
  const [, , command, ...args] = process.argv;
838
901
  if (!command || command === "--help" || command === "-h") {
839
902
  console.log([
@@ -841,16 +904,27 @@ if (!command || command === "--help" || command === "-h") {
841
904
  "",
842
905
  "Commands:",
843
906
  " doctor [root] Validate a Nuxt Content v3 to Ginko migration",
844
- " doctor --i18n [root] Validate i18n migration wiring and generated output"
907
+ " doctor --i18n [root] Validate i18n migration wiring and generated output",
908
+ " validate [root] Validate internal content links, anchors, and assets"
845
909
  ].join("\n"));
846
910
  process.exit(0);
847
911
  }
848
- if (command !== "doctor") {
912
+ if (command !== "doctor" && command !== "validate") {
849
913
  console.error(`Unknown command: ${command}`);
850
914
  console.error('Run "ginko-content --help" for available commands.');
851
915
  process.exit(1);
852
916
  }
853
917
  try {
918
+ if (command === "validate") {
919
+ const unknownFlag2 = args.find((arg) => arg.startsWith("-"));
920
+ if (unknownFlag2) {
921
+ console.error(`Unknown option: ${unknownFlag2}`);
922
+ process.exit(1);
923
+ }
924
+ const result2 = await runContentValidation({ rootDir: args[0] || process.cwd() });
925
+ process.stdout.write(formatContentValidationResult(result2));
926
+ process.exit(result2.exitCode);
927
+ }
854
928
  const i18n = args.includes("--i18n");
855
929
  const rootDirArg = args.find((arg) => !arg.startsWith("-"));
856
930
  const unknownFlag = args.find((arg) => arg.startsWith("-") && arg !== "--i18n");
@@ -0,0 +1,10 @@
1
+ import type { PortableMediaType } from './types.js';
2
+ export interface VerifiedPublicImage {
3
+ mediaType: PortableMediaType;
4
+ bytes: number;
5
+ sha256: string;
6
+ width: number;
7
+ height: number;
8
+ frames: number;
9
+ }
10
+ export declare function verifyPublicImageBytes(source: Uint8Array | AsyncIterable<Uint8Array>, claimedMediaType?: string): Promise<VerifiedPublicImage>;
@@ -0,0 +1,266 @@
1
+ import { IncrementalSha256 } from "./hash.js";
2
+ import { PORTABLE_CONTENT_LIMITS } from "./limits.js";
3
+ const {
4
+ assetBytes: MAX_BYTES,
5
+ imageDimension: MAX_DIMENSION,
6
+ imagePixels: MAX_PIXELS,
7
+ imageFrames: MAX_FRAMES,
8
+ imageDecodedBytes: MAX_DECODED_BYTES
9
+ } = PORTABLE_CONTENT_LIMITS;
10
+ const failure = (message) => {
11
+ throw new TypeError(`Invalid public image: ${message}`);
12
+ };
13
+ const u16be = (bytes, offset) => bytes[offset] << 8 | bytes[offset + 1];
14
+ const u16le = (bytes, offset) => bytes[offset] | bytes[offset + 1] << 8;
15
+ const u24le = (bytes, offset) => bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16;
16
+ const u32be = (bytes, offset) => (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
17
+ const u32le = (bytes, offset) => (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
18
+ const ascii = (bytes, offset, length) => String.fromCharCode(...bytes.subarray(offset, offset + length));
19
+ function validateDimensions(width, height) {
20
+ if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0 || width > MAX_DIMENSION || height > MAX_DIMENSION) failure("dimensions exceed the supported range.");
21
+ const pixels = width * height;
22
+ if (pixels > MAX_PIXELS) failure("pixel count exceeds the supported limit.");
23
+ return pixels;
24
+ }
25
+ function validateBounds(facts) {
26
+ const pixels = validateDimensions(facts.width, facts.height);
27
+ if (!Number.isInteger(facts.frames) || facts.frames <= 0 || facts.frames > MAX_FRAMES) {
28
+ failure("frame count exceeds the supported limit.");
29
+ }
30
+ if (pixels * 4 * facts.frames > MAX_DECODED_BYTES) {
31
+ failure("calculated decoded bytes exceed the supported limit.");
32
+ }
33
+ return facts;
34
+ }
35
+ let crcTable;
36
+ function crc32(bytes) {
37
+ if (!crcTable) {
38
+ crcTable = new Uint32Array(256);
39
+ for (let index = 0; index < 256; index++) {
40
+ let value = index;
41
+ for (let bit = 0; bit < 8; bit++) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
42
+ crcTable[index] = value >>> 0;
43
+ }
44
+ }
45
+ let crc = 4294967295;
46
+ for (const byte of bytes) crc = crcTable[(crc ^ byte) & 255] ^ crc >>> 8;
47
+ return (crc ^ 4294967295) >>> 0;
48
+ }
49
+ function parsePng(bytes) {
50
+ const signature = [137, 80, 78, 71, 13, 10, 26, 10];
51
+ if (bytes.length < 33 || signature.some((value, index) => bytes[index] !== value)) {
52
+ return failure("PNG signature is missing.");
53
+ }
54
+ let offset = 8;
55
+ let width = 0;
56
+ let height = 0;
57
+ let frames = 1;
58
+ let sawHeader = false;
59
+ let sawData = false;
60
+ let sawEnd = false;
61
+ while (offset < bytes.length) {
62
+ if (offset + 12 > bytes.length) failure("PNG chunk is truncated.");
63
+ const length = u32be(bytes, offset);
64
+ const end = offset + 12 + length;
65
+ if (end > bytes.length) failure("PNG chunk length exceeds the file.");
66
+ const type = ascii(bytes, offset + 4, 4);
67
+ const contentEnd = offset + 8 + length;
68
+ if (crc32(bytes.subarray(offset + 4, contentEnd)) !== u32be(bytes, contentEnd)) {
69
+ failure(`PNG ${type} checksum does not match.`);
70
+ }
71
+ if (!sawHeader && type !== "IHDR") failure("PNG IHDR must be the first chunk.");
72
+ if (type === "IHDR") {
73
+ if (sawHeader || length !== 13) failure("PNG IHDR is invalid.");
74
+ width = u32be(bytes, offset + 8);
75
+ height = u32be(bytes, offset + 12);
76
+ if (bytes[offset + 18] !== 0 || bytes[offset + 19] !== 0 || ![0, 1].includes(bytes[offset + 20])) {
77
+ failure("PNG compression, filter, or interlace method is unsupported.");
78
+ }
79
+ sawHeader = true;
80
+ } else if (type === "IDAT") {
81
+ sawData = true;
82
+ } else if (type === "acTL") {
83
+ if (length !== 8) failure("PNG animation control chunk is invalid.");
84
+ frames = u32be(bytes, offset + 8);
85
+ } else if (type === "IEND") {
86
+ if (length !== 0 || !sawData) failure("PNG terminal chunk is invalid.");
87
+ sawEnd = true;
88
+ offset = end;
89
+ break;
90
+ }
91
+ offset = end;
92
+ }
93
+ if (!sawEnd || offset !== bytes.length) failure("PNG has no exact terminal IEND chunk.");
94
+ return validateBounds({ mediaType: "image/png", width, height, frames });
95
+ }
96
+ function parseJpeg(bytes) {
97
+ if (bytes.length < 4 || bytes[0] !== 255 || bytes[1] !== 216) {
98
+ return failure("JPEG start marker is missing.");
99
+ }
100
+ let offset = 2;
101
+ let width = 0;
102
+ let height = 0;
103
+ let components = 0;
104
+ let sawEnd = false;
105
+ while (offset < bytes.length) {
106
+ if (bytes[offset++] !== 255) failure("JPEG marker prefix is invalid.");
107
+ while (bytes[offset] === 255) offset++;
108
+ const marker = bytes[offset++];
109
+ if (marker === void 0 || marker === 0) failure("JPEG marker is truncated.");
110
+ if (marker === 217) {
111
+ sawEnd = true;
112
+ break;
113
+ }
114
+ if (marker === 216 || marker >= 208 && marker <= 215 || marker === 1) continue;
115
+ if (offset + 2 > bytes.length) failure("JPEG segment is truncated.");
116
+ const length = u16be(bytes, offset);
117
+ if (length < 2 || offset + length > bytes.length) failure("JPEG segment length is invalid.");
118
+ const segmentStart = offset + 2;
119
+ if ([192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207].includes(marker)) {
120
+ if (length < 8) failure("JPEG frame header is truncated.");
121
+ height = u16be(bytes, segmentStart + 1);
122
+ width = u16be(bytes, segmentStart + 3);
123
+ components = bytes[segmentStart + 5];
124
+ if (length !== 8 + components * 3) failure("JPEG frame components are malformed.");
125
+ }
126
+ offset += length;
127
+ if (marker === 218) {
128
+ while (offset < bytes.length) {
129
+ if (bytes[offset++] !== 255) continue;
130
+ while (bytes[offset] === 255) offset++;
131
+ const next = bytes[offset];
132
+ if (next === 0 || next !== void 0 && next >= 208 && next <= 215) {
133
+ offset++;
134
+ continue;
135
+ }
136
+ offset--;
137
+ break;
138
+ }
139
+ }
140
+ }
141
+ if (!sawEnd || offset !== bytes.length) failure("JPEG has no exact terminal EOI marker.");
142
+ if (!width || !height || !components) failure("JPEG frame dimensions are missing.");
143
+ return validateBounds({ mediaType: "image/jpeg", width, height, frames: 1 });
144
+ }
145
+ function skipGifSubBlocks(bytes, start) {
146
+ let offset = start;
147
+ while (true) {
148
+ if (offset >= bytes.length) failure("GIF sub-block stream is truncated.");
149
+ const length = bytes[offset++];
150
+ if (length === 0) return offset;
151
+ if (offset + length > bytes.length) failure("GIF sub-block exceeds the file.");
152
+ offset += length;
153
+ }
154
+ }
155
+ function parseGif(bytes) {
156
+ const header = ascii(bytes, 0, 6);
157
+ if (bytes.length < 14 || !["GIF87a", "GIF89a"].includes(header)) return failure("GIF signature is missing.");
158
+ const width = u16le(bytes, 6);
159
+ const height = u16le(bytes, 8);
160
+ const packed = bytes[10];
161
+ let offset = 13 + (packed & 128 ? 3 * (1 << (packed & 7) + 1) : 0);
162
+ let frames = 0;
163
+ let decodedPixels = 0;
164
+ let sawEnd = false;
165
+ while (offset < bytes.length) {
166
+ const marker = bytes[offset++];
167
+ if (marker === 59) {
168
+ sawEnd = true;
169
+ break;
170
+ }
171
+ if (marker === 33) {
172
+ if (offset >= bytes.length) failure("GIF extension is truncated.");
173
+ offset++;
174
+ offset = skipGifSubBlocks(bytes, offset);
175
+ continue;
176
+ }
177
+ if (marker !== 44 || offset + 9 > bytes.length) failure("GIF block marker is invalid.");
178
+ const frameWidth = u16le(bytes, offset + 4);
179
+ const frameHeight = u16le(bytes, offset + 6);
180
+ const framePacked = bytes[offset + 8];
181
+ if (!frameWidth || !frameHeight) failure("GIF frame dimensions are invalid.");
182
+ decodedPixels += validateDimensions(frameWidth, frameHeight);
183
+ if (decodedPixels * 4 > MAX_DECODED_BYTES) failure("calculated decoded bytes exceed the supported limit.");
184
+ offset += 9;
185
+ if (framePacked & 128) offset += 3 * (1 << (framePacked & 7) + 1);
186
+ if (offset >= bytes.length || bytes[offset++] > 11) failure("GIF LZW code size is invalid.");
187
+ offset = skipGifSubBlocks(bytes, offset);
188
+ frames++;
189
+ }
190
+ if (!sawEnd || offset !== bytes.length || frames === 0) failure("GIF has no exact terminal trailer or image frame.");
191
+ return validateBounds({ mediaType: "image/gif", width, height, frames });
192
+ }
193
+ function parseWebp(bytes) {
194
+ if (bytes.length < 20 || ascii(bytes, 0, 4) !== "RIFF" || ascii(bytes, 8, 4) !== "WEBP") {
195
+ return failure("WebP RIFF signature is missing.");
196
+ }
197
+ if (u32le(bytes, 4) + 8 !== bytes.length) failure("WebP RIFF length does not match the file.");
198
+ let offset = 12;
199
+ let width = 0;
200
+ let height = 0;
201
+ let frames = 0;
202
+ while (offset < bytes.length) {
203
+ if (offset + 8 > bytes.length) failure("WebP chunk is truncated.");
204
+ const type = ascii(bytes, offset, 4);
205
+ const length = u32le(bytes, offset + 4);
206
+ const data = offset + 8;
207
+ const end = data + length;
208
+ if (end > bytes.length) failure("WebP chunk length exceeds the file.");
209
+ if (type === "VP8X") {
210
+ if (length !== 10) failure("WebP extended header is invalid.");
211
+ width = u24le(bytes, data + 4) + 1;
212
+ height = u24le(bytes, data + 7) + 1;
213
+ } else if (type === "VP8 ") {
214
+ if (length < 10 || bytes[data + 3] !== 157 || bytes[data + 4] !== 1 || bytes[data + 5] !== 42) {
215
+ failure("WebP VP8 frame header is invalid.");
216
+ }
217
+ width ||= u16le(bytes, data + 6) & 16383;
218
+ height ||= u16le(bytes, data + 8) & 16383;
219
+ frames ||= 1;
220
+ } else if (type === "VP8L") {
221
+ if (length < 5 || bytes[data] !== 47) failure("WebP lossless frame header is invalid.");
222
+ const bits = u32le(bytes, data + 1);
223
+ width ||= (bits & 16383) + 1;
224
+ height ||= (bits >>> 14 & 16383) + 1;
225
+ frames ||= 1;
226
+ } else if (type === "ANMF") {
227
+ if (length < 16) failure("WebP animation frame is invalid.");
228
+ frames++;
229
+ }
230
+ offset = end + (length & 1);
231
+ }
232
+ if (offset !== bytes.length || !width || !height || !frames) failure("WebP container is incomplete.");
233
+ return validateBounds({ mediaType: "image/webp", width, height, frames });
234
+ }
235
+ function parseImage(bytes) {
236
+ if (bytes[0] === 137 && ascii(bytes, 1, 3) === "PNG") return parsePng(bytes);
237
+ if (bytes[0] === 255 && bytes[1] === 216) return parseJpeg(bytes);
238
+ if (ascii(bytes, 0, 3) === "GIF") return parseGif(bytes);
239
+ if (ascii(bytes, 0, 4) === "RIFF") return parseWebp(bytes);
240
+ return failure("signature is unsupported.");
241
+ }
242
+ export async function verifyPublicImageBytes(source, claimedMediaType) {
243
+ const hash = new IncrementalSha256();
244
+ const chunks = [];
245
+ let bytes = 0;
246
+ const add = (chunk) => {
247
+ if (!(chunk instanceof Uint8Array)) failure("byte stream contains a non-Uint8Array chunk.");
248
+ bytes += chunk.length;
249
+ if (bytes <= 0 || bytes > MAX_BYTES) failure("byte length exceeds the supported upload limit.");
250
+ hash.update(chunk);
251
+ chunks.push(chunk.slice());
252
+ };
253
+ if (source instanceof Uint8Array) add(source);
254
+ else for await (const chunk of source) add(chunk);
255
+ const all = new Uint8Array(bytes);
256
+ let offset = 0;
257
+ for (const chunk of chunks) {
258
+ all.set(chunk, offset);
259
+ offset += chunk.length;
260
+ }
261
+ const facts = parseImage(all);
262
+ if (claimedMediaType && claimedMediaType.toLowerCase() !== facts.mediaType) {
263
+ failure(`claimed MIME "${claimedMediaType}" does not match verified ${facts.mediaType}.`);
264
+ }
265
+ return { ...facts, bytes, sha256: hash.digestHex() };
266
+ }
@@ -1,44 +1,15 @@
1
- /**
2
- * `buildCmsContract` — deterministic normalization of a host's
3
- * `content.config.ts` output into the shape `@lupinum/ginko-cms` consumes.
4
- *
5
- * Per the refactor plan: the CMS used to *infer* labels, types, locales,
6
- * routing, and field shape from a content collection's loose config. That
7
- * inference produced misclassifications (data collections rendered as
8
- * route-backed, singletons treated as flat, fields losing media metadata).
9
- *
10
- * `buildCmsContract` instead produces a single normalized artifact. Anything
11
- * the CMS needs to know is recorded explicitly. The CMS is forbidden from
12
- * inferring on its own; it just reads this contract.
13
- *
14
- * This is a Gate 0 spike: the function is shaped end-to-end so the CMS can
15
- * import and call it, but the schema-introspection branches are intentionally
16
- * minimal. Gate 1 will fill them in against real fixtures.
17
- */
18
1
  import type { ContentCollectionConfig } from '../types/config.js';
19
- import type { CmsContract, CmsSchemaCapabilities } from './types.js';
20
- /** Stable contract version. Bump when the CMS-facing artifact shape changes. */
21
- export declare const CMS_CONTRACT_VERSION = "v1";
22
- export declare class CmsContractSchemaUnsupportedError extends Error {
23
- readonly collectionSlug: string;
24
- readonly unsupported: CmsSchemaCapabilities['unsupported'];
25
- constructor(collectionSlug: string, unsupported: CmsSchemaCapabilities['unsupported']);
2
+ import type { PortableComponentPolicyV1, ResolvedContentContractV1 } from './types.js';
3
+ export declare const RESOLVED_CONTENT_CONTRACT_VERSION: 1;
4
+ export interface BuildResolvedContentContractInput {
5
+ collections: Record<string, ContentCollectionConfig>;
26
6
  }
27
- export interface BuildCmsContractOptions {
28
- /** Site default locale, e.g. `'en'`. */
7
+ export interface BuildResolvedContentContractOptions {
29
8
  defaultLocale: string;
30
- /** All locale codes the site can serve. */
31
9
  locales: string[];
32
- /** Optional include filter — when set, only listed collections are emitted. */
10
+ localeFallbacks?: Record<string, string[]>;
11
+ translatedSlugs?: boolean;
33
12
  include?: string[];
13
+ componentPolicy?: PortableComponentPolicyV1;
34
14
  }
35
- export interface BuildCmsContractInput {
36
- collections: Record<string, ContentCollectionConfig>;
37
- }
38
- /**
39
- * Build a normalized CMS contract from a host's `content.config.ts` output.
40
- *
41
- * The function is deterministic: same input yields byte-identical output. The
42
- * CMS hashes the result to detect contract changes between deployments.
43
- */
44
- export declare function buildCmsContract(config: BuildCmsContractInput, options: BuildCmsContractOptions): CmsContract;
15
+ export declare function buildResolvedContentContract(config: BuildResolvedContentContractInput, options: BuildResolvedContentContractOptions): ResolvedContentContractV1;