@caretcms/core 0.1.2 → 0.3.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.
- package/README.md +109 -13
- package/dist/contracts.d.ts +1 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +1 -0
- package/dist/contracts.js.map +1 -1
- package/dist/index.d.ts +31 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +146 -30
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +17 -6
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +57 -14
- package/dist/loader.js.map +1 -1
- package/dist/markdown/block-context.d.ts +21 -0
- package/dist/markdown/block-context.d.ts.map +1 -0
- package/dist/markdown/block-context.js +27 -0
- package/dist/markdown/block-context.js.map +1 -0
- package/dist/markdown/canonical-body.d.ts +30 -0
- package/dist/markdown/canonical-body.d.ts.map +1 -0
- package/dist/markdown/canonical-body.js +54 -0
- package/dist/markdown/canonical-body.js.map +1 -0
- package/dist/markdown/contracts.d.ts +66 -0
- package/dist/markdown/contracts.d.ts.map +1 -0
- package/dist/markdown/contracts.js +102 -0
- package/dist/markdown/contracts.js.map +1 -0
- package/dist/markdown/html-to-snodes.d.ts +26 -0
- package/dist/markdown/html-to-snodes.d.ts.map +1 -0
- package/dist/markdown/html-to-snodes.js +118 -0
- package/dist/markdown/html-to-snodes.js.map +1 -0
- package/dist/markdown/remark.d.ts +35 -0
- package/dist/markdown/remark.d.ts.map +1 -0
- package/dist/markdown/remark.js +66 -0
- package/dist/markdown/remark.js.map +1 -0
- package/dist/markdown/satteri.d.ts +19 -0
- package/dist/markdown/satteri.d.ts.map +1 -0
- package/dist/markdown/satteri.js +144 -0
- package/dist/markdown/satteri.js.map +1 -0
- package/dist/markdown/serialize.d.ts +60 -0
- package/dist/markdown/serialize.d.ts.map +1 -0
- package/dist/markdown/serialize.js +264 -0
- package/dist/markdown/serialize.js.map +1 -0
- package/dist/markdown/splice.d.ts +32 -0
- package/dist/markdown/splice.d.ts.map +1 -0
- package/dist/markdown/splice.js +44 -0
- package/dist/markdown/splice.js.map +1 -0
- package/dist/markdown/stamp.d.ts +68 -0
- package/dist/markdown/stamp.d.ts.map +1 -0
- package/dist/markdown/stamp.js +131 -0
- package/dist/markdown/stamp.js.map +1 -0
- package/dist/runtime/auth/rate-limiter.d.ts.map +1 -1
- package/dist/runtime/auth/rate-limiter.js +5 -0
- package/dist/runtime/auth/rate-limiter.js.map +1 -1
- package/dist/runtime/auth/session.d.ts +3 -3
- package/dist/runtime/auth/session.d.ts.map +1 -1
- package/dist/runtime/auth/session.js +68 -21
- package/dist/runtime/auth/session.js.map +1 -1
- package/dist/runtime/config.d.ts +3 -0
- package/dist/runtime/config.d.ts.map +1 -1
- package/dist/runtime/config.js +4 -1
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/content.d.ts.map +1 -1
- package/dist/runtime/content.js +4 -2
- package/dist/runtime/content.js.map +1 -1
- package/dist/runtime/i18n.d.ts +86 -0
- package/dist/runtime/i18n.d.ts.map +1 -0
- package/dist/runtime/i18n.js +168 -0
- package/dist/runtime/i18n.js.map +1 -0
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/middleware.js +61 -6
- package/dist/runtime/middleware.js.map +1 -1
- package/dist/runtime/mutations/contracts.d.ts +28 -1
- package/dist/runtime/mutations/contracts.d.ts.map +1 -1
- package/dist/runtime/mutations/contracts.js +76 -0
- package/dist/runtime/mutations/contracts.js.map +1 -1
- package/dist/runtime/mutations/engine.d.ts +6 -1
- package/dist/runtime/mutations/engine.d.ts.map +1 -1
- package/dist/runtime/mutations/engine.js +271 -51
- package/dist/runtime/mutations/engine.js.map +1 -1
- package/dist/runtime/providers.d.ts +2 -1
- package/dist/runtime/providers.d.ts.map +1 -1
- package/dist/runtime/providers.js +7 -1
- package/dist/runtime/providers.js.map +1 -1
- package/dist/runtime/publish.d.ts +13 -1
- package/dist/runtime/publish.d.ts.map +1 -1
- package/dist/runtime/publish.js +80 -4
- package/dist/runtime/publish.js.map +1 -1
- package/dist/runtime/request-context.d.ts +14 -2
- package/dist/runtime/request-context.d.ts.map +1 -1
- package/dist/runtime/request-context.js +7 -1
- package/dist/runtime/request-context.js.map +1 -1
- package/dist/runtime/rewrite.d.ts.map +1 -1
- package/dist/runtime/rewrite.js +109 -3
- package/dist/runtime/rewrite.js.map +1 -1
- package/dist/runtime/rich-allowlist.d.ts.map +1 -1
- package/dist/runtime/rich-allowlist.js +5 -1
- package/dist/runtime/rich-allowlist.js.map +1 -1
- package/dist/runtime/routes/admin-entry.d.ts.map +1 -1
- package/dist/runtime/routes/admin-entry.js +114 -18
- package/dist/runtime/routes/admin-entry.js.map +1 -1
- package/dist/runtime/routes/admin.d.ts.map +1 -1
- package/dist/runtime/routes/admin.js +33 -15
- package/dist/runtime/routes/admin.js.map +1 -1
- package/dist/runtime/routes/auth-login.d.ts.map +1 -1
- package/dist/runtime/routes/auth-login.js +4 -0
- package/dist/runtime/routes/auth-login.js.map +1 -1
- package/dist/runtime/routes/auth-logout.d.ts.map +1 -1
- package/dist/runtime/routes/auth-logout.js +7 -2
- package/dist/runtime/routes/auth-logout.js.map +1 -1
- package/dist/runtime/routes/auth-session.d.ts.map +1 -1
- package/dist/runtime/routes/auth-session.js +4 -2
- package/dist/runtime/routes/auth-session.js.map +1 -1
- package/dist/runtime/routes/collection-list.d.ts.map +1 -1
- package/dist/runtime/routes/collection-list.js +64 -41
- package/dist/runtime/routes/collection-list.js.map +1 -1
- package/dist/runtime/routes/entries.d.ts.map +1 -1
- package/dist/runtime/routes/entries.js +16 -6
- package/dist/runtime/routes/entries.js.map +1 -1
- package/dist/runtime/routes/history.d.ts.map +1 -1
- package/dist/runtime/routes/history.js +50 -22
- package/dist/runtime/routes/history.js.map +1 -1
- package/dist/runtime/routes/mutate.d.ts.map +1 -1
- package/dist/runtime/routes/mutate.js +40 -6
- package/dist/runtime/routes/mutate.js.map +1 -1
- package/dist/runtime/routes/publish.d.ts.map +1 -1
- package/dist/runtime/routes/publish.js +5 -2
- package/dist/runtime/routes/publish.js.map +1 -1
- package/dist/runtime/routes/schema.d.ts.map +1 -1
- package/dist/runtime/routes/schema.js +11 -3
- package/dist/runtime/routes/schema.js.map +1 -1
- package/dist/runtime/routes/studio-home.d.ts.map +1 -1
- package/dist/runtime/routes/studio-home.js +38 -19
- package/dist/runtime/routes/studio-home.js.map +1 -1
- package/dist/runtime/routes/theme-stylesheet.d.ts.map +1 -1
- package/dist/runtime/routes/theme-stylesheet.js +11 -1
- package/dist/runtime/routes/theme-stylesheet.js.map +1 -1
- package/dist/runtime/schema-registry.d.ts +8 -1
- package/dist/runtime/schema-registry.d.ts.map +1 -1
- package/dist/runtime/schema-registry.js +47 -3
- package/dist/runtime/schema-registry.js.map +1 -1
- package/dist/runtime/storage/atomic-write.d.ts.map +1 -1
- package/dist/runtime/storage/atomic-write.js +8 -3
- package/dist/runtime/storage/atomic-write.js.map +1 -1
- package/dist/runtime/storage/markdown-adapter.d.ts +19 -0
- package/dist/runtime/storage/markdown-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/markdown-adapter.js +41 -0
- package/dist/runtime/storage/markdown-adapter.js.map +1 -1
- package/dist/runtime/storage/session-overlay-adapter.d.ts +8 -0
- package/dist/runtime/storage/session-overlay-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/session-overlay-adapter.js +24 -2
- package/dist/runtime/storage/session-overlay-adapter.js.map +1 -1
- package/dist/runtime/themes/preset-tokens.js +4 -4
- package/dist/runtime/themes/preset-tokens.js.map +1 -1
- package/dist/runtime/utils.d.ts +10 -0
- package/dist/runtime/utils.d.ts.map +1 -1
- package/dist/runtime/utils.js +16 -0
- package/dist/runtime/utils.js.map +1 -1
- package/dist/runtime/views/studio-layout.d.ts +3 -0
- package/dist/runtime/views/studio-layout.d.ts.map +1 -1
- package/dist/runtime/views/studio-layout.js +36 -13
- package/dist/runtime/views/studio-layout.js.map +1 -1
- package/dist/schema-utils.d.ts +7 -0
- package/dist/schema-utils.d.ts.map +1 -1
- package/dist/schema-utils.js +143 -0
- package/dist/schema-utils.js.map +1 -1
- package/dist/types.d.ts +83 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/cms/admin-entry.css +135 -13
- package/static/cms/admin-entry.js +509 -86
- package/static/cms/editor/guards.js +1 -1
- package/static/cms/editor/image-edit.js +42 -11
- package/static/cms/editor/image.css +7 -1
- package/static/cms/editor/md-block-edit.js +176 -0
- package/static/cms/editor/md-serialize.js +301 -0
- package/static/cms/editor/panel.css +69 -25
- package/static/cms/editor/panel.js +58 -1
- package/static/cms/editor/rich-toolbar.js +4 -3
- package/static/cms/editor/sanitize.js +2 -1
- package/static/cms/editor/sync.js +277 -56
- package/static/cms/editor/text-edit.js +68 -17
- package/static/cms/editor/text-link-interactions.js +4 -4
- package/static/cms/editor/toast.css +114 -2
- package/static/cms/editor/toast.js +121 -22
- package/static/cms/editor/tokens-and-text.css +73 -3
- package/static/cms/editor/toolbar.css +19 -6
- package/static/cms/editor/toolbar.js +64 -23
- package/static/cms/editor.css +1 -1
- package/static/cms/editor.js +14 -3
- package/static/cms/studio-tokens.css +4 -4
- package/static/cms/studio.css +24 -0
|
@@ -2,7 +2,8 @@ export const prerender = false;
|
|
|
2
2
|
import { isEditorAuthenticated } from "../auth/session.js";
|
|
3
3
|
import { getRuntimeConfig } from "../config.js";
|
|
4
4
|
import { resolveAdapter } from "./_helpers.js";
|
|
5
|
-
import {
|
|
5
|
+
import { isKnownStudioCollection, resolveCollectionStudioConfig, } from "../schema-registry.js";
|
|
6
|
+
import { escapeHtml, htmlResponse, redirectResponse, renderStudioPage, serializeJsonForScript, } from "../views/studio-layout.js";
|
|
6
7
|
function humanize(name) {
|
|
7
8
|
return name.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
8
9
|
}
|
|
@@ -17,11 +18,17 @@ export async function GET(context) {
|
|
|
17
18
|
return redirectResponse(`${runtime.mountPath}/cms`);
|
|
18
19
|
}
|
|
19
20
|
const adapter = await resolveAdapter();
|
|
20
|
-
|
|
21
|
-
if (!known.includes(collection)) {
|
|
21
|
+
if (!(await isKnownStudioCollection(adapter, collection))) {
|
|
22
22
|
return redirectResponse(`${runtime.mountPath}/cms`);
|
|
23
23
|
}
|
|
24
|
-
const
|
|
24
|
+
const collectionConfig = await resolveCollectionStudioConfig(adapter, collection);
|
|
25
|
+
if (collectionConfig.singletonId) {
|
|
26
|
+
return redirectResponse(`${runtime.mountPath}/cms/${encodeURIComponent(collection)}/${encodeURIComponent(collectionConfig.singletonId)}`);
|
|
27
|
+
}
|
|
28
|
+
const label = collectionConfig.label || humanize(collection);
|
|
29
|
+
const messages = runtime.messages;
|
|
30
|
+
const creatable = collectionConfig.creatable !== false;
|
|
31
|
+
const orderable = collectionConfig.orderable !== false;
|
|
25
32
|
const safeCollection = escapeHtml(collection);
|
|
26
33
|
const extraStyles = `
|
|
27
34
|
.entry-card {
|
|
@@ -94,13 +101,14 @@ export async function GET(context) {
|
|
|
94
101
|
const body = `<div class="studio-fade-in" style="max-width:80rem;margin:0 auto;" id="collection-page" data-collection="${safeCollection}">
|
|
95
102
|
<div style="display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:1.5rem;">
|
|
96
103
|
<div>
|
|
97
|
-
<
|
|
98
|
-
<p id="entry-count" style="font-size:0.7rem;margin:0.25rem 0 0;color:var(--studio-text-dim);"
|
|
104
|
+
<h1 style="font-family:var(--studio-font-heading);font-size:1.25rem;margin:0;color:var(--studio-text);">${escapeHtml(label)}</h1>
|
|
105
|
+
<p id="entry-count" style="font-size:0.7rem;margin:0.25rem 0 0;color:var(--studio-text-dim);">${escapeHtml(messages["common.loading"])}</p>
|
|
99
106
|
</div>
|
|
100
107
|
<div style="display:flex;align-items:center;gap:0.75rem;flex-wrap:wrap;">
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
|
|
108
|
+
<label for="search-input" style="font-size:0.7rem;color:var(--studio-text-dim);">${escapeHtml(messages["collection.search"])}</label>
|
|
109
|
+
<input id="search-input" name="search" type="search" placeholder="${escapeHtml(messages["collection.searchPlaceholder"])}" class="studio-input" style="max-width:240px;" />
|
|
110
|
+
${orderable ? `<button id="btn-reorder" class="studio-btn-ghost">${escapeHtml(messages["collection.reorder"])}</button>` : ""}
|
|
111
|
+
${creatable ? `<button id="btn-new" class="studio-btn-primary">${escapeHtml(messages["collection.new"])}</button>` : ""}
|
|
104
112
|
</div>
|
|
105
113
|
</div>
|
|
106
114
|
|
|
@@ -109,13 +117,13 @@ export async function GET(context) {
|
|
|
109
117
|
</div>
|
|
110
118
|
|
|
111
119
|
<div id="empty" hidden style="text-align:center;padding:5rem 0;color:var(--studio-text-dim);">
|
|
112
|
-
<p style="font-size:0.875rem;margin:0 0 0.75rem;"
|
|
113
|
-
|
|
120
|
+
<p style="font-size:0.875rem;margin:0 0 0.75rem;">${escapeHtml(messages["collection.noEntries"])}</p>
|
|
121
|
+
${creatable ? `<button id="btn-empty-create" class="studio-btn-primary">${escapeHtml(messages["collection.createFirst"])}</button>` : ""}
|
|
114
122
|
</div>
|
|
115
123
|
|
|
116
124
|
<div id="error-state" hidden style="text-align:center;padding:5rem 0;">
|
|
117
|
-
<p style="font-size:0.875rem;margin:0 0 0.75rem;color:var(--studio-red);"
|
|
118
|
-
<button id="retry-btn" class="studio-btn-ghost"
|
|
125
|
+
<p style="font-size:0.875rem;margin:0 0 0.75rem;color:var(--studio-red);">${escapeHtml(messages["collection.failed"])}</p>
|
|
126
|
+
<button id="retry-btn" class="studio-btn-ghost">${escapeHtml(messages["common.retry"])}</button>
|
|
119
127
|
</div>
|
|
120
128
|
|
|
121
129
|
<div id="entries-grid" hidden style="display:grid;gap:1rem;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));"></div>
|
|
@@ -123,8 +131,8 @@ export async function GET(context) {
|
|
|
123
131
|
<div id="reorder-container" hidden>
|
|
124
132
|
<div id="reorder-list" style="display:flex;flex-direction:column;gap:0.25rem;"></div>
|
|
125
133
|
<div style="display:flex;justify-content:flex-end;gap:0.75rem;margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--studio-border);">
|
|
126
|
-
<button id="btn-reorder-cancel" class="studio-btn-ghost"
|
|
127
|
-
<button id="btn-reorder-save" class="studio-btn-primary"
|
|
134
|
+
<button id="btn-reorder-cancel" class="studio-btn-ghost">${escapeHtml(messages["common.cancel"])}</button>
|
|
135
|
+
<button id="btn-reorder-save" class="studio-btn-primary">${escapeHtml(messages["collection.saveOrder"])}</button>
|
|
128
136
|
</div>
|
|
129
137
|
</div>
|
|
130
138
|
</div>
|
|
@@ -132,25 +140,27 @@ export async function GET(context) {
|
|
|
132
140
|
<div id="create-dialog" class="modal-backdrop" hidden>
|
|
133
141
|
<div class="modal-card">
|
|
134
142
|
<div class="modal-header">
|
|
135
|
-
<span
|
|
136
|
-
<button id="btn-create-close" class="studio-btn-ghost" style="padding:4px 10px;"
|
|
143
|
+
<span>${escapeHtml(messages["collection.newEntry"])}</span>
|
|
144
|
+
<button id="btn-create-close" class="studio-btn-ghost" style="padding:4px 10px;">${escapeHtml(messages["common.close"])}</button>
|
|
137
145
|
</div>
|
|
138
146
|
<div class="modal-body">
|
|
139
|
-
<label for="create-id-input" class="studio-label"
|
|
140
|
-
<input id="create-id-input" type="text" class="studio-input" placeholder="
|
|
141
|
-
<p id="create-hint" style="font-size:10px;margin:0.5rem 0
|
|
147
|
+
<label for="create-id-input" class="studio-label">${escapeHtml(messages["collection.entryId"])}</label>
|
|
148
|
+
<input id="create-id-input" type="text" class="studio-input" placeholder="${escapeHtml(messages["collection.entryIdPlaceholder"])}" autocomplete="off" spellcheck="false" />
|
|
149
|
+
<p id="create-hint" style="font-size:10px;margin:0.5rem 0 0.35rem;color:var(--studio-text-dim);">${escapeHtml(messages["collection.idHint"])}</p>
|
|
150
|
+
<p style="font-size:10px;margin:0 0 1rem;color:var(--studio-text-dim);">${escapeHtml(messages["collection.publishHint"])}</p>
|
|
142
151
|
<p id="create-error" class="studio-error-text" hidden></p>
|
|
143
152
|
<div style="display:flex;justify-content:flex-end;gap:0.75rem;">
|
|
144
|
-
<button id="btn-create-cancel" class="studio-btn-ghost"
|
|
145
|
-
<button id="btn-create-confirm" class="studio-btn-primary" disabled
|
|
153
|
+
<button id="btn-create-cancel" class="studio-btn-ghost">${escapeHtml(messages["common.cancel"])}</button>
|
|
154
|
+
<button id="btn-create-confirm" class="studio-btn-primary" disabled>${escapeHtml(messages["collection.create"])}</button>
|
|
146
155
|
</div>
|
|
147
156
|
</div>
|
|
148
157
|
</div>
|
|
149
158
|
</div>`;
|
|
150
159
|
const inlineScript = `(function () {
|
|
151
|
-
var COLLECTION = ${
|
|
152
|
-
var API = ${
|
|
153
|
-
var MOUNT = ${
|
|
160
|
+
var COLLECTION = ${serializeJsonForScript(collection)};
|
|
161
|
+
var API = ${serializeJsonForScript(runtime.apiBasePath)};
|
|
162
|
+
var MOUNT = ${serializeJsonForScript(runtime.mountPath)};
|
|
163
|
+
var MSG = ${serializeJsonForScript(messages)};
|
|
154
164
|
var ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
155
165
|
var allEntries = [];
|
|
156
166
|
|
|
@@ -178,17 +188,20 @@ export async function GET(context) {
|
|
|
178
188
|
}
|
|
179
189
|
|
|
180
190
|
function getTitle(d) {
|
|
181
|
-
if (!d) return '
|
|
191
|
+
if (!d) return MSG['collection.untitled'];
|
|
182
192
|
for (var i = 0; i < ['name','title','question','company_name','headline','label'].length; i++) {
|
|
183
193
|
var k = ['name','title','question','company_name','headline','label'][i];
|
|
184
194
|
if (typeof d[k] === 'string' && d[k]) return d[k];
|
|
185
195
|
}
|
|
186
|
-
return '
|
|
196
|
+
return MSG['collection.untitled'];
|
|
187
197
|
}
|
|
188
198
|
function getThumb(d) {
|
|
189
199
|
if (!d) return null;
|
|
190
200
|
if (Array.isArray(d.images) && typeof d.images[0] === 'string') return d.images[0];
|
|
201
|
+
if (Array.isArray(d.images) && d.images[0] && typeof d.images[0].src === 'string') return d.images[0].src;
|
|
191
202
|
if (typeof d.image === 'string' && d.image) return d.image;
|
|
203
|
+
if (typeof d.coverImage === 'string' && d.coverImage) return d.coverImage;
|
|
204
|
+
if (typeof d.portrait === 'string' && d.portrait) return d.portrait;
|
|
192
205
|
if (typeof d.thumbnail === 'string' && d.thumbnail) return d.thumbnail;
|
|
193
206
|
if (typeof d.bg_image === 'string' && d.bg_image) return d.bg_image;
|
|
194
207
|
return null;
|
|
@@ -216,6 +229,14 @@ export async function GET(context) {
|
|
|
216
229
|
var title = getTitle(entry.data);
|
|
217
230
|
var thumb = getThumb(entry.data);
|
|
218
231
|
var subtitle = getSubtitle(entry.data);
|
|
232
|
+
var publication = entry.data && typeof entry.data.published === 'boolean'
|
|
233
|
+
? (entry.data.published
|
|
234
|
+
? '<span style="font-size:0.62rem;color:var(--studio-green);">' + htmlEsc(MSG['collection.published']) + '</span>'
|
|
235
|
+
: '<span style="font-size:0.62rem;color:var(--studio-text-dim);">' + htmlEsc(MSG['collection.unpublished']) + '</span>')
|
|
236
|
+
: '';
|
|
237
|
+
var invalid = Array.isArray(entry.validationIssues) && entry.validationIssues.length
|
|
238
|
+
? '<span style="display:block;font-size:0.62rem;color:var(--studio-red);margin-bottom:0.25rem;">' + htmlEsc(MSG['collection.invalid']) + '</span>'
|
|
239
|
+
: '';
|
|
219
240
|
var card = document.createElement('a');
|
|
220
241
|
card.href = MOUNT + '/cms/' + encodeURIComponent(COLLECTION) + '/' + encodeURIComponent(entry.id);
|
|
221
242
|
card.className = 'entry-card studio-card';
|
|
@@ -225,8 +246,10 @@ export async function GET(context) {
|
|
|
225
246
|
card.innerHTML =
|
|
226
247
|
(thumb ? '<div class="entry-thumb"><img src="' + htmlEsc(thumb) + '" alt="' + htmlEsc(title) + '" loading="lazy" /></div>' : '') +
|
|
227
248
|
'<div style="padding:1rem;">' +
|
|
228
|
-
'<
|
|
249
|
+
'<h2 style="font-size:0.875rem;font-weight:500;margin:0 0 0.25rem;color:var(--studio-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + htmlEsc(title) + '</h2>' +
|
|
229
250
|
(subtitle ? '<p style="font-size:0.7rem;margin:0 0 0.25rem;color:var(--studio-text-dim);text-transform:capitalize;">' + htmlEsc(subtitle) + '</p>' : '') +
|
|
251
|
+
invalid +
|
|
252
|
+
publication +
|
|
230
253
|
'<p style="font-size:0.65rem;margin:0;color:var(--studio-text-dim);font-family:var(--studio-font-mono);">' + htmlEsc(entry.id) + '</p>' +
|
|
231
254
|
'</div>';
|
|
232
255
|
grid.appendChild(card);
|
|
@@ -251,7 +274,7 @@ export async function GET(context) {
|
|
|
251
274
|
if (!json) return;
|
|
252
275
|
allEntries = Array.isArray(json.entries) ? json.entries : [];
|
|
253
276
|
loading.hidden = true;
|
|
254
|
-
countEl.textContent = allEntries.length + ' ' + (allEntries.length === 1 ? 'entry' : 'entries');
|
|
277
|
+
countEl.textContent = allEntries.length + ' ' + (allEntries.length === 1 ? MSG['count.entry'] : MSG['count.entries']);
|
|
255
278
|
renderEntries(allEntries);
|
|
256
279
|
})
|
|
257
280
|
.catch(function () {
|
|
@@ -286,8 +309,8 @@ export async function GET(context) {
|
|
|
286
309
|
function validate() {
|
|
287
310
|
var v = idInput.value.trim();
|
|
288
311
|
if (!v) { confirmBtn.disabled = true; errorEl.hidden = true; return; }
|
|
289
|
-
if (!ID_RE.test(v)) { errorEl.textContent = '
|
|
290
|
-
if (allEntries.some(function (e) { return e.id === v; })) { errorEl.textContent = '
|
|
312
|
+
if (!ID_RE.test(v)) { errorEl.textContent = MSG['collection.invalidId']; errorEl.hidden = false; confirmBtn.disabled = true; return; }
|
|
313
|
+
if (allEntries.some(function (e) { return e.id === v; })) { errorEl.textContent = MSG['collection.duplicateId']; errorEl.hidden = false; confirmBtn.disabled = true; return; }
|
|
291
314
|
errorEl.hidden = true; confirmBtn.disabled = false;
|
|
292
315
|
}
|
|
293
316
|
function createEntry() {
|
|
@@ -312,17 +335,17 @@ export async function GET(context) {
|
|
|
312
335
|
if (!res) return;
|
|
313
336
|
if (res.status === 401) { window.location.href = MOUNT + '?redirect=' + encodeURIComponent(window.location.pathname); return; }
|
|
314
337
|
if (!res.ok) throw new Error('mutate failed');
|
|
315
|
-
window.location.href = MOUNT + '/cms/' + encodeURIComponent(COLLECTION) + '/' + encodeURIComponent(entryId);
|
|
338
|
+
window.location.href = MOUNT + '/cms/' + encodeURIComponent(COLLECTION) + '/' + encodeURIComponent(entryId) + '?new=1';
|
|
316
339
|
})
|
|
317
340
|
.catch(function () {
|
|
318
|
-
errorEl.textContent = '
|
|
341
|
+
errorEl.textContent = MSG['collection.createFailed'];
|
|
319
342
|
errorEl.hidden = false;
|
|
320
343
|
confirmBtn.disabled = false;
|
|
321
|
-
confirmBtn.textContent = '
|
|
344
|
+
confirmBtn.textContent = MSG['collection.create'];
|
|
322
345
|
});
|
|
323
346
|
}
|
|
324
|
-
newBtn.addEventListener('click', openDialog);
|
|
325
|
-
emptyCreateBtn.addEventListener('click', openDialog);
|
|
347
|
+
if (newBtn) newBtn.addEventListener('click', openDialog);
|
|
348
|
+
if (emptyCreateBtn) emptyCreateBtn.addEventListener('click', openDialog);
|
|
326
349
|
document.getElementById('btn-create-close').addEventListener('click', closeDialog);
|
|
327
350
|
document.getElementById('btn-create-cancel').addEventListener('click', closeDialog);
|
|
328
351
|
confirmBtn.addEventListener('click', createEntry);
|
|
@@ -343,7 +366,7 @@ export async function GET(context) {
|
|
|
343
366
|
});
|
|
344
367
|
grid.hidden = true; empty.hidden = true;
|
|
345
368
|
searchInput.style.display = 'none'; newBtn.style.display = 'none';
|
|
346
|
-
reorderBtn.textContent = '
|
|
369
|
+
reorderBtn.textContent = MSG['collection.reordering']; reorderBtn.disabled = true;
|
|
347
370
|
reorderContainer.hidden = false;
|
|
348
371
|
renderReorderList();
|
|
349
372
|
}
|
|
@@ -351,7 +374,7 @@ export async function GET(context) {
|
|
|
351
374
|
reorderMode = false;
|
|
352
375
|
reorderContainer.hidden = true;
|
|
353
376
|
searchInput.style.display = ''; newBtn.style.display = '';
|
|
354
|
-
reorderBtn.textContent = '
|
|
377
|
+
reorderBtn.textContent = MSG['collection.reorder']; reorderBtn.disabled = false;
|
|
355
378
|
renderEntries(allEntries);
|
|
356
379
|
}
|
|
357
380
|
function renderReorderList() {
|
|
@@ -385,7 +408,7 @@ export async function GET(context) {
|
|
|
385
408
|
});
|
|
386
409
|
}
|
|
387
410
|
function saveOrder() {
|
|
388
|
-
reorderSave.disabled = true; reorderSave.textContent = '
|
|
411
|
+
reorderSave.disabled = true; reorderSave.textContent = MSG['common.saving'];
|
|
389
412
|
var items = ordered.map(function (entry, idx) {
|
|
390
413
|
return { id: entry.id, order: idx, expectedRevision: entry.revision };
|
|
391
414
|
});
|
|
@@ -403,9 +426,9 @@ export async function GET(context) {
|
|
|
403
426
|
ordered.forEach(function (entry, idx) { if (entry.data) entry.data.order = idx; });
|
|
404
427
|
exitReorder();
|
|
405
428
|
})
|
|
406
|
-
.catch(function () { reorderSave.disabled = false; reorderSave.textContent = '
|
|
429
|
+
.catch(function () { reorderSave.disabled = false; reorderSave.textContent = MSG['common.retry']; });
|
|
407
430
|
}
|
|
408
|
-
reorderBtn.addEventListener('click', enterReorder);
|
|
431
|
+
if (reorderBtn) reorderBtn.addEventListener('click', enterReorder);
|
|
409
432
|
reorderCancel.addEventListener('click', exitReorder);
|
|
410
433
|
reorderSave.addEventListener('click', saveOrder);
|
|
411
434
|
})();`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection-list.js","sourceRoot":"","sources":["../../../src/runtime/routes/collection-list.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAG/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"collection-list.js","sourceRoot":"","sources":["../../../src/runtime/routes/collection-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/entries.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/entries.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAkFxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyEhE"}
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
export const prerender = false;
|
|
2
2
|
import { isEditorAuthenticated } from "../auth/session.js";
|
|
3
3
|
import { parseCollectionName, parseEntryId } from "../mutations/contracts.js";
|
|
4
|
+
import { stripBodyOverlay } from "../utils.js";
|
|
5
|
+
import { getRegisteredSchema } from "../schema-registry.js";
|
|
6
|
+
import { validateJsonSchema } from "../../schema-utils.js";
|
|
4
7
|
import { json, resolveAdapter } from "./_helpers.js";
|
|
8
|
+
function withValidation(collection, entry, revision) {
|
|
9
|
+
const data = stripBodyOverlay(entry.data);
|
|
10
|
+
const schema = getRegisteredSchema(collection)?.schema;
|
|
11
|
+
const validationIssues = schema ? validateJsonSchema(data, schema) : [];
|
|
12
|
+
return {
|
|
13
|
+
id: entry.id,
|
|
14
|
+
data,
|
|
15
|
+
revision,
|
|
16
|
+
...(validationIssues.length > 0 ? { validationIssues } : {}),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
5
19
|
function asPositiveInt(value, fallback) {
|
|
6
20
|
if (!value)
|
|
7
21
|
return fallback;
|
|
@@ -50,7 +64,7 @@ export async function GET(context) {
|
|
|
50
64
|
const entry = await adapter.getEntry(collection, singleId);
|
|
51
65
|
const revision = entry ? await adapter.getRevision(collection, singleId) : 0;
|
|
52
66
|
const entries = entry
|
|
53
|
-
? [
|
|
67
|
+
? [withValidation(collection, entry, revision)]
|
|
54
68
|
: [];
|
|
55
69
|
return json({
|
|
56
70
|
entries,
|
|
@@ -74,11 +88,7 @@ export async function GET(context) {
|
|
|
74
88
|
const rawEntries = await Promise.all(pageIds.map((entryId) => adapter.getEntry(collection, entryId)));
|
|
75
89
|
const entries = await Promise.all(rawEntries
|
|
76
90
|
.filter((entry) => Boolean(entry))
|
|
77
|
-
.map(async (entry) => (
|
|
78
|
-
id: entry.id,
|
|
79
|
-
data: entry.data,
|
|
80
|
-
revision: await adapter.getRevision(collection, entry.id),
|
|
81
|
-
})));
|
|
91
|
+
.map(async (entry) => withValidation(collection, entry, await adapter.getRevision(collection, entry.id))));
|
|
82
92
|
return json({
|
|
83
93
|
entries,
|
|
84
94
|
pagination: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.js","sourceRoot":"","sources":["../../../src/runtime/routes/entries.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAG/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"entries.js","sourceRoot":"","sources":["../../../src/runtime/routes/entries.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/history.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiBhE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/history.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiBhE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8EjE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const prerender = false;
|
|
2
|
-
import { isEditorAuthenticated } from "../auth/session.js";
|
|
2
|
+
import { getEditorIdentity, isEditorAuthenticated } from "../auth/session.js";
|
|
3
3
|
import { parseEntryId } from "../mutations/contracts.js";
|
|
4
4
|
import { withEntryLock } from "../mutations/engine.js";
|
|
5
5
|
import { json, resolveAdapter, enforceCsrfHeader, readJsonBody } from "./_helpers.js";
|
|
@@ -42,27 +42,55 @@ export async function POST(context) {
|
|
|
42
42
|
if (!(await adapter.isKnownCollection(collectionRaw)) || !id || !Number.isFinite(ts)) {
|
|
43
43
|
return json({ error: "Invalid restore payload" }, 400);
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
45
|
+
try {
|
|
46
|
+
const editor = getEditorIdentity(context);
|
|
47
|
+
const entries = await adapter.getHistory(collectionRaw, id);
|
|
48
|
+
const snapshot = entries.find((entry) => entry.ts === ts);
|
|
49
|
+
if (!snapshot)
|
|
50
|
+
return json({ error: "Snapshot not found" }, 404);
|
|
51
|
+
if (!snapshot.data || typeof snapshot.data !== "object" || Array.isArray(snapshot.data)) {
|
|
52
|
+
return json({ error: "Snapshot data invalid" }, 500);
|
|
53
|
+
}
|
|
54
|
+
const snapshotData = snapshot.data;
|
|
55
|
+
// Hold the engine's per-entry lock so the restore can't interleave with a
|
|
56
|
+
// concurrent save_field/put_entry and tear the entry/revision pair. Write
|
|
57
|
+
// before appending history so a failed write doesn't record a phantom event.
|
|
58
|
+
const revision = await withEntryLock(collectionRaw, id, async () => {
|
|
59
|
+
// A publish snapshot that spliced body blocks carries the full
|
|
60
|
+
// pre-publish source file — restore it first (prose + frontmatter as
|
|
61
|
+
// they were), then writeEntry re-applies the snapshot's data on top so
|
|
62
|
+
// both restore paths converge on the same final state.
|
|
63
|
+
if (typeof snapshot.bodySource === "string" && adapter.writeBodySource) {
|
|
64
|
+
const current = await adapter.readBodySource?.(collectionRaw, id);
|
|
65
|
+
await adapter.writeBodySource(collectionRaw, id, snapshot.bodySource);
|
|
66
|
+
await adapter.writeEntry(collectionRaw, id, snapshotData);
|
|
67
|
+
const next = await adapter.bumpRevision(collectionRaw, id);
|
|
68
|
+
// Undo-of-the-undo: record what the file looked like before this restore.
|
|
69
|
+
await adapter.appendHistory(collectionRaw, id, {
|
|
70
|
+
ts: Date.now(),
|
|
71
|
+
action: "restore",
|
|
72
|
+
data: snapshotData,
|
|
73
|
+
...(typeof current === "string" ? { bodySource: current } : {}),
|
|
74
|
+
...(editor ? { editor } : {}),
|
|
75
|
+
});
|
|
76
|
+
return next;
|
|
77
|
+
}
|
|
78
|
+
await adapter.writeEntry(collectionRaw, id, snapshotData);
|
|
79
|
+
const next = await adapter.bumpRevision(collectionRaw, id);
|
|
80
|
+
await adapter.appendHistory(collectionRaw, id, {
|
|
81
|
+
ts: Date.now(),
|
|
82
|
+
action: "restore",
|
|
83
|
+
data: snapshotData,
|
|
84
|
+
...(editor ? { editor } : {}),
|
|
85
|
+
});
|
|
86
|
+
return next;
|
|
63
87
|
});
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
88
|
+
return json({ ok: true, revision });
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// An adapter throw must not leak a stack/path via a framework 500.
|
|
92
|
+
console.error("[caretcms] History restore failed:", error);
|
|
93
|
+
return json({ error: "Restore failed" }, 500);
|
|
94
|
+
}
|
|
67
95
|
}
|
|
68
96
|
//# sourceMappingURL=history.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../../src/runtime/routes/history.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAG/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../../src/runtime/routes/history.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAG/B,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEtF,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,MAAM,cAAc,EAAE,CAAC;IACvC,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,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAE5D,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AAC3B,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;IACvC,MAAM,IAAI,GACR,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAC9E,CAAC,CAAE,MAAM,CAAC,KAAiC;QAC3C,CAAC,CAAC,IAAI,CAAC;IACX,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,GAAG,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,MAAM,cAAc,EAAE,CAAC;IACvC,MAAM,aAAa,GAAG,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;QACvD,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;QACtC,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,EAAE,GAAG,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAEnF,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACrF,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxF,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,YAAY,GAAG,QAAQ,CAAC,IAA+B,CAAC;QAE9D,0EAA0E;QAC1E,0EAA0E;QAC1E,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,aAAa,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;YACjE,+DAA+D;YAC/D,qEAAqE;YACrE,uEAAuE;YACvE,uDAAuD;YACvD,IAAI,OAAO,QAAQ,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;gBACvE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;gBAClE,MAAM,OAAO,CAAC,eAAe,CAAC,aAAa,EAAE,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;gBACtE,MAAM,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC;gBAC1D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;gBAC3D,0EAA0E;gBAC1E,MAAM,OAAO,CAAC,aAAa,CAAC,aAAa,EAAE,EAAE,EAAE;oBAC7C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;oBACd,MAAM,EAAE,SAAS;oBACjB,IAAI,EAAE,YAAY;oBAClB,GAAG,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/D,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9B,CAAC,CAAC;gBACH,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC;YAC1D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YAC3D,MAAM,OAAO,CAAC,aAAa,CAAC,aAAa,EAAE,EAAE,EAAE;gBAC7C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,SAAS;gBACjB,IAAI,EAAE,YAAY;gBAClB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mEAAmE;QACnE,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutate.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"mutate.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AASxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAahE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiDjE"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export const prerender = false;
|
|
2
|
-
import { isEditorAuthenticated } from "../auth/session.js";
|
|
2
|
+
import { isEditorAuthenticated, getEditorId } from "../auth/session.js";
|
|
3
3
|
import { getRuntimeConfig } from "../config.js";
|
|
4
4
|
import { executeMutation } from "../mutations/engine.js";
|
|
5
|
+
import { getRuntimeServices } from "../providers.js";
|
|
6
|
+
import { SessionOverlayAdapter } from "../storage/session-overlay-adapter.js";
|
|
5
7
|
import { json, resolveAdapter, enforceCsrfHeader, readJsonBody } from "./_helpers.js";
|
|
6
8
|
export async function GET(context) {
|
|
7
9
|
const runtime = getRuntimeConfig();
|
|
@@ -25,11 +27,43 @@ export async function POST(context) {
|
|
|
25
27
|
const parsed = await readJsonBody(context.request);
|
|
26
28
|
if (!parsed.ok)
|
|
27
29
|
return parsed.response;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// Body-block edits are ALWAYS drafts, independent of the preview cookie that
|
|
31
|
+
// routes other mutations through the overlay: written through the base
|
|
32
|
+
// markdown adapter they'd be serialized into frontmatter. Build the editor's
|
|
33
|
+
// persistent draft overlay explicitly, exactly like the publish route does.
|
|
34
|
+
const isMdBlock = typeof parsed.value === "object" &&
|
|
35
|
+
parsed.value !== null &&
|
|
36
|
+
parsed.value.type === "md_block";
|
|
37
|
+
let adapter;
|
|
38
|
+
let options;
|
|
39
|
+
if (isMdBlock) {
|
|
40
|
+
const editorId = getEditorId(context);
|
|
41
|
+
if (!editorId)
|
|
42
|
+
return json({ error: "No editor draft session" }, 400);
|
|
43
|
+
const services = await getRuntimeServices();
|
|
44
|
+
const base = services.adapter;
|
|
45
|
+
if (!base.makeEditorOverlay) {
|
|
46
|
+
return json({ error: "Drafts are not supported by the configured storage adapter" }, 400);
|
|
47
|
+
}
|
|
48
|
+
adapter = new SessionOverlayAdapter(base, await base.makeEditorOverlay(editorId));
|
|
49
|
+
options = { allowedClasses: services.allowedClasses };
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
adapter = await resolveAdapter();
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const result = await executeMutation(adapter, parsed.value, options);
|
|
56
|
+
if (!result.ok) {
|
|
57
|
+
return json(result.body, result.status);
|
|
58
|
+
}
|
|
59
|
+
return json(result.body, 200);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// An adapter throw (full/read-only disk, KV outage) must surface as a
|
|
63
|
+
// curated JSON error, not a framework 500 that can leak a stack or a
|
|
64
|
+
// filesystem path. Log server-side, return an opaque message.
|
|
65
|
+
console.error("[caretcms] Mutation failed:", error);
|
|
66
|
+
return json({ error: "Mutation failed" }, 500);
|
|
32
67
|
}
|
|
33
|
-
return json(result.body, 200);
|
|
34
68
|
}
|
|
35
69
|
//# sourceMappingURL=mutate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../../src/runtime/routes/mutate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/publish.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAcxC;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/publish.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAcxC;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4DjE"}
|
|
@@ -45,7 +45,7 @@ export async function POST(context) {
|
|
|
45
45
|
return json({ error: "Drafts are not supported by the configured storage adapter" }, 400);
|
|
46
46
|
}
|
|
47
47
|
const overlay = await base.makeEditorOverlay(editorId);
|
|
48
|
-
const published = await publishOverlay(base, overlay, scope);
|
|
48
|
+
const { published, conflicts } = await publishOverlay(base, overlay, scope);
|
|
49
49
|
// Best-effort git journal (opt-in via CARET_GIT_ON_PUBLISH): turn the publish
|
|
50
50
|
// into a commit when content lives in a git repo. Runs AFTER the publish, so a
|
|
51
51
|
// git failure never blocks or reverts it; no-ops on non-filesystem adapters.
|
|
@@ -70,6 +70,9 @@ export async function POST(context) {
|
|
|
70
70
|
commit,
|
|
71
71
|
})
|
|
72
72
|
: { triggered: false, ok: true };
|
|
73
|
-
|
|
73
|
+
// Conflicted entries keep their drafts; the client surfaces them so the
|
|
74
|
+
// editor can reload (fresh stamps) and re-apply. `ok` reflects the whole
|
|
75
|
+
// request having been processed, not per-entry success — check `conflicts`.
|
|
76
|
+
return json({ ok: true, published, conflicts, commit, rebuild });
|
|
74
77
|
}
|
|
75
78
|
//# sourceMappingURL=publish.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/runtime/routes/publish.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAG/B,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAqB,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEtE,SAAS,aAAa,CAAC,KAAmB,EAAE,KAAa;IACvD,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,EAAE;QAAE,OAAO,WAAW,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;IACnF,IAAI,KAAK,CAAC,UAAU;QAAE,OAAO,WAAW,KAAK,CAAC,UAAU,KAAK,KAAK,GAAG,CAAC;IACtE,OAAO,oBAAoB,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC;AAC3E,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAmB;IAC5C,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAEjF,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,EAAE,GAAG,CAAC,CAAC;IAEtE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IACvC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAA2C,CAAC;IAE5E,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;QAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IAC5E,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;QAAE,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IACpD,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC5C,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;IACnC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,4DAA4D,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;
|
|
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,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/runtime/routes/schema.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAWxC,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmEhE"}
|