@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.
- package/README.md +117 -6
- package/dist/browser-runtime.d.ts.map +1 -1
- package/dist/browser-runtime.js +34 -20
- package/dist/browser-runtime.js.map +1 -1
- package/dist/contracts.d.ts +14 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +14 -0
- package/dist/contracts.js.map +1 -0
- package/dist/editable.d.ts +28 -0
- package/dist/editable.d.ts.map +1 -0
- package/dist/editable.js +122 -0
- package/dist/editable.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +134 -2
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +45 -3
- package/dist/loader.js.map +1 -1
- package/dist/providers/storage/markdown.d.ts +7 -0
- package/dist/providers/storage/markdown.d.ts.map +1 -0
- package/dist/providers/storage/markdown.js +6 -0
- package/dist/providers/storage/markdown.js.map +1 -0
- package/dist/runtime/auth/cookie-utils.d.ts +1 -0
- package/dist/runtime/auth/cookie-utils.d.ts.map +1 -1
- package/dist/runtime/auth/cookie-utils.js +1 -1
- package/dist/runtime/auth/cookie-utils.js.map +1 -1
- package/dist/runtime/auth/rate-limiter.d.ts.map +1 -1
- package/dist/runtime/auth/rate-limiter.js +19 -13
- package/dist/runtime/auth/rate-limiter.js.map +1 -1
- package/dist/runtime/auth/session.d.ts +8 -0
- package/dist/runtime/auth/session.d.ts.map +1 -1
- package/dist/runtime/auth/session.js +72 -11
- package/dist/runtime/auth/session.js.map +1 -1
- package/dist/runtime/config.d.ts +1 -0
- package/dist/runtime/config.d.ts.map +1 -1
- package/dist/runtime/config.js +2 -1
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/git-journal.d.ts +19 -0
- package/dist/runtime/git-journal.d.ts.map +1 -0
- package/dist/runtime/git-journal.js +64 -0
- package/dist/runtime/git-journal.js.map +1 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/middleware.js +125 -8
- package/dist/runtime/middleware.js.map +1 -1
- package/dist/runtime/mutations/contracts.d.ts.map +1 -1
- package/dist/runtime/mutations/contracts.js +7 -4
- package/dist/runtime/mutations/contracts.js.map +1 -1
- package/dist/runtime/mutations/engine.d.ts +7 -0
- package/dist/runtime/mutations/engine.d.ts.map +1 -1
- package/dist/runtime/mutations/engine.js +30 -17
- package/dist/runtime/mutations/engine.js.map +1 -1
- package/dist/runtime/providers.d.ts +7 -0
- package/dist/runtime/providers.d.ts.map +1 -1
- package/dist/runtime/providers.js +10 -0
- package/dist/runtime/providers.js.map +1 -1
- package/dist/runtime/publish.d.ts +38 -0
- package/dist/runtime/publish.d.ts.map +1 -0
- package/dist/runtime/publish.js +71 -0
- package/dist/runtime/publish.js.map +1 -0
- package/dist/runtime/request-context.d.ts +19 -0
- package/dist/runtime/request-context.d.ts.map +1 -1
- package/dist/runtime/request-context.js.map +1 -1
- package/dist/runtime/rewrite.d.ts +11 -1
- package/dist/runtime/rewrite.d.ts.map +1 -1
- package/dist/runtime/rewrite.js +21 -15
- package/dist/runtime/rewrite.js.map +1 -1
- package/dist/runtime/rich-allowlist.d.ts +28 -0
- package/dist/runtime/rich-allowlist.d.ts.map +1 -0
- package/dist/runtime/rich-allowlist.js +43 -0
- package/dist/runtime/rich-allowlist.js.map +1 -0
- package/dist/runtime/routes/_helpers.d.ts +26 -0
- package/dist/runtime/routes/_helpers.d.ts.map +1 -1
- package/dist/runtime/routes/_helpers.js +83 -0
- package/dist/runtime/routes/_helpers.js.map +1 -1
- package/dist/runtime/routes/admin.d.ts.map +1 -1
- package/dist/runtime/routes/admin.js +55 -6
- 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 +25 -8
- 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 +4 -0
- package/dist/runtime/routes/auth-logout.js.map +1 -1
- package/dist/runtime/routes/collections-metadata.d.ts.map +1 -1
- package/dist/runtime/routes/collections-metadata.js +4 -2
- package/dist/runtime/routes/collections-metadata.js.map +1 -1
- package/dist/runtime/routes/draft.d.ts +8 -0
- package/dist/runtime/routes/draft.d.ts.map +1 -0
- package/dist/runtime/routes/draft.js +38 -0
- package/dist/runtime/routes/draft.js.map +1 -0
- package/dist/runtime/routes/history.d.ts.map +1 -1
- package/dist/runtime/routes/history.js +21 -8
- 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 +5 -9
- package/dist/runtime/routes/mutate.js.map +1 -1
- package/dist/runtime/routes/publish.d.ts +9 -0
- package/dist/runtime/routes/publish.d.ts.map +1 -0
- package/dist/runtime/routes/publish.js +66 -0
- package/dist/runtime/routes/publish.js.map +1 -0
- package/dist/runtime/routes/schema.d.ts.map +1 -1
- package/dist/runtime/routes/schema.js +4 -2
- package/dist/runtime/routes/schema.js.map +1 -1
- package/dist/runtime/routes/upload.d.ts.map +1 -1
- package/dist/runtime/routes/upload.js +16 -3
- package/dist/runtime/routes/upload.js.map +1 -1
- package/dist/runtime/sanitize-html.d.ts +8 -2
- package/dist/runtime/sanitize-html.d.ts.map +1 -1
- package/dist/runtime/sanitize-html.js +57 -38
- package/dist/runtime/sanitize-html.js.map +1 -1
- package/dist/runtime/stega.d.ts +38 -0
- package/dist/runtime/stega.d.ts.map +1 -0
- package/dist/runtime/stega.js +98 -0
- package/dist/runtime/stega.js.map +1 -0
- package/dist/runtime/storage/atomic-write.d.ts +22 -0
- package/dist/runtime/storage/atomic-write.d.ts.map +1 -0
- package/dist/runtime/storage/atomic-write.js +44 -0
- package/dist/runtime/storage/atomic-write.js.map +1 -0
- package/dist/runtime/storage/filesystem-adapter.d.ts +14 -11
- package/dist/runtime/storage/filesystem-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/filesystem-adapter.js +71 -201
- package/dist/runtime/storage/filesystem-adapter.js.map +1 -1
- package/dist/runtime/storage/frontmatter-codec.d.ts +47 -0
- package/dist/runtime/storage/frontmatter-codec.d.ts.map +1 -0
- package/dist/runtime/storage/frontmatter-codec.js +515 -0
- package/dist/runtime/storage/frontmatter-codec.js.map +1 -0
- package/dist/runtime/storage/fs-runtime.d.ts +8 -0
- package/dist/runtime/storage/fs-runtime.d.ts.map +1 -0
- package/dist/runtime/storage/fs-runtime.js +40 -0
- package/dist/runtime/storage/fs-runtime.js.map +1 -0
- package/dist/runtime/storage/id-contracts.d.ts +22 -0
- package/dist/runtime/storage/id-contracts.d.ts.map +1 -0
- package/dist/runtime/storage/id-contracts.js +27 -0
- package/dist/runtime/storage/id-contracts.js.map +1 -0
- package/dist/runtime/storage/image-validation.d.ts +10 -0
- package/dist/runtime/storage/image-validation.d.ts.map +1 -1
- package/dist/runtime/storage/image-validation.js +17 -4
- package/dist/runtime/storage/image-validation.js.map +1 -1
- package/dist/runtime/storage/in-memory-adapter.d.ts +4 -0
- package/dist/runtime/storage/in-memory-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/in-memory-adapter.js +11 -0
- package/dist/runtime/storage/in-memory-adapter.js.map +1 -1
- package/dist/runtime/storage/markdown-adapter.d.ts +63 -0
- package/dist/runtime/storage/markdown-adapter.d.ts.map +1 -0
- package/dist/runtime/storage/markdown-adapter.js +227 -0
- package/dist/runtime/storage/markdown-adapter.js.map +1 -0
- package/dist/runtime/storage/quota-upload-handler.d.ts +2 -0
- package/dist/runtime/storage/quota-upload-handler.d.ts.map +1 -1
- package/dist/runtime/storage/quota-upload-handler.js +34 -8
- package/dist/runtime/storage/quota-upload-handler.js.map +1 -1
- package/dist/runtime/storage/session-overlay-adapter.d.ts +3 -0
- package/dist/runtime/storage/session-overlay-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/session-overlay-adapter.js +3 -1
- package/dist/runtime/storage/session-overlay-adapter.js.map +1 -1
- package/dist/runtime/storage/sidecar-meta-store.d.ts +51 -0
- package/dist/runtime/storage/sidecar-meta-store.d.ts.map +1 -0
- package/dist/runtime/storage/sidecar-meta-store.js +209 -0
- package/dist/runtime/storage/sidecar-meta-store.js.map +1 -0
- package/dist/runtime/themes/preset-tokens.d.ts +0 -1
- package/dist/runtime/themes/preset-tokens.d.ts.map +1 -1
- package/dist/runtime/themes/preset-tokens.js +1 -1
- package/dist/runtime/themes/preset-tokens.js.map +1 -1
- package/dist/runtime/utils.d.ts +9 -1
- package/dist/runtime/utils.d.ts.map +1 -1
- package/dist/runtime/utils.js +21 -1
- package/dist/runtime/utils.js.map +1 -1
- package/dist/schema-utils.d.ts.map +1 -1
- package/dist/schema-utils.js +1 -0
- package/dist/schema-utils.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -1
- package/static/cms/dev-toolbar/app.js +263 -0
- package/static/cms/editor/highlight.js +46 -0
- package/static/cms/editor/sanitize.js +48 -5
- package/static/cms/editor/stega-hydrate.js +80 -0
- package/static/cms/editor/text-edit.js +22 -0
- package/static/cms/editor/tokens-and-text.css +1 -1
- package/static/cms/editor/toolbar.css +42 -0
- package/static/cms/editor/toolbar.js +97 -15
- package/static/cms/editor.js +15 -0
- package/static/cms/signin-hint.css +74 -0
- package/dist/runtime/schema/template.d.ts +0 -15
- package/dist/runtime/schema/template.d.ts.map +0 -1
- package/dist/runtime/schema/template.js +0 -38
- package/dist/runtime/schema/template.js.map +0 -1
|
@@ -1,23 +1,43 @@
|
|
|
1
|
-
import { createHmac, timingSafeEqual } from "crypto";
|
|
1
|
+
import { createHmac, randomUUID, timingSafeEqual } from "crypto";
|
|
2
2
|
import { shouldUseSecureCookies } from "./cookie-utils.js";
|
|
3
3
|
import { getRequestContext } from "../request-context.js";
|
|
4
4
|
const SESSION_COOKIE_NAME = "caret_session";
|
|
5
5
|
const SESSION_TTL_SECONDS = 60 * 60 * 12;
|
|
6
6
|
const DEV_SECRET_FALLBACK = "caretcms-dev-secret";
|
|
7
7
|
let devSecretWarned = false;
|
|
8
|
-
function
|
|
8
|
+
function getConfiguredEditorPassword() {
|
|
9
9
|
const value = process.env.CARET_EDIT_PASSWORD ?? process.env.EDIT_PASSWORD ?? "";
|
|
10
10
|
return value.trim().length > 0 ? value : null;
|
|
11
11
|
}
|
|
12
|
+
// During `astro dev`, the integration generates a throwaway password and exposes
|
|
13
|
+
// it via the __ASTRO_CARET_DEV_PASSWORD__ define so a freshly-installed site can
|
|
14
|
+
// sign in without any setup. Never honored in production: the define is empty in
|
|
15
|
+
// a production build, and we additionally refuse it when NODE_ENV is production.
|
|
16
|
+
function getDevFallbackPassword() {
|
|
17
|
+
if (process.env.NODE_ENV === "production")
|
|
18
|
+
return null;
|
|
19
|
+
const dev = typeof __ASTRO_CARET_DEV_PASSWORD__ === "string"
|
|
20
|
+
? __ASTRO_CARET_DEV_PASSWORD__
|
|
21
|
+
: "";
|
|
22
|
+
return dev.length > 0 ? dev : null;
|
|
23
|
+
}
|
|
24
|
+
function getEditorPassword() {
|
|
25
|
+
return getConfiguredEditorPassword() ?? getDevFallbackPassword();
|
|
26
|
+
}
|
|
27
|
+
// True when the only thing unlocking the editor is the dev fallback — i.e. the
|
|
28
|
+
// developer hasn't set a real password yet. Drives the on-page setup hint.
|
|
29
|
+
export function isDevEditorPasswordActive() {
|
|
30
|
+
return getConfiguredEditorPassword() === null && getDevFallbackPassword() !== null;
|
|
31
|
+
}
|
|
12
32
|
function getSessionSecret() {
|
|
13
33
|
const configured = process.env.CARET_SESSION_SECRET;
|
|
14
34
|
if (configured && configured.trim().length > 0)
|
|
15
35
|
return configured;
|
|
16
|
-
// No secret configured. Safe to fall back
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// production and warn loudly in dev.
|
|
20
|
-
if (
|
|
36
|
+
// No secret configured. Safe to fall back when no real password is set — that
|
|
37
|
+
// includes the dev-only throwaway password, which is itself dev-gated. Once a
|
|
38
|
+
// real password is configured the dev fallback is a known string that lets
|
|
39
|
+
// anyone forge a session — refuse it in production and warn loudly in dev.
|
|
40
|
+
if (getConfiguredEditorPassword() === null)
|
|
21
41
|
return DEV_SECRET_FALLBACK;
|
|
22
42
|
if (process.env.NODE_ENV === "production") {
|
|
23
43
|
throw new Error("[caretcms] CARET_SESSION_SECRET is required in production when CARET_EDIT_PASSWORD is set. " +
|
|
@@ -33,6 +53,27 @@ function getSessionSecret() {
|
|
|
33
53
|
function signPayload(payloadB64) {
|
|
34
54
|
return createHmac("sha256", getSessionSecret()).update(payloadB64).digest("base64url");
|
|
35
55
|
}
|
|
56
|
+
let secretErrorLogged = false;
|
|
57
|
+
/**
|
|
58
|
+
* The missing-secret misconfiguration must hard-fail where a session is MINTED
|
|
59
|
+
* (login) — but it must not take the whole site down: the pre-middleware checks
|
|
60
|
+
* every request that carries a `caret_session` cookie, so an unguarded throw
|
|
61
|
+
* here turns one missing env var into a 500 on every page for every visitor
|
|
62
|
+
* with a stale cookie. Verification therefore fails closed ("not an editor")
|
|
63
|
+
* and logs the cause once for the operator.
|
|
64
|
+
*/
|
|
65
|
+
function trySignPayload(payloadB64) {
|
|
66
|
+
try {
|
|
67
|
+
return signPayload(payloadB64);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (!secretErrorLogged) {
|
|
71
|
+
secretErrorLogged = true;
|
|
72
|
+
console.error(`${err.message} Editor sessions are disabled until it is set.`);
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
36
77
|
function serializeEditorSessionCookie(value, path, maxAge, request) {
|
|
37
78
|
const parts = [
|
|
38
79
|
`${SESSION_COOKIE_NAME}=${value}`,
|
|
@@ -58,7 +99,9 @@ function parseToken(token) {
|
|
|
58
99
|
const [payloadB64, signature] = parts;
|
|
59
100
|
if (!payloadB64 || !signature)
|
|
60
101
|
return null;
|
|
61
|
-
const expected =
|
|
102
|
+
const expected = trySignPayload(payloadB64);
|
|
103
|
+
if (expected === null)
|
|
104
|
+
return null;
|
|
62
105
|
let sigBuf;
|
|
63
106
|
let expectedBuf;
|
|
64
107
|
try {
|
|
@@ -83,6 +126,9 @@ function parseToken(token) {
|
|
|
83
126
|
return null;
|
|
84
127
|
if (payload.exp <= Date.now())
|
|
85
128
|
return null;
|
|
129
|
+
// editorId is optional (legacy tokens lack it), but reject a malformed one.
|
|
130
|
+
if (payload.editorId !== undefined && typeof payload.editorId !== "string")
|
|
131
|
+
return null;
|
|
86
132
|
return payload;
|
|
87
133
|
}
|
|
88
134
|
catch {
|
|
@@ -104,7 +150,7 @@ export function isEditorPasswordValid(candidate) {
|
|
|
104
150
|
}
|
|
105
151
|
export function issueEditorSessionCookie(path = "/", request) {
|
|
106
152
|
const exp = Date.now() + SESSION_TTL_SECONDS * 1000;
|
|
107
|
-
const token = buildToken({ editor: true, exp });
|
|
153
|
+
const token = buildToken({ editor: true, exp, editorId: randomUUID() });
|
|
108
154
|
return serializeEditorSessionCookie(encodeURIComponent(token), path, SESSION_TTL_SECONDS, request);
|
|
109
155
|
}
|
|
110
156
|
export function clearEditorSessionCookie(path = "/", request) {
|
|
@@ -116,13 +162,28 @@ export function hasConfiguredEditorPassword() {
|
|
|
116
162
|
export function isEditorAuthenticated(context) {
|
|
117
163
|
// Demo mode: any visitor with a resolved sandbox session is an editor of
|
|
118
164
|
// their own private overlay. Middleware sets `demoMode` + `sessionId` in
|
|
119
|
-
// the request-scoped ALS context before this check runs.
|
|
165
|
+
// the request-scoped ALS context before this check runs. We require
|
|
166
|
+
// `overlayActive` too: without an installed per-session overlay, writes
|
|
167
|
+
// would land in the shared base store, so granting editor rights would be
|
|
168
|
+
// an unauthenticated-write hole. Fail closed when the overlay is absent.
|
|
120
169
|
const ctx = getRequestContext();
|
|
121
|
-
if (ctx?.demoMode && ctx.sessionId)
|
|
170
|
+
if (ctx?.demoMode && ctx.sessionId && ctx.overlayActive)
|
|
122
171
|
return true;
|
|
123
172
|
const token = context.cookies?.get(SESSION_COOKIE_NAME)?.value;
|
|
124
173
|
if (!token)
|
|
125
174
|
return false;
|
|
126
175
|
return parseToken(token) !== null;
|
|
127
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* The per-editor id carried by the session cookie, used to key a draft overlay.
|
|
179
|
+
* Returns null when the request has no valid editor session, or when the session
|
|
180
|
+
* predates editor ids (a legacy token). Does NOT consider demo sessions — those
|
|
181
|
+
* are keyed by their own `sessionId`.
|
|
182
|
+
*/
|
|
183
|
+
export function getEditorId(context) {
|
|
184
|
+
const token = context.cookies?.get(SESSION_COOKIE_NAME)?.value;
|
|
185
|
+
if (!token)
|
|
186
|
+
return null;
|
|
187
|
+
return parseToken(token)?.editorId ?? null;
|
|
188
|
+
}
|
|
128
189
|
//# sourceMappingURL=session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/runtime/auth/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/runtime/auth/session.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/config.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/runtime/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/runtime/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAEF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CASjF;AAsBD,wBAAgB,gBAAgB,IAAI,kBAAkB,CAerD"}
|
package/dist/runtime/config.js
CHANGED
|
@@ -32,9 +32,10 @@ const DEFAULT_THEME = {
|
|
|
32
32
|
export function getRuntimeConfig() {
|
|
33
33
|
const mountPath = normalizePath(__ASTRO_CARET_MOUNT_PATH__, "/admin");
|
|
34
34
|
const apiBasePath = normalizePath(__ASTRO_CARET_API_BASE_PATH__, "/api/cms");
|
|
35
|
+
const editorHome = normalizePath(__ASTRO_CARET_EDITOR_HOME__, "/");
|
|
35
36
|
const mode = (__ASTRO_CARET_MODE__ ?? "embedded");
|
|
36
37
|
const theme = safeParse(__ASTRO_CARET_THEME_CONFIG__, DEFAULT_THEME);
|
|
37
38
|
const brand = safeParse(__ASTRO_CARET_BRAND_CONFIG__, DEFAULT_BRAND);
|
|
38
|
-
return { mountPath, apiBasePath, mode, theme, brand };
|
|
39
|
+
return { mountPath, apiBasePath, editorHome, mode, theme, brand };
|
|
39
40
|
}
|
|
40
41
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/runtime/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/runtime/config.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,aAAa,CAAC,KAAyB,EAAE,QAAgB;IACvE,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;IAC3E,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS,CAAI,GAAuB,EAAE,QAAW;IACxD,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,aAAa,GAAqB;IACtC,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,IAAI;IACV,UAAU,EAAE,IAAI;CACjB,CAAC;AAEF,MAAM,aAAa,GAAqB;IACtC,QAAQ,EAAE,IAAI;IACd,cAAc,EAAE,EAAE;CACnB,CAAC;AAEF,MAAM,UAAU,gBAAgB;IAC9B,MAAM,SAAS,GAAG,aAAa,CAAC,0BAA0B,EAAE,QAAQ,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,aAAa,CAAC,6BAA6B,EAAE,UAAU,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,aAAa,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;IACnE,MAAM,IAAI,GAAG,CAAC,oBAAoB,IAAI,UAAU,CAAc,CAAC;IAC/D,MAAM,KAAK,GAAG,SAAS,CACrB,4BAA4B,EAC5B,aAAa,CACd,CAAC;IACF,MAAM,KAAK,GAAG,SAAS,CACrB,4BAA4B,EAC5B,aAAa,CACd,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** True when `cwd` is inside a git work tree. */
|
|
2
|
+
export declare function isGitRepo(cwd: string): Promise<boolean>;
|
|
3
|
+
export interface CommitOptions {
|
|
4
|
+
/** Repo working directory (a publish runs from the project root). */
|
|
5
|
+
cwd: string;
|
|
6
|
+
/** Files to stage + commit (absolute or repo-relative). Adds, edits, deletes. */
|
|
7
|
+
paths: string[];
|
|
8
|
+
message: string;
|
|
9
|
+
/** Commit author/committer identity (e.g. the editor). Falls back to git config. */
|
|
10
|
+
authorName?: string;
|
|
11
|
+
authorEmail?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Stage `paths` and commit them. Returns the new commit SHA, or null when there
|
|
15
|
+
* is nothing to commit or anything goes wrong (not a repo, git missing, no diff,
|
|
16
|
+
* git error). Never throws.
|
|
17
|
+
*/
|
|
18
|
+
export declare function commitPaths(opts: CommitOptions): Promise<string | null>;
|
|
19
|
+
//# sourceMappingURL=git-journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-journal.d.ts","sourceRoot":"","sources":["../../src/runtime/git-journal.ts"],"names":[],"mappings":"AAkBA,iDAAiD;AACjD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,iFAAiF;IACjF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoC7E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git journal — best-effort, opt-in commit of published content.
|
|
3
|
+
*
|
|
4
|
+
* When content lives as files in a git repo, a publish can become a real commit:
|
|
5
|
+
* blame, revert, branch-per-draft, and PR review of content all come for free.
|
|
6
|
+
* This is deliberately BEST-EFFORT — a git failure logs and returns null, never
|
|
7
|
+
* throwing into the publish path or blocking the response. Guarded by
|
|
8
|
+
* `isGitRepo`, so non-filesystem deployments (KV/R2) simply never call it.
|
|
9
|
+
*
|
|
10
|
+
* Uses the `git` CLI (already a dependency of preflight) via async execFile, so
|
|
11
|
+
* it never blocks the event loop. Commits are scoped with a pathspec so only the
|
|
12
|
+
* published files land in the commit, never unrelated working-tree changes.
|
|
13
|
+
*/
|
|
14
|
+
import { execFile } from "node:child_process";
|
|
15
|
+
import { promisify } from "node:util";
|
|
16
|
+
const exec = promisify(execFile);
|
|
17
|
+
/** True when `cwd` is inside a git work tree. */
|
|
18
|
+
export async function isGitRepo(cwd) {
|
|
19
|
+
try {
|
|
20
|
+
const { stdout } = await exec("git", ["rev-parse", "--is-inside-work-tree"], { cwd });
|
|
21
|
+
return stdout.trim() === "true";
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Stage `paths` and commit them. Returns the new commit SHA, or null when there
|
|
29
|
+
* is nothing to commit or anything goes wrong (not a repo, git missing, no diff,
|
|
30
|
+
* git error). Never throws.
|
|
31
|
+
*/
|
|
32
|
+
export async function commitPaths(opts) {
|
|
33
|
+
if (opts.paths.length === 0)
|
|
34
|
+
return null;
|
|
35
|
+
try {
|
|
36
|
+
// Stage adds/edits/deletes for exactly these paths.
|
|
37
|
+
await exec("git", ["add", "--", ...opts.paths], { cwd: opts.cwd });
|
|
38
|
+
// Nothing actually changed for these paths → skip an empty commit.
|
|
39
|
+
const { stdout: staged } = await exec("git", ["diff", "--cached", "--name-only", "--", ...opts.paths], { cwd: opts.cwd });
|
|
40
|
+
if (!staged.trim())
|
|
41
|
+
return null;
|
|
42
|
+
const env = { ...process.env };
|
|
43
|
+
if (opts.authorName) {
|
|
44
|
+
env.GIT_AUTHOR_NAME = opts.authorName;
|
|
45
|
+
env.GIT_COMMITTER_NAME = opts.authorName;
|
|
46
|
+
}
|
|
47
|
+
if (opts.authorEmail) {
|
|
48
|
+
env.GIT_AUTHOR_EMAIL = opts.authorEmail;
|
|
49
|
+
env.GIT_COMMITTER_EMAIL = opts.authorEmail;
|
|
50
|
+
}
|
|
51
|
+
// Pathspec limits the commit to these files even if other things are staged.
|
|
52
|
+
await exec("git", ["commit", "-m", opts.message, "--", ...opts.paths], {
|
|
53
|
+
cwd: opts.cwd,
|
|
54
|
+
env,
|
|
55
|
+
});
|
|
56
|
+
const { stdout: sha } = await exec("git", ["rev-parse", "HEAD"], { cwd: opts.cwd });
|
|
57
|
+
return sha.trim();
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.warn(`[caretcms] git journal commit skipped: ${err.message}`);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=git-journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-journal.js","sourceRoot":"","sources":["../../src/runtime/git-journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEjC,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACtF,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,MAAM,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAaD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAmB;IACnD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC;QACH,oDAAoD;QACpD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAEnE,mEAAmE;QACnE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CACnC,KAAK,EACL,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EACxD,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAClB,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO,IAAI,CAAC;QAEhC,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC;YACtC,GAAG,CAAC,kBAAkB,GAAG,IAAI,CAAC,UAAU,CAAC;QAC3C,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC;YACxC,GAAG,CAAC,mBAAmB,GAAG,IAAI,CAAC,WAAW,CAAC;QAC7C,CAAC;QAED,6EAA6E;QAC7E,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE;YACrE,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG;SACJ,CAAC,CAAC;QAEH,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACpF,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,0CAA2C,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export type { EntryData } from "./content.js";
|
|
|
9
9
|
export { SessionOverlayAdapter } from "./storage/session-overlay-adapter.js";
|
|
10
10
|
export { QuotaUploadHandler } from "./storage/quota-upload-handler.js";
|
|
11
11
|
export type { QuotaCounter, QuotaUploadHandlerOptions, } from "./storage/quota-upload-handler.js";
|
|
12
|
-
export { IMAGE_KIND_TO_EXT, IMAGE_MAX_SIZE, IMAGE_MIME_TO_KIND, detectImageKind, readAndValidateImage, sanitizeImageBaseName, } from "./storage/image-validation.js";
|
|
12
|
+
export { IMAGE_KIND_TO_EXT, IMAGE_MAX_SIZE, IMAGE_MIME_TO_KIND, UploadError, detectImageKind, readAndValidateImage, sanitizeImageBaseName, } from "./storage/image-validation.js";
|
|
13
13
|
export type { AllowedImageKind } from "./storage/image-validation.js";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1E,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,YAAY,EACV,YAAY,EACZ,yBAAyB,GAC1B,MAAM,mCAAmC,CAAC;AAI3C,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1E,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,YAAY,EACV,YAAY,EACZ,yBAAyB,GAC1B,MAAM,mCAAmC,CAAC;AAI3C,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/runtime/index.js
CHANGED
|
@@ -12,5 +12,5 @@ export { SessionOverlayAdapter } from "./storage/session-overlay-adapter.js";
|
|
|
12
12
|
export { QuotaUploadHandler } from "./storage/quota-upload-handler.js";
|
|
13
13
|
// Shared image-upload validation — adapter authors should call
|
|
14
14
|
// readAndValidateImage() before writing user-supplied bytes to storage.
|
|
15
|
-
export { IMAGE_KIND_TO_EXT, IMAGE_MAX_SIZE, IMAGE_MIME_TO_KIND, detectImageKind, readAndValidateImage, sanitizeImageBaseName, } from "./storage/image-validation.js";
|
|
15
|
+
export { IMAGE_KIND_TO_EXT, IMAGE_MAX_SIZE, IMAGE_MIME_TO_KIND, UploadError, detectImageKind, readAndValidateImage, sanitizeImageBaseName, } from "./storage/image-validation.js";
|
|
16
16
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6DAA6D;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,4EAA4E;AAC5E,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG1E,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAMvE,+DAA+D;AAC/D,wEAAwE;AACxE,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6DAA6D;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,4EAA4E;AAC5E,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG1E,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAMvE,+DAA+D;AAC/D,wEAAwE;AACxE,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/runtime/middleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/runtime/middleware.ts"],"names":[],"mappings":"AAUA,OAAO,0BAA0B,CAAC;AAElC,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE;QACR,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;KACtD,CAAC;IACF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAqFF,KAAK,cAAc,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE9C,wBAAsB,SAAS,CAC7B,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,QAAQ,CAAC,CAgInB"}
|
|
@@ -1,12 +1,69 @@
|
|
|
1
|
-
import { isEditorAuthenticated } from "./auth/session.js";
|
|
1
|
+
import { isEditorAuthenticated, getEditorId } from "./auth/session.js";
|
|
2
2
|
import { isDemoModeEnabled, resolveDemoSession } from "./auth/demo-session.js";
|
|
3
3
|
import { getRuntimeServices } from "./providers.js";
|
|
4
4
|
import { runWithRequestContext } from "./request-context.js";
|
|
5
5
|
import { rewriteCaretAttributes } from "./rewrite.js";
|
|
6
|
+
import { hasStega, stegaClean } from "./stega.js";
|
|
6
7
|
import { SessionOverlayAdapter } from "./storage/session-overlay-adapter.js";
|
|
7
8
|
// Side-effect import: registers any user-provided schemas into the schema registry
|
|
8
9
|
import "virtual:caretcms/schemas";
|
|
9
10
|
let _cachedRuntimeEnv;
|
|
11
|
+
let _overlayWarned = false;
|
|
12
|
+
function warnMissingOverlay() {
|
|
13
|
+
if (_overlayWarned)
|
|
14
|
+
return;
|
|
15
|
+
_overlayWarned = true;
|
|
16
|
+
console.warn("[caretcms] CARET_DEMO_MODE is on but the configured storage adapter does " +
|
|
17
|
+
"not implement makeSessionOverlay. Demo editor access is disabled to " +
|
|
18
|
+
"avoid unauthenticated writes to shared storage. Use an adapter with " +
|
|
19
|
+
"session-overlay support (e.g. the filesystem or Cloudflare KV adapters).");
|
|
20
|
+
}
|
|
21
|
+
const PREVIEW_COOKIE = "caret_preview";
|
|
22
|
+
/** Rendered binding attributes: `data-caret="…"` / `data-caret-scope="…"`.
|
|
23
|
+
* Matches the attribute grammar the rewrite engine consumes (whitespace
|
|
24
|
+
* around `=` tolerated), so prose mentions of "data-caret" don't count. */
|
|
25
|
+
const BINDING_PROBE_RE = /\bdata-caret(?:-scope)?\s*=\s*"/;
|
|
26
|
+
/** Is this request for a CMS-owned route (Studio, API, or editor assets)? Those
|
|
27
|
+
* pages are infrastructure, so the authed empty-state hint must never show on
|
|
28
|
+
* them — only on the live site. Conservative: if the path can't be read, treat
|
|
29
|
+
* it as owned (skip the hint). */
|
|
30
|
+
function isCmsOwnedPath(context, mountPath, apiBasePath) {
|
|
31
|
+
const url = context.request?.url;
|
|
32
|
+
if (!url)
|
|
33
|
+
return true;
|
|
34
|
+
let pathname;
|
|
35
|
+
try {
|
|
36
|
+
pathname = new URL(url).pathname;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return (pathname === mountPath ||
|
|
42
|
+
pathname.startsWith(`${mountPath}/`) ||
|
|
43
|
+
pathname.startsWith(apiBasePath) ||
|
|
44
|
+
pathname.startsWith("/__caret"));
|
|
45
|
+
}
|
|
46
|
+
/** Inject the authenticated empty-state hint before `</body>` (falls back to
|
|
47
|
+
* appending). The markup is static — the only interpolation is the normalized,
|
|
48
|
+
* config-controlled mount path — so no escaping is required. */
|
|
49
|
+
function injectSigninHint(html, mountPath) {
|
|
50
|
+
const snippet = `<link rel="stylesheet" href="/__caret/signin-hint.css">` +
|
|
51
|
+
`<div class="caret-signin-hint" role="status">` +
|
|
52
|
+
`<span class="caret-signin-hint__dot" aria-hidden="true"></span>` +
|
|
53
|
+
`<span class="caret-signin-hint__text">Signed in · no editable fields on this page. ` +
|
|
54
|
+
`Run <code>npx @caretcms/caretize</code> to add some, or <a href="${mountPath}/cms">open the Studio</a>.` +
|
|
55
|
+
`</span></div>`;
|
|
56
|
+
const closeBody = html.toLowerCase().lastIndexOf("</body>");
|
|
57
|
+
if (closeBody === -1)
|
|
58
|
+
return html + snippet;
|
|
59
|
+
return html.slice(0, closeBody) + snippet + html.slice(closeBody);
|
|
60
|
+
}
|
|
61
|
+
/** Whether this request opted into draft preview (the editor toggles a cookie).
|
|
62
|
+
* Only meaningful for an authenticated editor — the overlay install also
|
|
63
|
+
* requires a valid editor id. */
|
|
64
|
+
function isPreviewRequest(context) {
|
|
65
|
+
return context.cookies?.get(PREVIEW_COOKIE)?.value === "1";
|
|
66
|
+
}
|
|
10
67
|
async function resolveRuntimeEnv() {
|
|
11
68
|
if (_cachedRuntimeEnv !== undefined)
|
|
12
69
|
return _cachedRuntimeEnv;
|
|
@@ -26,7 +83,9 @@ export async function onRequest(context, next) {
|
|
|
26
83
|
let adapter = services.adapter;
|
|
27
84
|
let uploadHandler = services.uploadHandler;
|
|
28
85
|
let sessionId = null;
|
|
86
|
+
let editorId = null;
|
|
29
87
|
let setCookieHeader = null;
|
|
88
|
+
let overlayActive = false;
|
|
30
89
|
const demoMode = isDemoModeEnabled(runtimeEnv);
|
|
31
90
|
if (demoMode) {
|
|
32
91
|
const request = context.request ?? new Request("http://localhost/");
|
|
@@ -36,13 +95,45 @@ export async function onRequest(context, next) {
|
|
|
36
95
|
if (services.adapter.makeSessionOverlay) {
|
|
37
96
|
const overlay = await services.adapter.makeSessionOverlay(sessionId);
|
|
38
97
|
adapter = new SessionOverlayAdapter(services.adapter, overlay);
|
|
98
|
+
overlayActive = true;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
warnMissingOverlay();
|
|
39
102
|
}
|
|
40
103
|
if (services.uploadHandler.makeSessionWrapper) {
|
|
41
104
|
uploadHandler = await services.uploadHandler.makeSessionWrapper(sessionId);
|
|
42
105
|
}
|
|
43
106
|
}
|
|
44
|
-
|
|
45
|
-
|
|
107
|
+
else if (isPreviewRequest(context) && services.adapter.makeEditorOverlay) {
|
|
108
|
+
// Draft/preview mode: an authenticated editor opting into preview reads and
|
|
109
|
+
// writes through their per-editor overlay (the public site keeps seeing the
|
|
110
|
+
// base). Keyed by the editor id from the session cookie; absent that, there's
|
|
111
|
+
// no editor session so we leave the base adapter in place. Publish later
|
|
112
|
+
// flushes the overlay back to the base.
|
|
113
|
+
const id = getEditorId(context);
|
|
114
|
+
if (id) {
|
|
115
|
+
const overlay = await services.adapter.makeEditorOverlay(id);
|
|
116
|
+
adapter = new SessionOverlayAdapter(services.adapter, overlay);
|
|
117
|
+
overlayActive = true;
|
|
118
|
+
editorId = id;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const requestContext = {
|
|
122
|
+
adapter,
|
|
123
|
+
uploadHandler,
|
|
124
|
+
sessionId,
|
|
125
|
+
editorId,
|
|
126
|
+
demoMode,
|
|
127
|
+
overlayActive,
|
|
128
|
+
editor: false,
|
|
129
|
+
};
|
|
130
|
+
return runWithRequestContext(requestContext, async () => {
|
|
131
|
+
const isEditor = isEditorAuthenticated(context);
|
|
132
|
+
// Demo-overlay editor status depends on the request context (demoMode +
|
|
133
|
+
// overlayActive), so it can only be resolved here, inside the ALS scope.
|
|
134
|
+
// Mutate the live context object so the loaders see the gate during render.
|
|
135
|
+
requestContext.editor = isEditor;
|
|
136
|
+
context.locals.isEditor = isEditor;
|
|
46
137
|
const inner = await next();
|
|
47
138
|
const contentType = inner.headers.get("content-type") ?? "";
|
|
48
139
|
const contentEncoding = inner.headers.get("content-encoding") ?? "";
|
|
@@ -56,15 +147,41 @@ export async function onRequest(context, next) {
|
|
|
56
147
|
let bodyConsumed = false;
|
|
57
148
|
let rewritten = false;
|
|
58
149
|
if (isHtml) {
|
|
59
|
-
|
|
150
|
+
let html = await inner.text();
|
|
60
151
|
bodyConsumed = true;
|
|
61
|
-
|
|
62
|
-
|
|
152
|
+
// Probe for ATTRIBUTE syntax, not the bare substring: a page that merely
|
|
153
|
+
// mentions data-caret in prose (docs, a blog post about the CMS) must not
|
|
154
|
+
// run the rewrite engine or suppress the signed-in empty-state hint.
|
|
155
|
+
// data-caret-rich is a bare attribute but always accompanies data-caret,
|
|
156
|
+
// so the two valued forms cover every binding the engine can act on.
|
|
157
|
+
const hasBindings = BINDING_PROBE_RE.test(html);
|
|
158
|
+
if (hasBindings) {
|
|
159
|
+
html = await rewriteCaretAttributes(html, adapter, {
|
|
160
|
+
allowedClasses: services.allowedClasses,
|
|
161
|
+
});
|
|
63
162
|
rewritten = true;
|
|
64
163
|
}
|
|
65
|
-
|
|
66
|
-
|
|
164
|
+
// Backstop: strip stega metadata from published output so non-editors
|
|
165
|
+
// never receive the invisible characters, even if a value was encoded
|
|
166
|
+
// outside the loader's editor gate. Editors keep it — the overlay decodes
|
|
167
|
+
// it for click-to-edit.
|
|
168
|
+
if (!requestContext.editor && hasStega(html)) {
|
|
169
|
+
html = stegaClean(html);
|
|
170
|
+
rewritten = true;
|
|
171
|
+
}
|
|
172
|
+
// Authenticated empty-state hint: a signed-in editor landing on a live
|
|
173
|
+
// page with zero data-caret bindings would otherwise get no signal that
|
|
174
|
+
// anything happened (reads as "broken"). Show a small affordance pointing
|
|
175
|
+
// at caretize / the Studio. Editors-only and skipped on CMS-owned pages,
|
|
176
|
+
// so the public never sees it and it never clutters the Studio.
|
|
177
|
+
if (services.enableInlineEditor &&
|
|
178
|
+
requestContext.editor &&
|
|
179
|
+
!hasBindings &&
|
|
180
|
+
!isCmsOwnedPath(context, services.mountPath, services.apiBasePath)) {
|
|
181
|
+
html = injectSigninHint(html, services.mountPath);
|
|
182
|
+
rewritten = true;
|
|
67
183
|
}
|
|
184
|
+
body = html;
|
|
68
185
|
}
|
|
69
186
|
if (!bodyConsumed && !setCookieHeader) {
|
|
70
187
|
return inner;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/runtime/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/runtime/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/runtime/mutations/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/runtime/mutations/contracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { COLLECTION_NAME_RE, ENTRY_ID_RE } from "../storage/id-contracts.js";
|
|
1
2
|
export function isRecord(value) {
|
|
2
3
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
4
|
}
|
|
@@ -14,8 +15,6 @@ function asOptionalExpectedRevision(value) {
|
|
|
14
15
|
return value;
|
|
15
16
|
return null;
|
|
16
17
|
}
|
|
17
|
-
const COLLECTION_NAME_RE = /^[a-z][a-z0-9_-]*$/;
|
|
18
|
-
const ENTRY_ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
19
18
|
/**
|
|
20
19
|
* Validate a collection name's *format* (not its existence). A well-formed
|
|
21
20
|
* name is accepted even for a collection that has never been written — writes
|
|
@@ -267,14 +266,18 @@ export async function parseMutationCommand(adapter, input) {
|
|
|
267
266
|
}
|
|
268
267
|
async function parseCreateCollectionCommand(_adapter, input) {
|
|
269
268
|
const issues = [];
|
|
270
|
-
|
|
269
|
+
// Same normalization as every other command (save_field/put_entry/
|
|
270
|
+
// delete_collection all lowercase via parseCollectionName): without it,
|
|
271
|
+
// create_collection("Blog") was rejected while save_field on "Blog" silently
|
|
272
|
+
// wrote to "blog".
|
|
273
|
+
const id = parseCollectionName(input.id);
|
|
271
274
|
const label = asNonEmptyString(input.label);
|
|
272
275
|
const description = typeof input.description === "string" ? input.description : undefined;
|
|
273
276
|
const icon = typeof input.icon === "string" ? input.icon : undefined;
|
|
274
277
|
const creatable = typeof input.creatable === "boolean" ? input.creatable : undefined;
|
|
275
278
|
const orderable = typeof input.orderable === "boolean" ? input.orderable : undefined;
|
|
276
279
|
const schema = input.schema;
|
|
277
|
-
if (!id
|
|
280
|
+
if (!id) {
|
|
278
281
|
issues.push(issue("id", "invalid_type", "Collection ID must be lowercase alphanumeric with hyphens/underscores"));
|
|
279
282
|
}
|
|
280
283
|
if (!label) {
|