gazetta 0.5.0 → 0.6.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 (236) hide show
  1. package/admin-dist/assets/index-B6pVot0Y.css +1 -0
  2. package/admin-dist/assets/index-DniLwxJA.js +609 -0
  3. package/admin-dist/assets/{vendor-primevue-BnR1c_bQ.js → vendor-primevue-C0Q_YTCb.js} +330 -431
  4. package/admin-dist/assets/vendor-vue-D3wBSmDf.js +1 -0
  5. package/admin-dist/index.html +4 -4
  6. package/dist/admin-api/index.d.ts +19 -4
  7. package/dist/admin-api/index.d.ts.map +1 -1
  8. package/dist/admin-api/index.js +154 -18
  9. package/dist/admin-api/index.js.map +1 -1
  10. package/dist/admin-api/routes/compare.d.ts +2 -1
  11. package/dist/admin-api/routes/compare.d.ts.map +1 -1
  12. package/dist/admin-api/routes/compare.js +33 -24
  13. package/dist/admin-api/routes/compare.js.map +1 -1
  14. package/dist/admin-api/routes/fields.d.ts +2 -2
  15. package/dist/admin-api/routes/fields.d.ts.map +1 -1
  16. package/dist/admin-api/routes/fields.js +10 -3
  17. package/dist/admin-api/routes/fields.js.map +1 -1
  18. package/dist/admin-api/routes/fragments.d.ts +2 -3
  19. package/dist/admin-api/routes/fragments.d.ts.map +1 -1
  20. package/dist/admin-api/routes/fragments.js +92 -19
  21. package/dist/admin-api/routes/fragments.js.map +1 -1
  22. package/dist/admin-api/routes/history.d.ts +23 -0
  23. package/dist/admin-api/routes/history.d.ts.map +1 -0
  24. package/dist/admin-api/routes/history.js +143 -0
  25. package/dist/admin-api/routes/history.js.map +1 -0
  26. package/dist/admin-api/routes/pages.d.ts +2 -3
  27. package/dist/admin-api/routes/pages.d.ts.map +1 -1
  28. package/dist/admin-api/routes/pages.js +118 -20
  29. package/dist/admin-api/routes/pages.js.map +1 -1
  30. package/dist/admin-api/routes/preview.d.ts +2 -2
  31. package/dist/admin-api/routes/preview.d.ts.map +1 -1
  32. package/dist/admin-api/routes/preview.js +50 -15
  33. package/dist/admin-api/routes/preview.js.map +1 -1
  34. package/dist/admin-api/routes/publish.d.ts +2 -1
  35. package/dist/admin-api/routes/publish.d.ts.map +1 -1
  36. package/dist/admin-api/routes/publish.js +213 -66
  37. package/dist/admin-api/routes/publish.js.map +1 -1
  38. package/dist/admin-api/routes/site.d.ts +2 -2
  39. package/dist/admin-api/routes/site.d.ts.map +1 -1
  40. package/dist/admin-api/routes/site.js +27 -4
  41. package/dist/admin-api/routes/site.js.map +1 -1
  42. package/dist/admin-api/routes/templates.d.ts +2 -2
  43. package/dist/admin-api/routes/templates.d.ts.map +1 -1
  44. package/dist/admin-api/routes/templates.js +19 -9
  45. package/dist/admin-api/routes/templates.js.map +1 -1
  46. package/dist/admin-api/schemas/compare.d.ts +29 -0
  47. package/dist/admin-api/schemas/compare.d.ts.map +1 -0
  48. package/dist/admin-api/schemas/compare.js +30 -0
  49. package/dist/admin-api/schemas/compare.js.map +1 -0
  50. package/dist/admin-api/schemas/dependents.d.ts +15 -0
  51. package/dist/admin-api/schemas/dependents.d.ts.map +1 -0
  52. package/dist/admin-api/schemas/dependents.js +14 -0
  53. package/dist/admin-api/schemas/dependents.js.map +1 -0
  54. package/dist/admin-api/schemas/fetch.d.ts +12 -0
  55. package/dist/admin-api/schemas/fetch.d.ts.map +1 -0
  56. package/dist/admin-api/schemas/fetch.js +11 -0
  57. package/dist/admin-api/schemas/fetch.js.map +1 -0
  58. package/dist/admin-api/schemas/fields.d.ts +11 -0
  59. package/dist/admin-api/schemas/fields.d.ts.map +1 -0
  60. package/dist/admin-api/schemas/fields.js +11 -0
  61. package/dist/admin-api/schemas/fields.js.map +1 -0
  62. package/dist/admin-api/schemas/fragments.d.ts +27 -0
  63. package/dist/admin-api/schemas/fragments.d.ts.map +1 -0
  64. package/dist/admin-api/schemas/fragments.js +26 -0
  65. package/dist/admin-api/schemas/fragments.js.map +1 -0
  66. package/dist/admin-api/schemas/history.d.ts +73 -0
  67. package/dist/admin-api/schemas/history.d.ts.map +1 -0
  68. package/dist/admin-api/schemas/history.js +35 -0
  69. package/dist/admin-api/schemas/history.js.map +1 -0
  70. package/dist/admin-api/schemas/index.d.ts +32 -0
  71. package/dist/admin-api/schemas/index.d.ts.map +1 -0
  72. package/dist/admin-api/schemas/index.js +32 -0
  73. package/dist/admin-api/schemas/index.js.map +1 -0
  74. package/dist/admin-api/schemas/pages.d.ts +46 -0
  75. package/dist/admin-api/schemas/pages.d.ts.map +1 -0
  76. package/dist/admin-api/schemas/pages.js +47 -0
  77. package/dist/admin-api/schemas/pages.js.map +1 -0
  78. package/dist/admin-api/schemas/publish.d.ts +67 -0
  79. package/dist/admin-api/schemas/publish.d.ts.map +1 -0
  80. package/dist/admin-api/schemas/publish.js +60 -0
  81. package/dist/admin-api/schemas/publish.js.map +1 -0
  82. package/dist/admin-api/schemas/site.d.ts +28 -0
  83. package/dist/admin-api/schemas/site.d.ts.map +1 -0
  84. package/dist/admin-api/schemas/site.js +24 -0
  85. package/dist/admin-api/schemas/site.js.map +1 -0
  86. package/dist/admin-api/schemas/targets.d.ts +36 -0
  87. package/dist/admin-api/schemas/targets.d.ts.map +1 -0
  88. package/dist/admin-api/schemas/targets.js +19 -0
  89. package/dist/admin-api/schemas/targets.js.map +1 -0
  90. package/dist/admin-api/schemas/templates.d.ts +17 -0
  91. package/dist/admin-api/schemas/templates.d.ts.map +1 -0
  92. package/dist/admin-api/schemas/templates.js +16 -0
  93. package/dist/admin-api/schemas/templates.js.map +1 -0
  94. package/dist/admin-api/source-context.d.ts +165 -0
  95. package/dist/admin-api/source-context.d.ts.map +1 -0
  96. package/dist/admin-api/source-context.js +95 -0
  97. package/dist/admin-api/source-context.js.map +1 -0
  98. package/dist/app.js +1 -1
  99. package/dist/app.js.map +1 -1
  100. package/dist/assemble.d.ts.map +1 -1
  101. package/dist/assemble.js +4 -1
  102. package/dist/assemble.js.map +1 -1
  103. package/dist/cli/bootstrap.d.ts +48 -0
  104. package/dist/cli/bootstrap.d.ts.map +1 -0
  105. package/dist/cli/bootstrap.js +85 -0
  106. package/dist/cli/bootstrap.js.map +1 -0
  107. package/dist/cli/history.d.ts +45 -0
  108. package/dist/cli/history.d.ts.map +1 -0
  109. package/dist/cli/history.js +165 -0
  110. package/dist/cli/history.js.map +1 -0
  111. package/dist/cli/index.js +630 -115
  112. package/dist/cli/index.js.map +1 -1
  113. package/dist/compare.d.ts +8 -5
  114. package/dist/compare.d.ts.map +1 -1
  115. package/dist/compare.js +53 -14
  116. package/dist/compare.js.map +1 -1
  117. package/dist/content-root.d.ts +38 -0
  118. package/dist/content-root.d.ts.map +1 -0
  119. package/dist/content-root.js +29 -0
  120. package/dist/content-root.js.map +1 -0
  121. package/dist/editor/mount.d.ts +1 -1
  122. package/dist/editor/mount.d.ts.map +1 -1
  123. package/dist/editor/mount.js +61 -29
  124. package/dist/editor/mount.js.map +1 -1
  125. package/dist/hash.d.ts +34 -3
  126. package/dist/hash.d.ts.map +1 -1
  127. package/dist/hash.js +64 -7
  128. package/dist/hash.js.map +1 -1
  129. package/dist/history-provider.d.ts +49 -0
  130. package/dist/history-provider.d.ts.map +1 -0
  131. package/dist/history-provider.js +226 -0
  132. package/dist/history-provider.js.map +1 -0
  133. package/dist/history-recorder.d.ts +98 -0
  134. package/dist/history-recorder.d.ts.map +1 -0
  135. package/dist/history-recorder.js +160 -0
  136. package/dist/history-recorder.js.map +1 -0
  137. package/dist/history-restorer.d.ts +46 -0
  138. package/dist/history-restorer.d.ts.map +1 -0
  139. package/dist/history-restorer.js +105 -0
  140. package/dist/history-restorer.js.map +1 -0
  141. package/dist/history.d.ts +111 -0
  142. package/dist/history.d.ts.map +1 -0
  143. package/dist/history.js +25 -0
  144. package/dist/history.js.map +1 -0
  145. package/dist/index.d.ts +26 -4
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +16 -3
  148. package/dist/index.js.map +1 -1
  149. package/dist/locale.d.ts +74 -0
  150. package/dist/locale.d.ts.map +1 -0
  151. package/dist/locale.js +150 -0
  152. package/dist/locale.js.map +1 -0
  153. package/dist/manifest.d.ts.map +1 -1
  154. package/dist/manifest.js +16 -1
  155. package/dist/manifest.js.map +1 -1
  156. package/dist/providers/azure-blob.d.ts.map +1 -1
  157. package/dist/providers/azure-blob.js.map +1 -1
  158. package/dist/providers/r2.d.ts.map +1 -1
  159. package/dist/providers/r2.js +7 -4
  160. package/dist/providers/r2.js.map +1 -1
  161. package/dist/providers/s3.d.ts.map +1 -1
  162. package/dist/providers/s3.js +23 -15
  163. package/dist/providers/s3.js.map +1 -1
  164. package/dist/publish-locale.d.ts +44 -0
  165. package/dist/publish-locale.d.ts.map +1 -0
  166. package/dist/publish-locale.js +103 -0
  167. package/dist/publish-locale.js.map +1 -0
  168. package/dist/publish-rendered.d.ts +16 -5
  169. package/dist/publish-rendered.d.ts.map +1 -1
  170. package/dist/publish-rendered.js +89 -36
  171. package/dist/publish-rendered.js.map +1 -1
  172. package/dist/publish.d.ts +5 -7
  173. package/dist/publish.d.ts.map +1 -1
  174. package/dist/publish.js +21 -12
  175. package/dist/publish.js.map +1 -1
  176. package/dist/renderer.d.ts +14 -4
  177. package/dist/renderer.d.ts.map +1 -1
  178. package/dist/renderer.js +35 -23
  179. package/dist/renderer.js.map +1 -1
  180. package/dist/resolver.d.ts +7 -2
  181. package/dist/resolver.d.ts.map +1 -1
  182. package/dist/resolver.js +66 -15
  183. package/dist/resolver.js.map +1 -1
  184. package/dist/robots.d.ts +22 -0
  185. package/dist/robots.d.ts.map +1 -0
  186. package/dist/robots.js +25 -0
  187. package/dist/robots.js.map +1 -0
  188. package/dist/seo.d.ts +56 -0
  189. package/dist/seo.d.ts.map +1 -0
  190. package/dist/seo.js +72 -0
  191. package/dist/seo.js.map +1 -0
  192. package/dist/serve.d.ts +41 -3
  193. package/dist/serve.d.ts.map +1 -1
  194. package/dist/serve.js +206 -65
  195. package/dist/serve.js.map +1 -1
  196. package/dist/sidecars.d.ts +9 -5
  197. package/dist/sidecars.d.ts.map +1 -1
  198. package/dist/sidecars.js +112 -22
  199. package/dist/sidecars.js.map +1 -1
  200. package/dist/site-loader.d.ts +74 -6
  201. package/dist/site-loader.d.ts.map +1 -1
  202. package/dist/site-loader.js +138 -28
  203. package/dist/site-loader.js.map +1 -1
  204. package/dist/sitemap.d.ts +45 -0
  205. package/dist/sitemap.d.ts.map +1 -0
  206. package/dist/sitemap.js +67 -0
  207. package/dist/sitemap.js.map +1 -0
  208. package/dist/source-sidecars.d.ts +21 -2
  209. package/dist/source-sidecars.d.ts.map +1 -1
  210. package/dist/source-sidecars.js +51 -5
  211. package/dist/source-sidecars.js.map +1 -1
  212. package/dist/targets.d.ts +47 -1
  213. package/dist/targets.d.ts.map +1 -1
  214. package/dist/targets.js +78 -9
  215. package/dist/targets.js.map +1 -1
  216. package/dist/template-loader.d.ts +7 -3
  217. package/dist/template-loader.d.ts.map +1 -1
  218. package/dist/template-loader.js +27 -12
  219. package/dist/template-loader.js.map +1 -1
  220. package/dist/templates-scan-worker.js +1 -1
  221. package/dist/templates-scan-worker.js.map +1 -1
  222. package/dist/templates-scan.d.ts.map +1 -1
  223. package/dist/templates-scan.js +1 -1
  224. package/dist/templates-scan.js.map +1 -1
  225. package/dist/types.d.ts +116 -9
  226. package/dist/types.d.ts.map +1 -1
  227. package/dist/types.js +28 -5
  228. package/dist/types.js.map +1 -1
  229. package/dist/workers/cloudflare-r2.d.ts +11 -2
  230. package/dist/workers/cloudflare-r2.d.ts.map +1 -1
  231. package/dist/workers/cloudflare-r2.js +120 -55
  232. package/dist/workers/cloudflare-r2.js.map +1 -1
  233. package/package.json +11 -2
  234. package/admin-dist/assets/index-BZAFKsUp.js +0 -608
  235. package/admin-dist/assets/index-BpRotMuK.css +0 -1
  236. package/admin-dist/assets/vendor-vue-DSjyxCX6.js +0 -1
