@caretcms/core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +117 -6
  2. package/dist/browser-runtime.d.ts.map +1 -1
  3. package/dist/browser-runtime.js +34 -20
  4. package/dist/browser-runtime.js.map +1 -1
  5. package/dist/contracts.d.ts +14 -0
  6. package/dist/contracts.d.ts.map +1 -0
  7. package/dist/contracts.js +14 -0
  8. package/dist/contracts.js.map +1 -0
  9. package/dist/editable.d.ts +28 -0
  10. package/dist/editable.d.ts.map +1 -0
  11. package/dist/editable.js +122 -0
  12. package/dist/editable.js.map +1 -0
  13. package/dist/index.d.ts +30 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +134 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/loader.d.ts.map +1 -1
  18. package/dist/loader.js +45 -3
  19. package/dist/loader.js.map +1 -1
  20. package/dist/providers/storage/markdown.d.ts +7 -0
  21. package/dist/providers/storage/markdown.d.ts.map +1 -0
  22. package/dist/providers/storage/markdown.js +6 -0
  23. package/dist/providers/storage/markdown.js.map +1 -0
  24. package/dist/runtime/auth/cookie-utils.d.ts +1 -0
  25. package/dist/runtime/auth/cookie-utils.d.ts.map +1 -1
  26. package/dist/runtime/auth/cookie-utils.js +1 -1
  27. package/dist/runtime/auth/cookie-utils.js.map +1 -1
  28. package/dist/runtime/auth/rate-limiter.d.ts.map +1 -1
  29. package/dist/runtime/auth/rate-limiter.js +19 -13
  30. package/dist/runtime/auth/rate-limiter.js.map +1 -1
  31. package/dist/runtime/auth/session.d.ts +8 -0
  32. package/dist/runtime/auth/session.d.ts.map +1 -1
  33. package/dist/runtime/auth/session.js +72 -11
  34. package/dist/runtime/auth/session.js.map +1 -1
  35. package/dist/runtime/config.d.ts +1 -0
  36. package/dist/runtime/config.d.ts.map +1 -1
  37. package/dist/runtime/config.js +2 -1
  38. package/dist/runtime/config.js.map +1 -1
  39. package/dist/runtime/git-journal.d.ts +19 -0
  40. package/dist/runtime/git-journal.d.ts.map +1 -0
  41. package/dist/runtime/git-journal.js +64 -0
  42. package/dist/runtime/git-journal.js.map +1 -0
  43. package/dist/runtime/index.d.ts +1 -1
  44. package/dist/runtime/index.d.ts.map +1 -1
  45. package/dist/runtime/index.js +1 -1
  46. package/dist/runtime/index.js.map +1 -1
  47. package/dist/runtime/middleware.d.ts.map +1 -1
  48. package/dist/runtime/middleware.js +125 -8
  49. package/dist/runtime/middleware.js.map +1 -1
  50. package/dist/runtime/mutations/contracts.d.ts.map +1 -1
  51. package/dist/runtime/mutations/contracts.js +7 -4
  52. package/dist/runtime/mutations/contracts.js.map +1 -1
  53. package/dist/runtime/mutations/engine.d.ts +7 -0
  54. package/dist/runtime/mutations/engine.d.ts.map +1 -1
  55. package/dist/runtime/mutations/engine.js +30 -17
  56. package/dist/runtime/mutations/engine.js.map +1 -1
  57. package/dist/runtime/providers.d.ts +7 -0
  58. package/dist/runtime/providers.d.ts.map +1 -1
  59. package/dist/runtime/providers.js +10 -0
  60. package/dist/runtime/providers.js.map +1 -1
  61. package/dist/runtime/publish.d.ts +38 -0
  62. package/dist/runtime/publish.d.ts.map +1 -0
  63. package/dist/runtime/publish.js +71 -0
  64. package/dist/runtime/publish.js.map +1 -0
  65. package/dist/runtime/request-context.d.ts +19 -0
  66. package/dist/runtime/request-context.d.ts.map +1 -1
  67. package/dist/runtime/request-context.js.map +1 -1
  68. package/dist/runtime/rewrite.d.ts +11 -1
  69. package/dist/runtime/rewrite.d.ts.map +1 -1
  70. package/dist/runtime/rewrite.js +21 -15
  71. package/dist/runtime/rewrite.js.map +1 -1
  72. package/dist/runtime/rich-allowlist.d.ts +28 -0
  73. package/dist/runtime/rich-allowlist.d.ts.map +1 -0
  74. package/dist/runtime/rich-allowlist.js +43 -0
  75. package/dist/runtime/rich-allowlist.js.map +1 -0
  76. package/dist/runtime/routes/_helpers.d.ts +26 -0
  77. package/dist/runtime/routes/_helpers.d.ts.map +1 -1
  78. package/dist/runtime/routes/_helpers.js +83 -0
  79. package/dist/runtime/routes/_helpers.js.map +1 -1
  80. package/dist/runtime/routes/admin.d.ts.map +1 -1
  81. package/dist/runtime/routes/admin.js +55 -6
  82. package/dist/runtime/routes/admin.js.map +1 -1
  83. package/dist/runtime/routes/auth-login.d.ts.map +1 -1
  84. package/dist/runtime/routes/auth-login.js +25 -8
  85. package/dist/runtime/routes/auth-login.js.map +1 -1
  86. package/dist/runtime/routes/auth-logout.d.ts.map +1 -1
  87. package/dist/runtime/routes/auth-logout.js +4 -0
  88. package/dist/runtime/routes/auth-logout.js.map +1 -1
  89. package/dist/runtime/routes/collections-metadata.d.ts.map +1 -1
  90. package/dist/runtime/routes/collections-metadata.js +4 -2
  91. package/dist/runtime/routes/collections-metadata.js.map +1 -1
  92. package/dist/runtime/routes/draft.d.ts +8 -0
  93. package/dist/runtime/routes/draft.d.ts.map +1 -0
  94. package/dist/runtime/routes/draft.js +38 -0
  95. package/dist/runtime/routes/draft.js.map +1 -0
  96. package/dist/runtime/routes/history.d.ts.map +1 -1
  97. package/dist/runtime/routes/history.js +21 -8
  98. package/dist/runtime/routes/history.js.map +1 -1
  99. package/dist/runtime/routes/mutate.d.ts.map +1 -1
  100. package/dist/runtime/routes/mutate.js +5 -9
  101. package/dist/runtime/routes/mutate.js.map +1 -1
  102. package/dist/runtime/routes/publish.d.ts +9 -0
  103. package/dist/runtime/routes/publish.d.ts.map +1 -0
  104. package/dist/runtime/routes/publish.js +66 -0
  105. package/dist/runtime/routes/publish.js.map +1 -0
  106. package/dist/runtime/routes/schema.d.ts.map +1 -1
  107. package/dist/runtime/routes/schema.js +4 -2
  108. package/dist/runtime/routes/schema.js.map +1 -1
  109. package/dist/runtime/routes/upload.d.ts.map +1 -1
  110. package/dist/runtime/routes/upload.js +16 -3
  111. package/dist/runtime/routes/upload.js.map +1 -1
  112. package/dist/runtime/sanitize-html.d.ts +8 -2
  113. package/dist/runtime/sanitize-html.d.ts.map +1 -1
  114. package/dist/runtime/sanitize-html.js +57 -38
  115. package/dist/runtime/sanitize-html.js.map +1 -1
  116. package/dist/runtime/stega.d.ts +38 -0
  117. package/dist/runtime/stega.d.ts.map +1 -0
  118. package/dist/runtime/stega.js +98 -0
  119. package/dist/runtime/stega.js.map +1 -0
  120. package/dist/runtime/storage/atomic-write.d.ts +22 -0
  121. package/dist/runtime/storage/atomic-write.d.ts.map +1 -0
  122. package/dist/runtime/storage/atomic-write.js +44 -0
  123. package/dist/runtime/storage/atomic-write.js.map +1 -0
  124. package/dist/runtime/storage/filesystem-adapter.d.ts +14 -11
  125. package/dist/runtime/storage/filesystem-adapter.d.ts.map +1 -1
  126. package/dist/runtime/storage/filesystem-adapter.js +71 -201
  127. package/dist/runtime/storage/filesystem-adapter.js.map +1 -1
  128. package/dist/runtime/storage/frontmatter-codec.d.ts +47 -0
  129. package/dist/runtime/storage/frontmatter-codec.d.ts.map +1 -0
  130. package/dist/runtime/storage/frontmatter-codec.js +515 -0
  131. package/dist/runtime/storage/frontmatter-codec.js.map +1 -0
  132. package/dist/runtime/storage/fs-runtime.d.ts +8 -0
  133. package/dist/runtime/storage/fs-runtime.d.ts.map +1 -0
  134. package/dist/runtime/storage/fs-runtime.js +40 -0
  135. package/dist/runtime/storage/fs-runtime.js.map +1 -0
  136. package/dist/runtime/storage/id-contracts.d.ts +22 -0
  137. package/dist/runtime/storage/id-contracts.d.ts.map +1 -0
  138. package/dist/runtime/storage/id-contracts.js +27 -0
  139. package/dist/runtime/storage/id-contracts.js.map +1 -0
  140. package/dist/runtime/storage/image-validation.d.ts +10 -0
  141. package/dist/runtime/storage/image-validation.d.ts.map +1 -1
  142. package/dist/runtime/storage/image-validation.js +17 -4
  143. package/dist/runtime/storage/image-validation.js.map +1 -1
  144. package/dist/runtime/storage/in-memory-adapter.d.ts +4 -0
  145. package/dist/runtime/storage/in-memory-adapter.d.ts.map +1 -1
  146. package/dist/runtime/storage/in-memory-adapter.js +11 -0
  147. package/dist/runtime/storage/in-memory-adapter.js.map +1 -1
  148. package/dist/runtime/storage/markdown-adapter.d.ts +63 -0
  149. package/dist/runtime/storage/markdown-adapter.d.ts.map +1 -0
  150. package/dist/runtime/storage/markdown-adapter.js +227 -0
  151. package/dist/runtime/storage/markdown-adapter.js.map +1 -0
  152. package/dist/runtime/storage/quota-upload-handler.d.ts +2 -0
  153. package/dist/runtime/storage/quota-upload-handler.d.ts.map +1 -1
  154. package/dist/runtime/storage/quota-upload-handler.js +34 -8
  155. package/dist/runtime/storage/quota-upload-handler.js.map +1 -1
  156. package/dist/runtime/storage/session-overlay-adapter.d.ts +3 -0
  157. package/dist/runtime/storage/session-overlay-adapter.d.ts.map +1 -1
  158. package/dist/runtime/storage/session-overlay-adapter.js +3 -1
  159. package/dist/runtime/storage/session-overlay-adapter.js.map +1 -1
  160. package/dist/runtime/storage/sidecar-meta-store.d.ts +51 -0
  161. package/dist/runtime/storage/sidecar-meta-store.d.ts.map +1 -0
  162. package/dist/runtime/storage/sidecar-meta-store.js +209 -0
  163. package/dist/runtime/storage/sidecar-meta-store.js.map +1 -0
  164. package/dist/runtime/themes/preset-tokens.d.ts +0 -1
  165. package/dist/runtime/themes/preset-tokens.d.ts.map +1 -1
  166. package/dist/runtime/themes/preset-tokens.js +1 -1
  167. package/dist/runtime/themes/preset-tokens.js.map +1 -1
  168. package/dist/runtime/utils.d.ts +9 -1
  169. package/dist/runtime/utils.d.ts.map +1 -1
  170. package/dist/runtime/utils.js +21 -1
  171. package/dist/runtime/utils.js.map +1 -1
  172. package/dist/schema-utils.d.ts.map +1 -1
  173. package/dist/schema-utils.js +1 -0
  174. package/dist/schema-utils.js.map +1 -1
  175. package/dist/types.d.ts +17 -0
  176. package/dist/types.d.ts.map +1 -1
  177. package/package.json +9 -1
  178. package/static/cms/dev-toolbar/app.js +263 -0
  179. package/static/cms/editor/highlight.js +46 -0
  180. package/static/cms/editor/sanitize.js +48 -5
  181. package/static/cms/editor/stega-hydrate.js +80 -0
  182. package/static/cms/editor/text-edit.js +22 -0
  183. package/static/cms/editor/tokens-and-text.css +1 -1
  184. package/static/cms/editor/toolbar.css +42 -0
  185. package/static/cms/editor/toolbar.js +97 -15
  186. package/static/cms/editor.js +15 -0
  187. package/static/cms/signin-hint.css +74 -0
  188. package/dist/runtime/schema/template.d.ts +0 -15
  189. package/dist/runtime/schema/template.d.ts.map +0 -1
  190. package/dist/runtime/schema/template.js +0 -38
  191. package/dist/runtime/schema/template.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"history.js","sourceRoot":"","sources":["../../../src/runtime/routes/history.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../../src/runtime/routes/history.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mutate.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAahE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqBjE"}
1
+ {"version":3,"file":"mutate.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAahE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiBjE"}
@@ -1,7 +1,7 @@
1
1
  import { isEditorAuthenticated } from "../auth/session.js";
2
2
  import { getRuntimeConfig } from "../config.js";
3
3
  import { executeMutation } from "../mutations/engine.js";
4
- import { json, getAdapter, enforceCsrfHeader } from "./_helpers.js";
4
+ import { json, getAdapter, enforceCsrfHeader, readJsonBody } from "./_helpers.js";
5
5
  export async function GET(context) {
6
6
  const runtime = getRuntimeConfig();
7
7
  if (!isEditorAuthenticated(context)) {
@@ -21,15 +21,11 @@ export async function POST(context) {
21
21
  if (!isEditorAuthenticated(context)) {
22
22
  return json({ error: "Unauthorized" }, 401);
23
23
  }
24
- let body;
25
- try {
26
- body = await context.request.json();
27
- }
28
- catch {
29
- return json({ error: "Invalid JSON" }, 400);
30
- }
24
+ const parsed = await readJsonBody(context.request);
25
+ if (!parsed.ok)
26
+ return parsed.response;
31
27
  const adapter = getAdapter();
32
- const result = await executeMutation(adapter, body);
28
+ const result = await executeMutation(adapter, parsed.value);
33
29
  if (!result.ok) {
34
30
  return json(result.body, result.status);
35
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAmB;IAC3C,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IAEnC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,IAAI,CAAC;QACV,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,GAAG,OAAO,CAAC,WAAW,SAAS;QACtC,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,wEAAwE;KAC/E,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAmB;IAC5C,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,IAA+B,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,IAA+B,EAAE,GAAG,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAmB;IAC3C,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IAEnC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,IAAI,CAAC;QACV,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,GAAG,OAAO,CAAC,WAAW,SAAS;QACtC,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,wEAAwE;KAC/E,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAmB;IAC5C,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAEvC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,IAA+B,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,IAA+B,EAAE,GAAG,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { APIContext } from "astro";
2
+ /**
3
+ * POST /api/cms/publish — flush the current editor's draft overlay into the base.
4
+ * Body: `{ collection?, id? }` to scope to one entry/collection, or `{}` for all.
5
+ * Returns the published entries with their NEW base revisions so the editor
6
+ * client can reconcile its revision cache (avoiding a post-publish 409).
7
+ */
8
+ export declare function POST(context: APIContext): Promise<Response>;
9
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/publish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAaxC;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgDjE"}
@@ -0,0 +1,66 @@
1
+ import { isEditorAuthenticated, getEditorId } from "../auth/session.js";
2
+ import { getRuntimeServices } from "../providers.js";
3
+ import { publishOverlay } from "../publish.js";
4
+ import { isGitRepo, commitPaths } from "../git-journal.js";
5
+ import { json, enforceCsrfHeader, readJsonBody } from "./_helpers.js";
6
+ function commitMessage(scope, count) {
7
+ if (scope.collection && scope.id)
8
+ return `publish ${scope.collection}/${scope.id}`;
9
+ if (scope.collection)
10
+ return `publish ${scope.collection} (${count})`;
11
+ return `publish content (${count} ${count === 1 ? "entry" : "entries"})`;
12
+ }
13
+ /**
14
+ * POST /api/cms/publish — flush the current editor's draft overlay into the base.
15
+ * Body: `{ collection?, id? }` to scope to one entry/collection, or `{}` for all.
16
+ * Returns the published entries with their NEW base revisions so the editor
17
+ * client can reconcile its revision cache (avoiding a post-publish 409).
18
+ */
19
+ export async function POST(context) {
20
+ const csrf = enforceCsrfHeader(context.request);
21
+ if (csrf)
22
+ return csrf;
23
+ if (!isEditorAuthenticated(context))
24
+ return json({ error: "Unauthorized" }, 401);
25
+ const editorId = getEditorId(context);
26
+ if (!editorId)
27
+ return json({ error: "No editor draft session" }, 400);
28
+ const parsed = await readJsonBody(context.request);
29
+ if (!parsed.ok)
30
+ return parsed.response;
31
+ const body = (parsed.value ?? {});
32
+ const scope = {};
33
+ if (typeof body.collection === "string")
34
+ scope.collection = body.collection;
35
+ if (typeof body.id === "string")
36
+ scope.id = body.id;
37
+ if (scope.id && !scope.collection) {
38
+ return json({ error: "id requires a collection" }, 400);
39
+ }
40
+ const { adapter: base } = await getRuntimeServices();
41
+ if (!base.makeEditorOverlay) {
42
+ return json({ error: "Drafts are not supported by the configured storage adapter" }, 400);
43
+ }
44
+ const overlay = await base.makeEditorOverlay(editorId);
45
+ const published = await publishOverlay(base, overlay, scope);
46
+ // Best-effort git journal (opt-in via CARET_GIT_ON_PUBLISH): turn the publish
47
+ // into a commit when content lives in a git repo. Runs AFTER the publish, so a
48
+ // git failure never blocks or reverts it; no-ops on non-filesystem adapters.
49
+ let commit = null;
50
+ if (published.length > 0 &&
51
+ process.env.CARET_GIT_ON_PUBLISH === "true" &&
52
+ base.committablePath) {
53
+ const cwd = process.cwd();
54
+ if (await isGitRepo(cwd)) {
55
+ commit = await commitPaths({
56
+ cwd,
57
+ paths: [base.committablePath()],
58
+ message: commitMessage(scope, published.length),
59
+ authorName: `CaretCMS editor ${editorId.slice(0, 8)}`,
60
+ authorEmail: "editor@caretcms.local",
61
+ });
62
+ }
63
+ }
64
+ return json({ ok: true, published, commit });
65
+ }
66
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/runtime/routes/publish.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAOxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyDhE"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4DhE"}
@@ -1,7 +1,6 @@
1
1
  import { isEditorAuthenticated } from "../auth/session.js";
2
2
  import { getRegisteredSchema } from "../schema-registry.js";
3
3
  import { inferJsonSchema, buildTemplate } from "../../schema-utils.js";
4
- import { generateTemplateFromSchema } from "../schema/template.js";
5
4
  import { json, getAdapter } from "./_helpers.js";
6
5
  export async function GET(context) {
7
6
  if (!isEditorAuthenticated(context)) {
@@ -27,7 +26,10 @@ export async function GET(context) {
27
26
  // 2. Check for dynamic schema (from collection metadata)
28
27
  const metadata = await adapter.getCollectionMetadata(collectionRaw);
29
28
  if (metadata?.schema) {
30
- const template = generateTemplateFromSchema(metadata.schema);
29
+ // Same builder as the inferred-schema path below: the default new-entry
30
+ // shape must not depend on HOW a collection came to exist (a second flat
31
+ // builder used to seed enums/integers/nested objects differently).
32
+ const template = buildTemplate(metadata.schema) ?? {};
31
33
  return json({
32
34
  schema: metadata.schema,
33
35
  template,
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/runtime/routes/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAmB;IAC3C,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;SACrE,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;IAED,oEAAoE;IACpE,MAAM,UAAU,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IACtD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;YACV,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,UAAU,EAAE,aAAa;YACzB,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;IACL,CAAC;IAED,yDAAyD;IACzD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACpE,IAAI,QAAQ,EAAE,MAAM,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,0BAA0B,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;YACV,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,QAAQ;YACR,UAAU,EAAE,aAAa;YACzB,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE;gBACR,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,WAAW,EAAE,QAAQ,CAAC,WAAW;gBACjC,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,SAAS,EAAE,QAAQ,CAAC,SAAS;aAC9B;SACF,CAAC,CAAC;IACL,CAAC;IAED,oDAAoD;IACpD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IAE1C,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAEvC,OAAO,IAAI,CAAC;QACV,MAAM;QACN,QAAQ;QACR,UAAU,EAAE,aAAa;QACzB,MAAM,EAAE,UAAU;QAClB,YAAY,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;KACxD,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/runtime/routes/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAmB;IAC3C,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;SACrE,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;IAED,oEAAoE;IACpE,MAAM,UAAU,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IACtD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;YACV,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,UAAU,EAAE,aAAa;YACzB,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;IACL,CAAC;IAED,yDAAyD;IACzD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACpE,IAAI,QAAQ,EAAE,MAAM,EAAE,CAAC;QACrB,wEAAwE;QACxE,yEAAyE;QACzE,mEAAmE;QACnE,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC;YACV,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,QAAQ;YACR,UAAU,EAAE,aAAa;YACzB,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE;gBACR,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,WAAW,EAAE,QAAQ,CAAC,WAAW;gBACjC,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,SAAS,EAAE,QAAQ,CAAC,SAAS;aAC9B;SACF,CAAC,CAAC;IACL,CAAC;IAED,oDAAoD;IACpD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IAE1C,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAEvC,OAAO,IAAI,CAAC;QACV,MAAM;QACN,QAAQ;QACR,UAAU,EAAE,aAAa;QACzB,MAAM,EAAE,UAAU;QAClB,YAAY,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;KACxD,CAAC,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AASxC,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmCjE"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAYxC,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+CjE"}
@@ -1,5 +1,6 @@
1
1
  import { isEditorAuthenticated } from "../auth/session.js";
2
- import { json, getUploadHandler, getSessionId, enforceCsrfHeader, } from "./_helpers.js";
2
+ import { UploadError } from "../storage/image-validation.js";
3
+ import { json, getUploadHandler, getSessionId, enforceCsrfHeader, enforceContentLength, MAX_UPLOAD_BODY_BYTES, } from "./_helpers.js";
3
4
  export async function POST(context) {
4
5
  const csrfFailure = enforceCsrfHeader(context.request);
5
6
  if (csrfFailure)
@@ -11,6 +12,12 @@ export async function POST(context) {
11
12
  if (!contentType.includes("multipart/form-data")) {
12
13
  return json({ error: "Expected multipart/form-data" }, 400);
13
14
  }
15
+ // Reject oversized uploads before formData() buffers the whole body. Demo
16
+ // sessions get a tighter per-file/per-session cap from QuotaUploadHandler;
17
+ // this is the embedded-mode backstop that would otherwise be unbounded.
18
+ const tooLarge = enforceContentLength(context.request, MAX_UPLOAD_BODY_BYTES);
19
+ if (tooLarge)
20
+ return tooLarge;
14
21
  const formData = await context.request.formData().catch(() => null);
15
22
  if (!formData) {
16
23
  return json({ error: "Invalid form data" }, 400);
@@ -26,8 +33,14 @@ export async function POST(context) {
26
33
  return json({ url: result.url });
27
34
  }
28
35
  catch (error) {
29
- const message = error instanceof Error ? error.message : "Upload failed";
30
- return json({ error: message }, 400);
36
+ // Only surface curated validation/quota messages. Unexpected errors (e.g.
37
+ // a storage error carrying a filesystem path) are logged and returned
38
+ // opaquely so they never leak to the client.
39
+ if (error instanceof UploadError) {
40
+ return json({ error: error.message }, 400);
41
+ }
42
+ console.error("[caretcms] Upload failed:", error);
43
+ return json({ error: "Upload failed" }, 500);
31
44
  }
32
45
  }
33
46
  //# sourceMappingURL=upload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../src/runtime/routes/upload.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EACL,IAAI,EACJ,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAmB;IAC5C,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CACjC,IAAI,EACJ,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CACtC,CAAC;QACF,OAAO,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACzE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../src/runtime/routes/upload.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EACL,IAAI,EACJ,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAmB;IAC5C,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;IAC9E,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CACjC,IAAI,EACJ,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CACtC,CAAC;QACF,OAAO,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,sEAAsE;QACtE,6CAA6C;QAC7C,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -2,7 +2,13 @@
2
2
  * Server-side HTML sanitizer for rich text fields.
3
3
  *
4
4
  * Regex-based (no DOM dependency) — works in Node, Deno, edge runtimes.
5
- * Same allowlist as the client sanitizer in static/cms/editor/sanitize.js.
5
+ * Allowlist + class matcher live in ./rich-allowlist.ts, shared with the cloud
6
+ * sanitizer; static/cms/editor/sanitize.js mirrors them by hand.
6
7
  */
7
- export declare function sanitizeHtml(html: string): string;
8
+ import { type AllowedClasses } from "./rich-allowlist.js";
9
+ export type { AllowedClasses } from "./rich-allowlist.js";
10
+ export interface SanitizeOptions {
11
+ allowedClasses?: AllowedClasses;
12
+ }
13
+ export declare function sanitizeHtml(html: string, options?: SanitizeOptions): string;
8
14
  //# sourceMappingURL=sanitize-html.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize-html.d.ts","sourceRoot":"","sources":["../../src/runtime/sanitize-html.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmEjD"}
1
+ {"version":3,"file":"sanitize-html.d.ts","sourceRoot":"","sources":["../../src/runtime/sanitize-html.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAuC5E"}
@@ -2,20 +2,16 @@
2
2
  * Server-side HTML sanitizer for rich text fields.
3
3
  *
4
4
  * Regex-based (no DOM dependency) — works in Node, Deno, edge runtimes.
5
- * Same allowlist as the client sanitizer in static/cms/editor/sanitize.js.
5
+ * Allowlist + class matcher live in ./rich-allowlist.ts, shared with the cloud
6
+ * sanitizer; static/cms/editor/sanitize.js mirrors them by hand.
6
7
  */
7
- const ALLOWED_TAGS = new Set([
8
- "b", "strong", "i", "em", "u", "s", "a", "br", "sub", "sup",
9
- ]);
10
- const ALLOWED_ATTRS = {
11
- a: new Set(["href", "target", "rel"]),
12
- };
13
- const SAFE_HREF_RE = /^(?:https?:|mailto:|tel:|\/)/i;
8
+ import { RICH_ALLOWED_TAGS as ALLOWED_TAGS, RICH_ALLOWED_ATTRS as ALLOWED_ATTRS, SAFE_HREF_RE, filterClasses, } from "./rich-allowlist.js";
14
9
  const TOKEN_RE = /<\/?([a-zA-Z][\w-]*)\b([^>]*)\/?>|[^<]+/g;
15
10
  const ATTR_RE = /([a-zA-Z][\w-]*)\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+))/g;
16
- export function sanitizeHtml(html) {
11
+ export function sanitizeHtml(html, options) {
17
12
  if (!html)
18
13
  return "";
14
+ const allowedClasses = options?.allowedClasses;
19
15
  let result = "";
20
16
  TOKEN_RE.lastIndex = 0;
21
17
  let match;
@@ -36,40 +32,63 @@ export function sanitizeHtml(html) {
36
32
  continue;
37
33
  }
38
34
  // Build sanitized opening tag
39
- const allowedAttrSet = ALLOWED_ATTRS[tag];
40
- let attrs = "";
41
- if (allowedAttrSet && rawAttrs) {
42
- ATTR_RE.lastIndex = 0;
43
- let attrMatch;
44
- while ((attrMatch = ATTR_RE.exec(rawAttrs)) !== null) {
45
- const attrName = attrMatch[1].toLowerCase();
46
- const attrValue = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
47
- if (!allowedAttrSet.has(attrName))
48
- continue;
49
- if (attrName === "href") {
50
- if (!SAFE_HREF_RE.test(attrValue))
51
- continue;
52
- }
53
- attrs += ` ${attrName}="${escapeAttr(attrValue)}"`;
54
- }
55
- }
35
+ let attrs = sanitizeAttributes(rawAttrs, ALLOWED_ATTRS[tag], allowedClasses?.[tag]);
56
36
  // Force security attrs on external <a> links
57
- if (tag === "a") {
58
- const hrefMatch = /\bhref\s*=\s*"([^"]*)"/i.exec(attrs);
59
- const href = hrefMatch?.[1] ?? "";
60
- if (href && /^https?:/i.test(href)) {
61
- if (!attrs.includes("target=")) {
62
- attrs += ` target="_blank"`;
63
- }
64
- if (!attrs.includes("rel=")) {
65
- attrs += ` rel="noopener noreferrer"`;
66
- }
67
- }
68
- }
37
+ if (tag === "a")
38
+ attrs = enforceLinkSafety(attrs);
69
39
  result += isSelfClosing ? `<${tag}${attrs} />` : `<${tag}${attrs}>`;
70
40
  }
71
41
  return result;
72
42
  }
43
+ /**
44
+ * Sanitize one opening tag's raw attribute text into a ` name="value"…` string.
45
+ * Keeps only attributes in `allowedAttrSet` (with href gated by SAFE_HREF_RE),
46
+ * plus `class` filtered to `classPatterns` (class is gated separately, by the
47
+ * per-tag allowedClasses — never by ALLOWED_ATTRS). Everything else is dropped.
48
+ */
49
+ function sanitizeAttributes(rawAttrs, allowedAttrSet, classPatterns) {
50
+ if ((!allowedAttrSet && !classPatterns) || !rawAttrs)
51
+ return "";
52
+ let attrs = "";
53
+ ATTR_RE.lastIndex = 0;
54
+ let attrMatch;
55
+ while ((attrMatch = ATTR_RE.exec(rawAttrs)) !== null) {
56
+ const attrName = attrMatch[1].toLowerCase();
57
+ const attrValue = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
58
+ // class is gated by the per-tag allowlist, not ALLOWED_ATTRS
59
+ if (attrName === "class") {
60
+ if (!classPatterns)
61
+ continue;
62
+ const kept = filterClasses(attrValue, classPatterns);
63
+ if (kept)
64
+ attrs += ` class="${escapeAttr(kept)}"`;
65
+ continue;
66
+ }
67
+ if (!allowedAttrSet || !allowedAttrSet.has(attrName))
68
+ continue;
69
+ if (attrName === "href") {
70
+ if (!SAFE_HREF_RE.test(attrValue))
71
+ continue;
72
+ }
73
+ attrs += ` ${attrName}="${escapeAttr(attrValue)}"`;
74
+ }
75
+ return attrs;
76
+ }
77
+ /**
78
+ * Force `target="_blank"` + `rel="noopener noreferrer"` onto external (http/https)
79
+ * `<a>` links, without clobbering values the author already set. Relative,
80
+ * mailto:, and tel: links are left untouched.
81
+ */
82
+ function enforceLinkSafety(attrs) {
83
+ const href = /\bhref\s*=\s*"([^"]*)"/i.exec(attrs)?.[1] ?? "";
84
+ if (!href || !/^https?:/i.test(href))
85
+ return attrs;
86
+ if (!attrs.includes("target="))
87
+ attrs += ` target="_blank"`;
88
+ if (!attrs.includes("rel="))
89
+ attrs += ` rel="noopener noreferrer"`;
90
+ return attrs;
91
+ }
73
92
  function escapeText(str) {
74
93
  return str
75
94
  .replace(/&/g, "&amp;")
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize-html.js","sourceRoot":"","sources":["../../src/runtime/sanitize-html.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sanitize-html.js","sourceRoot":"","sources":["../../src/runtime/sanitize-html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Vendored steganographic encoder for Content Source Maps.
3
+ *
4
+ * Hides a small JSON payload (e.g. a Caret binding key) *inside* a string by
5
+ * appending invisible Unicode "tag" characters (U+E0000–U+E007F, the Unicode
6
+ * Tags block, which render to nothing). Because the metadata lives in the string
7
+ * value itself — not on a DOM element — it survives flowing through component
8
+ * props, slots, and `.map()` loops, and can later be decoded from a rendered DOM
9
+ * text node to power click-to-edit overlays with no `data-caret` attribute.
10
+ *
11
+ * This is the same technique used by `@vercel/stega`, reimplemented here in a
12
+ * few lines so `@caretcms/core` keeps ZERO runtime dependencies. The wire format
13
+ * is Caret's own (Caret encodes and Caret decodes), so it is intentionally
14
+ * simple rather than byte-compatible with Vercel's envelope.
15
+ *
16
+ * Isomorphic: encode/clean run server-side (loaders, middleware); decode runs in
17
+ * the editor's browser bundle. Published output MUST be run through stegaClean().
18
+ */
19
+ /**
20
+ * Append `payload` to `value` as invisible metadata. The returned string looks
21
+ * and prints identically to `value`, but carries the payload for later decode.
22
+ */
23
+ export declare function stegaCombine(value: string, payload: unknown): string;
24
+ /**
25
+ * Extract the hidden payload from a string, or `undefined` if there is none
26
+ * (or it is malformed). Safe to call on any string, encoded or not.
27
+ */
28
+ export declare function stegaDecode<T = unknown>(value: string): T | undefined;
29
+ /** Strip ALL stega metadata, returning the clean visible string. */
30
+ export declare function stegaClean(value: string): string;
31
+ /** Convenience: the cleaned string and the decoded payload in one call. */
32
+ export declare function stegaSplit<T = unknown>(value: string): {
33
+ cleaned: string;
34
+ payload: T | undefined;
35
+ };
36
+ /** Whether a string carries any stega metadata. */
37
+ export declare function hasStega(value: string): boolean;
38
+ //# sourceMappingURL=stega.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stega.d.ts","sourceRoot":"","sources":["../../src/runtime/stega.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAwCH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAEpE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAiBrE;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EACpC,KAAK,EAAE,MAAM,GACZ;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,GAAG,SAAS,CAAA;CAAE,CAE7C;AAED,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/C"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Vendored steganographic encoder for Content Source Maps.
3
+ *
4
+ * Hides a small JSON payload (e.g. a Caret binding key) *inside* a string by
5
+ * appending invisible Unicode "tag" characters (U+E0000–U+E007F, the Unicode
6
+ * Tags block, which render to nothing). Because the metadata lives in the string
7
+ * value itself — not on a DOM element — it survives flowing through component
8
+ * props, slots, and `.map()` loops, and can later be decoded from a rendered DOM
9
+ * text node to power click-to-edit overlays with no `data-caret` attribute.
10
+ *
11
+ * This is the same technique used by `@vercel/stega`, reimplemented here in a
12
+ * few lines so `@caretcms/core` keeps ZERO runtime dependencies. The wire format
13
+ * is Caret's own (Caret encodes and Caret decodes), so it is intentionally
14
+ * simple rather than byte-compatible with Vercel's envelope.
15
+ *
16
+ * Isomorphic: encode/clean run server-side (loaders, middleware); decode runs in
17
+ * the editor's browser bundle. Published output MUST be run through stegaClean().
18
+ */
19
+ // The Unicode Tags block. Every character here is invisible when rendered.
20
+ const TAG_BASE = 0xe0000;
21
+ const TAG_MAX = 0xe007f;
22
+ // Delimiters at offsets 0x00 / 0x01 — these are NOT base64 characters, so they
23
+ // can never collide with an encoded body.
24
+ const START = String.fromCodePoint(TAG_BASE + 0x00);
25
+ const END = String.fromCodePoint(TAG_BASE + 0x01);
26
+ // Matches any character in the Tags block (used to strip all stega metadata).
27
+ const TAG_RE = /[\u{E0000}-\u{E007F}]/gu;
28
+ function toBase64(input) {
29
+ const bytes = new TextEncoder().encode(input);
30
+ if (typeof Buffer !== "undefined")
31
+ return Buffer.from(bytes).toString("base64");
32
+ let binary = "";
33
+ for (const byte of bytes)
34
+ binary += String.fromCharCode(byte);
35
+ return btoa(binary);
36
+ }
37
+ function fromBase64(b64) {
38
+ if (typeof Buffer !== "undefined")
39
+ return Buffer.from(b64, "base64").toString("utf8");
40
+ const binary = atob(b64);
41
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
42
+ return new TextDecoder().decode(bytes);
43
+ }
44
+ /** Encode a payload into an invisible, appendable string of tag characters. */
45
+ function encodePayload(payload) {
46
+ const b64 = toBase64(JSON.stringify(payload));
47
+ let body = "";
48
+ for (let i = 0; i < b64.length; i++) {
49
+ // base64 chars are ASCII; map each to its invisible tag-block counterpart.
50
+ body += String.fromCodePoint(TAG_BASE + b64.charCodeAt(i));
51
+ }
52
+ return START + body + END;
53
+ }
54
+ /**
55
+ * Append `payload` to `value` as invisible metadata. The returned string looks
56
+ * and prints identically to `value`, but carries the payload for later decode.
57
+ */
58
+ export function stegaCombine(value, payload) {
59
+ return value + encodePayload(payload);
60
+ }
61
+ /**
62
+ * Extract the hidden payload from a string, or `undefined` if there is none
63
+ * (or it is malformed). Safe to call on any string, encoded or not.
64
+ */
65
+ export function stegaDecode(value) {
66
+ const start = value.indexOf(START);
67
+ if (start === -1)
68
+ return undefined;
69
+ const end = value.indexOf(END, start + START.length);
70
+ if (end === -1)
71
+ return undefined;
72
+ let b64 = "";
73
+ for (const ch of value.slice(start + START.length, end)) {
74
+ const cp = ch.codePointAt(0);
75
+ if (cp === undefined || cp < TAG_BASE || cp > TAG_MAX)
76
+ return undefined;
77
+ b64 += String.fromCharCode(cp - TAG_BASE);
78
+ }
79
+ try {
80
+ return JSON.parse(fromBase64(b64));
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ /** Strip ALL stega metadata, returning the clean visible string. */
87
+ export function stegaClean(value) {
88
+ return value.replace(TAG_RE, "");
89
+ }
90
+ /** Convenience: the cleaned string and the decoded payload in one call. */
91
+ export function stegaSplit(value) {
92
+ return { cleaned: stegaClean(value), payload: stegaDecode(value) };
93
+ }
94
+ /** Whether a string carries any stega metadata. */
95
+ export function hasStega(value) {
96
+ return value.includes(START);
97
+ }
98
+ //# sourceMappingURL=stega.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stega.js","sourceRoot":"","sources":["../../src/runtime/stega.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Crash-safe filesystem write primitives shared by every filesystem-backed
3
+ * StorageAdapter and the sidecar metadata store.
4
+ */
5
+ /**
6
+ * Write a file atomically: stream into a sibling temp file, then rename over
7
+ * the target. rename(2) is atomic on the same filesystem, so a crash/SIGKILL
8
+ * mid-write can never leave a truncated or empty file — readers always see
9
+ * either the old contents or the complete new contents. The temp file is a
10
+ * sibling (same dir → same filesystem) so the rename stays atomic and never
11
+ * crosses a device boundary.
12
+ */
13
+ export declare function atomicWrite(filePath: string, contents: string): Promise<void>;
14
+ /**
15
+ * Serialize async tasks that share a `key` so their read-modify-write sequences
16
+ * never interleave. Used for the single shared revisions store, where a torn
17
+ * read-increment-write would lose revision state and defeat optimistic
18
+ * concurrency. Keyed by an arbitrary string (typically a file path); chains are
19
+ * cleaned up once drained so the map can't grow unbounded.
20
+ */
21
+ export declare function serializeWrite<T>(key: string, task: () => Promise<T>): Promise<T>;
22
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../../../src/runtime/storage/atomic-write.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASnF;AAID;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAYjF"}
@@ -0,0 +1,44 @@
1
+ import { rename, unlink, writeFile } from "node:fs/promises";
2
+ import { randomUUID } from "node:crypto";
3
+ /**
4
+ * Crash-safe filesystem write primitives shared by every filesystem-backed
5
+ * StorageAdapter and the sidecar metadata store.
6
+ */
7
+ /**
8
+ * Write a file atomically: stream into a sibling temp file, then rename over
9
+ * the target. rename(2) is atomic on the same filesystem, so a crash/SIGKILL
10
+ * mid-write can never leave a truncated or empty file — readers always see
11
+ * either the old contents or the complete new contents. The temp file is a
12
+ * sibling (same dir → same filesystem) so the rename stays atomic and never
13
+ * crosses a device boundary.
14
+ */
15
+ export async function atomicWrite(filePath, contents) {
16
+ const tmpPath = `${filePath}.${randomUUID()}.tmp`;
17
+ await writeFile(tmpPath, contents, "utf8");
18
+ try {
19
+ await rename(tmpPath, filePath);
20
+ }
21
+ catch (error) {
22
+ await unlink(tmpPath).catch(() => { });
23
+ throw error;
24
+ }
25
+ }
26
+ const writeChains = new Map();
27
+ /**
28
+ * Serialize async tasks that share a `key` so their read-modify-write sequences
29
+ * never interleave. Used for the single shared revisions store, where a torn
30
+ * read-increment-write would lose revision state and defeat optimistic
31
+ * concurrency. Keyed by an arbitrary string (typically a file path); chains are
32
+ * cleaned up once drained so the map can't grow unbounded.
33
+ */
34
+ export function serializeWrite(key, task) {
35
+ const previous = writeChains.get(key) ?? Promise.resolve();
36
+ const next = previous.then(task, task);
37
+ writeChains.set(key, next.finally(() => {
38
+ if (writeChains.get(key) === next) {
39
+ writeChains.delete(key);
40
+ }
41
+ }));
42
+ return next;
43
+ }
44
+ //# sourceMappingURL=atomic-write.js.map