@@ -1,8 +1,9 @@
1
1
  import { Hono } from 'hono';
2
- import { loadSite } from '../../site-loader.js';
2
+ import { allPageEntries } from '../../site-loader.js';
3
+ import { loadSiteFromSource } from '../source-context.js';
3
4
  import { resolveFragment, resolvePage } from '../../resolver.js';
4
5
  import { renderFragment, renderPage } from '../../renderer.js';
5
- export function previewRoutes(siteDir, storage, templatesDir) {
6
+ export function previewRoutes(resolve, templatesDir) {
6
7
  const app = new Hono();
7
8
  // No caching — preview always serves fresh content for editing
8
9
  app.use('/preview/*', async (c, next) => {
@@ -10,25 +11,50 @@ export function previewRoutes(siteDir, storage, templatesDir) {
10
11
  c.header('Cache-Control', 'no-store');
11
12
  });
12
13
  app.get('/preview/*', async (c) => {
13
- return renderPreview(c, siteDir, storage, undefined, templatesDir);
14
+ const source = await resolve(c.req.query('target'));
15
+ return renderPreview(c, source, undefined, templatesDir);
14
16
  });
15
17
  app.post('/preview/*', async (c) => {
16
- const body = await c.req.json();
17
- return renderPreview(c, siteDir, storage, body.overrides, templatesDir);
18
+ const source = await resolve(c.req.query('target'));
19
+ const body = (await c.req.json());
20
+ return renderPreview(c, source, body.overrides, templatesDir);
18
21
  });
19
22
  return app;
20
23
  }
21
- async function renderPreview(c, siteDir, storage, overrides, templatesDir) {
22
- const site = await loadSite({ siteDir, storage, templatesDir });
24
+ async function renderPreview(c, source, overrides, templatesDir) {
25
+ // Empty target (no site.yaml) preview returns a friendly placeholder
26
+ // so the admin can still show the iframe. Happens when the active
27
+ // target is a never-published publish-target.
28
+ let site;
29
+ try {
30
+ site = await loadSiteFromSource(source, { templatesDir });
31
+ }
32
+ catch (err) {
33
+ if (err.message.includes('No site.yaml found')) {
34
+ return c.html('<!doctype html><html><body style="font-family:system-ui;padding:2rem;color:#525252">' +
35
+ '<h2 style="margin:0 0 0.5rem">No content on this target yet</h2>' +
36
+ '<p style="margin:0;font-size:0.875rem">Publish from an editable target to see a preview here.</p>' +
37
+ '</body></html>', 404);
38
+ }
39
+ throw err;
40
+ }
23
41
  const requestPath = c.req.path.replace(/^.*\/preview/, '') || '/';
24
- // Fragment preview: /preview/@fragmentName
25
- if (requestPath.startsWith('/@')) {
26
- const fragmentName = requestPath.slice(2);
42
+ // Fragment preview: /preview/@fragmentName or /preview/fr/@fragmentName
43
+ // Extract locale prefix if present before the @
44
+ let previewLocale;
45
+ let fragRequestPath = requestPath;
46
+ const localeFragMatch = requestPath.match(/^\/([a-z]{2}(?:-[a-z]+)?)\/(@.+)$/);
47
+ if (localeFragMatch) {
48
+ previewLocale = localeFragMatch[1];
49
+ fragRequestPath = `/${localeFragMatch[2]}`;
50
+ }
51
+ if (fragRequestPath.startsWith('/@')) {
52
+ const fragmentName = fragRequestPath.slice(2);
27
53
  try {
28
- const resolved = await resolveFragment(fragmentName, site);
54
+ const resolved = await resolveFragment(fragmentName, site, previewLocale);
29
55
  if (overrides)
30
56
  applyOverrides(resolved, overrides);
31
- return c.html(await renderFragment(resolved));
57
+ return c.html(await renderFragment(resolved, previewLocale));
32
58
  }
33
59
  catch (err) {
34
60
  const e = err;
@@ -37,14 +63,23 @@ async function renderPreview(c, siteDir, storage, overrides, templatesDir) {
37
63
  return c.html(`<div style="font-family:system-ui;padding:2rem;color:#fca5a5;background:#1a1a2e;min-height:100vh"><h2 style="color:#f87171;margin-bottom:1rem">Template Error</h2><pre style="white-space:pre-wrap;font-size:0.875rem;line-height:1.7">${msg}</pre><details style="margin-top:1rem"><summary style="color:#52525b;cursor:pointer">Stack trace</summary><pre style="color:#52525b;font-size:0.75rem;margin-top:0.5rem">${stack}</pre></details></div>`, 500);
38
64
  }
39
65
  }
40
- for (const [pageName, page] of site.pages) {
66
+ for (const { name: pageName, page, locale: pageLocale } of allPageEntries(site)) {
41
67
  const params = matchRoute(page.route, requestPath);
42
68
  if (params) {
43
69
  try {
44
- const resolved = await resolvePage(pageName, site);
70
+ const resolved = await resolvePage(pageName, site, pageLocale);
45
71
  if (overrides)
46
72
  applyOverrides(resolved, overrides);
47
- return c.html(await renderPage(resolved, params));
73
+ return c.html(await renderPage(resolved, {
74
+ routeParams: params,
75
+ metadata: page.metadata,
76
+ route: page.route,
77
+ seo: {
78
+ siteName: site.manifest.name,
79
+ locale: pageLocale ?? site.manifest.locale,
80
+ defaultOgImage: site.manifest.defaultOgImage,
81
+ },
82
+ }));
48
83
  }
49
84
  catch (err) {
50
85
  const e = err;
@@ -1 +1 @@
1
- {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/admin-api/routes/preview.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/admin-api/routes/preview.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Hono } from 'hono';
2
2
  import type { StorageProvider, TargetConfig } from '../../types.js';
3
+ import type { SourceContextResolver } from '../source-context.js';
3
4
  import type { PublishResult } from '../../publish.js';
4
5
  import { type TemplateInfo } from '../../templates-scan.js';
5
6
  /**
@@ -35,5 +36,5 @@ export type PublishProgress = {
35
36
  errors: string[];
36
37
  }[];
37
38
  };
38
- export declare function publishRoutes(siteDir: string, sourceStorage: StorageProvider, preInitTargets?: Map<string, StorageProvider>, targetConfigs?: Record<string, TargetConfig>, templatesDir?: string, scanTemplatesInjected?: (templatesDir: string, projectRoot: string) => Promise<TemplateInfo[]>): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
39
+ export declare function publishRoutes(resolve: SourceContextResolver, preInitTargets?: Map<string, StorageProvider>, targetConfigs?: Record<string, TargetConfig>, templatesDir?: string, scanTemplatesInjected?: (templatesDir: string, projectRoot: string) => Promise<TemplateInfo[]>): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
39
40
  //# sourceMappingURL=publish.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/admin-api/routes/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAInE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAIrD,OAAO,EAAqC,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAG9F;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAAE,CAAA;AAE7F,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,eAAe,EAC9B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC7C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC5C,YAAY,CAAC,EAAE,MAAM,EAIrB,qBAAqB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,8EAmW/F"}
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/admin-api/routes/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAEnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAarD,OAAO,EAAqC,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAM9F;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAAE,CAAA;AAE7F,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,EAC9B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC7C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC5C,YAAY,CAAC,EAAE,MAAM,EAIrB,qBAAqB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,8EAkgB/F"}
@@ -1,38 +1,48 @@
1
1
  import { Hono } from 'hono';
2
2
  import { streamSSE } from 'hono/streaming';
3
- import { getPublishMode, getEnvironment } from '../../types.js';
3
+ import { getType, getEnvironment, isEditable, isHistoryEnabled, getHistoryRetention } from '../../types.js';
4
4
  import { publishItems, resolveDependencies, findFragmentDependents, findDependentsFromSidecars } from '../../publish.js';
5
- import { listSidecars } from '../../sidecars.js';
6
5
  import { mapLimitStream } from '../../concurrency.js';
7
- import { publishPageRendered, publishPageStatic, publishFragmentRendered, publishSiteManifest, publishFragmentIndex, createCloudflarePurge, lookupCloudflareZoneId } from '../../publish-rendered.js';
8
- import { loadSite } from '../../site-loader.js';
6
+ import { publishPageStatic, publishSiteManifest, publishFragmentIndex, createCloudflarePurge, lookupCloudflareZoneId, } from '../../publish-rendered.js';
7
+ import { loadSiteFromSource } from '../source-context.js';
8
+ import { publishPageAllLocales, publishFragmentAllLocales } from '../../publish-locale.js';
9
9
  import { resolveEnvVars } from '../../targets.js';
10
10
  import { scanTemplates, templateHashesFrom } from '../../templates-scan.js';
11
11
  import { hashManifest } from '../../hash.js';
12
- export function publishRoutes(siteDir, sourceStorage, preInitTargets, targetConfigs, templatesDir,
12
+ import { createContentRoot } from '../../content-root.js';
13
+ import { createHistoryProvider } from '../../history-provider.js';
14
+ import { recordWrite } from '../../history-recorder.js';
15
+ export function publishRoutes(resolve, preInitTargets, targetConfigs, templatesDir,
13
16
  // Optional injected scanner — the admin-api server memoizes it and
14
17
  // clears the cache via its template file watcher. Default: fresh scan
15
18
  // on every call (used by the CLI and tests).
16
19
  scanTemplatesInjected) {
17
20
  const scan = scanTemplatesInjected ?? scanTemplates;
18
21
  const app = new Hono();
19
- // Background target initialization
22
+ // Background target initialization — lazy, needs the resolved source's
23
+ // projectSiteDir to resolve filesystem target paths. We call resolve()
24
+ // once with undefined (→ default editable) to obtain projectSiteDir.
20
25
  let targets = preInitTargets ?? null;
21
- const initPromise = preInitTargets
22
- ? Promise.resolve(preInitTargets)
23
- : (!targetConfigs || Object.keys(targetConfigs).length === 0)
24
- ? Promise.resolve(new Map())
25
- : (async () => {
26
- const { createTargetRegistry } = await import('../../targets.js');
27
- targets = await createTargetRegistry(targetConfigs, siteDir);
28
- return targets;
29
- })();
30
- if (!preInitTargets) {
31
- initPromise.then(t => { targets = t; }).catch(() => { targets = new Map(); });
32
- }
26
+ let initPromise = null;
33
27
  async function getTargets() {
34
28
  if (targets)
35
29
  return targets;
30
+ if (!targetConfigs || Object.keys(targetConfigs).length === 0) {
31
+ targets = new Map();
32
+ return targets;
33
+ }
34
+ if (!initPromise) {
35
+ initPromise = (async () => {
36
+ const { createTargetRegistry } = await import('../../targets.js');
37
+ const bootstrapSource = await resolve(undefined);
38
+ const t = await createTargetRegistry(targetConfigs, bootstrapSource.projectSiteDir);
39
+ targets = t;
40
+ return t;
41
+ })().catch(() => {
42
+ targets = new Map();
43
+ return targets;
44
+ });
45
+ }
36
46
  return initPromise;
37
47
  }
38
48
  function getTargetConfig(name) {
@@ -45,7 +55,8 @@ scanTemplatesInjected) {
45
55
  return {
46
56
  name,
47
57
  environment: cfg ? getEnvironment(cfg) : 'local',
48
- publishMode: cfg ? getPublishMode(cfg) : 'static',
58
+ type: cfg ? getType(cfg) : 'static',
59
+ editable: cfg ? isEditable(cfg) : true,
49
60
  };
50
61
  }));
51
62
  });
@@ -70,30 +81,41 @@ scanTemplatesInjected) {
70
81
  return c.json({ error: 'Missing or invalid "item" query (must be fragments/<name>)' }, 400);
71
82
  }
72
83
  const fragmentName = item.slice('fragments/'.length);
84
+ // `target` — specific published target's sidecars (read-only listing).
85
+ // Useful for "what would need republish on staging?" queries
86
+ // where sidecars reflect the last publish, not the draft.
87
+ // `source` — the editable source target (authoritative for the draft).
88
+ // When target === source (common case: client sends the
89
+ // active editable target), route through source so the
90
+ // sidecar writer can backfill missing entries.
73
91
  const targetName = c.req.query('target');
92
+ const sourceName = c.req.query('source');
74
93
  try {
75
- if (targetName) {
94
+ const source = await resolve(sourceName);
95
+ // Treat `target=local` (the active editable target) the same as no
96
+ // target — the source path is the authoritative one for the draft,
97
+ // and it's the only path that knows how to backfill sidecars on a
98
+ // fresh dev server.
99
+ const isTargetTheSource = !targetName || targetName === source.targetName;
100
+ if (!isTargetTheSource) {
76
101
  const t = await getTargets();
77
102
  const targetStorage = t.get(targetName);
78
103
  if (!targetStorage)
79
104
  return c.json({ error: `Unknown target: ${targetName}` }, 400);
80
- const result = await findDependentsFromSidecars(targetStorage, { fragment: fragmentName });
105
+ const result = await findDependentsFromSidecars(createContentRoot(targetStorage), { fragment: fragmentName });
81
106
  return c.json(result);
82
107
  }
83
- // Source-side: prefer sidecars (listings only) when present. If the
84
- // project has any source sidecars, trust them empty means "no
85
- // dependents," not "stale." Fall back to a full manifest scan only
86
- // when sidecars don't exist (e.g. project was never opened in the
87
- // admin UI).
88
- const [pagesList, fragmentsList] = await Promise.all([
89
- listSidecars(sourceStorage, `${siteDir}/pages`),
90
- listSidecars(sourceStorage, `${siteDir}/fragments`),
91
- ]);
92
- if (pagesList.size || fragmentsList.size) {
93
- const result = await findDependentsFromSidecars(sourceStorage, { fragment: fragmentName }, { baseDir: siteDir });
108
+ // Source-side path: ensure every item has a sidecar before reading.
109
+ // The writer memoizes the backfill concurrent tree badges on a
110
+ // fresh dev server share one pass instead of racing to an empty index.
111
+ const sidecarWriter = source.sidecarWriter;
112
+ if (sidecarWriter) {
113
+ await sidecarWriter.ensureBackfilled();
114
+ const result = await findDependentsFromSidecars(source.contentRoot, { fragment: fragmentName });
94
115
  return c.json(result);
95
116
  }
96
- const result = await findFragmentDependents(sourceStorage, siteDir, fragmentName);
117
+ // No writer injected (legacy setup) — fall back to the manifest walker.
118
+ const result = await findFragmentDependents(source.contentRoot, fragmentName);
97
119
  return c.json(result);
98
120
  }
99
121
  catch (err) {
@@ -110,7 +132,7 @@ scanTemplatesInjected) {
110
132
  * Pre-flight validation (unknown targets, invalid templates) is reported as
111
133
  * 'fatal' before any 'target-start' event so callers can map to a 4xx.
112
134
  */
113
- async function* runPublish(items, targetNames) {
135
+ async function* runPublish(items, targetNames, sourceName) {
114
136
  if (!items?.length) {
115
137
  yield { kind: 'fatal', error: 'No items specified' };
116
138
  return;
@@ -119,6 +141,16 @@ scanTemplatesInjected) {
119
141
  yield { kind: 'fatal', error: 'No targets specified' };
120
142
  return;
121
143
  }
144
+ // Resolve the source editable target for this publish run.
145
+ let source;
146
+ try {
147
+ source = await resolve(sourceName);
148
+ }
149
+ catch (err) {
150
+ yield { kind: 'fatal', error: err.message };
151
+ return;
152
+ }
153
+ const { projectSiteDir } = source;
122
154
  const t = await getTargets();
123
155
  for (const name of targetNames) {
124
156
  if (!t.has(name)) {
@@ -126,12 +158,12 @@ scanTemplatesInjected) {
126
158
  return;
127
159
  }
128
160
  }
129
- const allItems = await resolveDependencies(sourceStorage, siteDir, items);
161
+ const allItems = await resolveDependencies(source.contentRoot, items);
130
162
  console.log(` Publishing to ${targetNames.length} target(s):`);
131
163
  console.log(` Items: ${items.join(', ')} (+ ${allItems.length - items.length} dependencies)`);
132
164
  console.log(` Targets: ${targetNames.join(', ')}`);
133
- const tdir = templatesDir ?? `${siteDir}/templates`;
134
- const projectRoot = siteDir.replace(/\/sites\/[^/]+$/, '');
165
+ const tdir = templatesDir ?? `${projectSiteDir}/templates`;
166
+ const projectRoot = projectSiteDir.replace(/\/sites\/[^/]+$/, '');
135
167
  const templateInfos = await scan(tdir, projectRoot);
136
168
  const invalidTpls = templateInfos.filter(t => !t.valid);
137
169
  if (invalidTpls.length) {
@@ -143,13 +175,13 @@ scanTemplatesInjected) {
143
175
  return;
144
176
  }
145
177
  const templateHashes = templateHashesFrom(templateInfos);
146
- const site = await loadSite({ siteDir, storage: sourceStorage, templatesDir: tdir });
178
+ const site = await loadSiteFromSource(source, { templatesDir: tdir });
147
179
  yield { kind: 'start', targets: targetNames, itemsPerTarget: allItems.length };
148
180
  const results = [];
149
181
  for (const targetName of targetNames) {
150
182
  const targetStorage = t.get(targetName);
151
183
  const config = getTargetConfig(targetName);
152
- const isStatic = config ? getPublishMode(config) === 'static' : true;
184
+ const isStatic = config ? getType(config) === 'static' : true;
153
185
  const purgeConfig = config?.cache?.purge;
154
186
  // Static mode bakes fragments into pages at publish time — if the user
155
187
  // picked @header, we must also republish every page that uses it.
@@ -161,7 +193,7 @@ scanTemplatesInjected) {
161
193
  const expanded = new Set(allItems);
162
194
  for (const frag of fragmentItems) {
163
195
  const name = frag.replace('fragments/', '');
164
- const deps = await findFragmentDependents(sourceStorage, siteDir, name);
196
+ const deps = await findFragmentDependents(source.contentRoot, name);
165
197
  for (const p of deps.pages)
166
198
  expanded.add(`pages/${p}`);
167
199
  }
@@ -174,8 +206,35 @@ scanTemplatesInjected) {
174
206
  let current = 0;
175
207
  try {
176
208
  let totalFiles = 0;
209
+ const targetRoot = createContentRoot(targetStorage);
210
+ // History must record BEFORE the writes so the baseline
211
+ // revision (emitted automatically by recordWrite on the first
212
+ // call against this target) captures pre-publish state.
213
+ // Otherwise "undo this publish" would restore the post-
214
+ // publish state and no-op. See pages.ts save handler.
215
+ if (config && isHistoryEnabled(config)) {
216
+ try {
217
+ const history = createHistoryProvider({
218
+ storage: targetStorage,
219
+ retention: getHistoryRetention(config),
220
+ });
221
+ const items = await collectPublishedItemsForHistory(source.contentRoot, targetRoot, targetItems);
222
+ await recordWrite({
223
+ history,
224
+ contentRoot: targetRoot,
225
+ operation: 'publish',
226
+ source: sourceName,
227
+ items,
228
+ });
229
+ }
230
+ catch (err) {
231
+ // History is a best-effort audit layer — a write failure
232
+ // here must not break the publish itself.
233
+ console.warn(` ${targetName}: history record failed — ${err.message}`);
234
+ }
235
+ }
177
236
  // 1. Source copy
178
- const { copiedFiles } = await publishItems(sourceStorage, siteDir, targetStorage, '', targetItems);
237
+ const { copiedFiles } = await publishItems(source.contentRoot, targetRoot, targetItems);
179
238
  totalFiles += copiedFiles;
180
239
  current++;
181
240
  yield { kind: 'progress', target: targetName, current, total, label: 'source files' };
@@ -194,22 +253,33 @@ scanTemplatesInjected) {
194
253
  }
195
254
  }
196
255
  const pageHashOpts = isStatic ? { templateHashes, fragmentHashes } : { templateHashes };
256
+ // SEO context for this target — built once, shared across all page renders.
257
+ const seo = {
258
+ siteName: site.manifest.name,
259
+ siteUrl: config?.siteUrl,
260
+ locale: site.manifest.locale,
261
+ defaultOgImage: site.manifest.defaultOgImage,
262
+ };
197
263
  const renderItem = async (item) => {
198
264
  if (item.startsWith('pages/')) {
199
- const pageName = item.replace('pages/', '');
265
+ const raw = item.replace('pages/', '');
266
+ // Support locale-qualified items: pages/home:fr → publish only FR
267
+ const [pageName, itemLocale] = raw.includes(':') ? raw.split(':') : [raw, undefined];
200
268
  const page = site.pages.get(pageName);
201
269
  const manifestHash = page ? hashManifest(page, pageHashOpts) : undefined;
202
270
  if (isStatic) {
203
- return publishPageStatic(pageName, sourceStorage, siteDir, targetStorage, tdir, manifestHash, site);
271
+ return publishPageStatic(pageName, source.contentRoot, targetStorage, tdir, manifestHash, site, seo, itemLocale);
204
272
  }
205
- const { files } = await publishPageRendered(pageName, sourceStorage, siteDir, targetStorage, config?.cache, tdir, manifestHash, site);
273
+ // When a specific locale is requested, only publish that one
274
+ const onlyLocales = itemLocale ? [itemLocale] : undefined;
275
+ const { files } = await publishPageAllLocales(pageName, source.contentRoot, targetStorage, site, pageHashOpts, { cache: config?.cache, templatesDir: tdir, seo, targetLocales: onlyLocales ?? config?.locales });
206
276
  return { files };
207
277
  }
208
278
  if (item.startsWith('fragments/') && !isStatic) {
209
- const fragName = item.replace('fragments/', '');
210
- const frag = site.fragments.get(fragName);
211
- const manifestHash = frag ? hashManifest(frag, { templateHashes }) : undefined;
212
- const { files } = await publishFragmentRendered(fragName, sourceStorage, siteDir, targetStorage, tdir, manifestHash, site);
279
+ const raw = item.replace('fragments/', '');
280
+ const [fragName, itemLocale] = raw.includes(':') ? raw.split(':') : [raw, undefined];
281
+ const onlyLocales = itemLocale ? [itemLocale] : undefined;
282
+ const { files } = await publishFragmentAllLocales(fragName, source.contentRoot, targetStorage, site, { templateHashes }, { templatesDir: tdir, targetLocales: onlyLocales ?? config?.locales });
213
283
  return { files };
214
284
  }
215
285
  return { files: 0 }; // skipped (e.g. fragment on static target)
@@ -222,15 +292,46 @@ scanTemplatesInjected) {
222
292
  yield { kind: 'progress', target: targetName, current, total, label: item };
223
293
  }
224
294
  // 3. Site manifest + fragment index
225
- await publishSiteManifest(sourceStorage, siteDir, targetStorage, site);
226
- await publishFragmentIndex(sourceStorage, siteDir, targetStorage, site);
295
+ await publishSiteManifest(source.contentRoot, targetStorage, site);
296
+ await publishFragmentIndex(source.contentRoot, targetStorage, site);
227
297
  totalFiles += 2;
228
298
  current++;
229
299
  yield { kind: 'progress', target: targetName, current, total, label: 'site manifest' };
300
+ // 3b. Sitemap + robots.txt
301
+ const siteUrl = config?.siteUrl;
302
+ if (siteUrl) {
303
+ const { listSidecars } = await import('../../sidecars.js');
304
+ const { generateSitemap } = await import('../../sitemap.js');
305
+ const { generateRobotsTxt } = await import('../../robots.js');
306
+ const targetPageSidecars = await listSidecars(targetStorage, 'pages');
307
+ const sitemapXml = generateSitemap({
308
+ siteUrl,
309
+ pages: targetPageSidecars,
310
+ systemPages: site.manifest.systemPages,
311
+ });
312
+ if (sitemapXml) {
313
+ await targetStorage.writeFile('sitemap.xml', sitemapXml);
314
+ totalFiles++;
315
+ }
316
+ // robots.txt only at domain root — Google ignores it at subpaths.
317
+ const isRootDeploy = !new URL(siteUrl).pathname.replace(/\/+$/, '');
318
+ if (isRootDeploy) {
319
+ let robotsTxt;
320
+ try {
321
+ robotsTxt = await source.contentRoot.storage.readFile(source.contentRoot.path('robots.txt'));
322
+ }
323
+ catch {
324
+ robotsTxt = generateRobotsTxt({ siteUrl });
325
+ }
326
+ await targetStorage.writeFile('robots.txt', robotsTxt);
327
+ totalFiles++;
328
+ }
329
+ }
230
330
  // 4. Purge CDN cache
231
331
  if (purgeConfig?.type === 'cloudflare') {
232
332
  const apiToken = resolveEnvVars(purgeConfig.apiToken);
233
- const zoneId = resolveEnvVars(purgeConfig.zoneId) ?? (config?.siteUrl && apiToken ? await lookupCloudflareZoneId(config.siteUrl, apiToken) : null);
333
+ const zoneId = resolveEnvVars(purgeConfig.zoneId) ??
334
+ (config?.siteUrl && apiToken ? await lookupCloudflareZoneId(config.siteUrl, apiToken) : null);
234
335
  if (apiToken && zoneId) {
235
336
  const purge = createCloudflarePurge(zoneId, apiToken);
236
337
  const hasFragments = targetItems.some(i => i.startsWith('fragments/'));
@@ -239,14 +340,16 @@ scanTemplatesInjected) {
239
340
  console.log(` ${targetName}: cache purged (all)`);
240
341
  }
241
342
  else if (config?.siteUrl) {
242
- const siteForUrls = await loadSite({ siteDir, storage: sourceStorage, templatesDir });
243
- const urls = targetItems
244
- .filter(i => i.startsWith('pages/'))
245
- .map(i => {
246
- const page = siteForUrls.pages.get(i.replace('pages/', ''));
247
- return page ? `${config.siteUrl}${page.route}` : null;
248
- })
249
- .filter(Boolean);
343
+ const siteForUrls = await loadSiteFromSource(source, { templatesDir });
344
+ const publishedPageNames = new Set(targetItems.filter(i => i.startsWith('pages/')).map(i => i.replace('pages/', '')));
345
+ // Collect URLs for all published pages including locale variants
346
+ const urls = [];
347
+ const { allPageEntries } = await import('../../site-loader.js');
348
+ for (const { name, page } of allPageEntries(siteForUrls)) {
349
+ if (publishedPageNames.has(name)) {
350
+ urls.push(`${config.siteUrl}${page.route}`);
351
+ }
352
+ }
250
353
  if (urls.length > 0) {
251
354
  await purge.purgeUrls(urls);
252
355
  console.log(` ${targetName}: cache purged (${urls.join(', ')})`);
@@ -272,10 +375,10 @@ scanTemplatesInjected) {
272
375
  yield { kind: 'done', results };
273
376
  }
274
377
  app.post('/api/publish', async (c) => {
275
- const body = await c.req.json();
378
+ const body = (await c.req.json());
276
379
  let results = [];
277
380
  let fatal = null;
278
- for await (const ev of runPublish(body.items, body.targets)) {
381
+ for await (const ev of runPublish(body.items, body.targets, body.source)) {
279
382
  if (ev.kind === 'fatal')
280
383
  fatal = ev;
281
384
  else if (ev.kind === 'done')
@@ -289,10 +392,10 @@ scanTemplatesInjected) {
289
392
  return c.json({ results }, allSuccess ? 200 : 207);
290
393
  });
291
394
  app.post('/api/publish/stream', async (c) => {
292
- const body = await c.req.json();
395
+ const body = (await c.req.json());
293
396
  return streamSSE(c, async (stream) => {
294
397
  try {
295
- for await (const ev of runPublish(body.items, body.targets)) {
398
+ for await (const ev of runPublish(body.items, body.targets, body.source)) {
296
399
  if (stream.aborted)
297
400
  return;
298
401
  await stream.writeSSE({ event: ev.kind, data: JSON.stringify(ev) });
@@ -300,19 +403,33 @@ scanTemplatesInjected) {
300
403
  }
301
404
  catch (err) {
302
405
  if (!stream.aborted) {
303
- await stream.writeSSE({ event: 'fatal', data: JSON.stringify({ kind: 'fatal', error: err.message }) });
406
+ await stream.writeSSE({
407
+ event: 'fatal',
408
+ data: JSON.stringify({ kind: 'fatal', error: err.message }),
409
+ });
304
410
  }
305
411
  }
306
412
  });
307
413
  });
308
414
  app.post('/api/fetch', async (c) => {
309
- const body = await c.req.json();
415
+ // `source` (body) target to fetch FROM (a published target)
416
+ // `destination` (body) — optional editable target to write INTO; defaults
417
+ // to the resolver's default editable target (the author's current source)
418
+ const body = (await c.req.json());
310
419
  if (!body.source)
311
420
  return c.json({ error: 'Missing "source" target name' }, 400);
312
421
  const t = await getTargets();
313
422
  const targetStorage = t.get(body.source);
314
423
  if (!targetStorage)
315
424
  return c.json({ error: `Unknown target: ${body.source}` }, 400);
425
+ // Resolve the destination editable target for this fetch.
426
+ let destination;
427
+ try {
428
+ destination = await resolve(body.destination);
429
+ }
430
+ catch (err) {
431
+ return c.json({ error: err.message }, 400);
432
+ }
316
433
  let items;
317
434
  if (body.items?.length) {
318
435
  items = body.items;
@@ -351,7 +468,8 @@ scanTemplatesInjected) {
351
468
  console.log(` Fetching ${items.length} items from "${body.source}":`);
352
469
  console.log(` Items: ${items.join(', ')}`);
353
470
  try {
354
- const { copiedFiles } = await publishItems(targetStorage, '', sourceStorage, siteDir, items);
471
+ const targetRoot = createContentRoot(targetStorage);
472
+ const { copiedFiles } = await publishItems(targetRoot, destination.contentRoot, items);
355
473
  console.log(` ${copiedFiles} files copied to working copy`);
356
474
  return c.json({ success: true, copiedFiles, items });
357
475
  }
@@ -363,4 +481,33 @@ scanTemplatesInjected) {
363
481
  });
364
482
  return app;
365
483
  }
484
+ /**
485
+ * Build the history `items` for a publish — one entry per published
486
+ * item, content = the source-side manifest. Records semantic authored
487
+ * state (JSON manifests) rather than target-side artifacts (static
488
+ * HTML, fragment indexes), so Restore is a content-level operation.
489
+ *
490
+ * `_targetRoot` is accepted for symmetry with `recordWrite`'s other
491
+ * path-building needs; it's unused today because we hash source
492
+ * content directly and let recordWrite overlay paths relative to the
493
+ * target's rootPath (which is `''` for target-rooted storage, the
494
+ * common case).
495
+ */
496
+ async function collectPublishedItemsForHistory(sourceRoot, _targetRoot, publishedItems) {
497
+ const out = [];
498
+ for (const item of publishedItems) {
499
+ const manifestName = item.startsWith('pages/') ? 'page.json' : 'fragment.json';
500
+ const key = `${item}/${manifestName}`;
501
+ const sourcePath = sourceRoot.path(key);
502
+ try {
503
+ const content = await sourceRoot.storage.readFile(sourcePath);
504
+ out.push({ path: key, content });
505
+ }
506
+ catch {
507
+ // Item missing on source (unusual — publish normally reads from
508
+ // source manifests). Skip; snapshot stays as-was for this item.
509
+ }
510
+ }
511
+ return out;
512
+ }
366
513
  //# sourceMappingURL=publish.js.map