@caretcms/core 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -6
- package/dist/browser-runtime.d.ts +16 -0
- package/dist/browser-runtime.d.ts.map +1 -1
- package/dist/browser-runtime.js +42 -23
- 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 +53 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +274 -4
- 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 +16 -0
- package/dist/runtime/providers.d.ts.map +1 -1
- package/dist/runtime/providers.js +16 -0
- package/dist/runtime/providers.js.map +1 -1
- package/dist/runtime/publish.d.ts +40 -0
- package/dist/runtime/publish.d.ts.map +1 -0
- package/dist/runtime/publish.js +75 -0
- package/dist/runtime/publish.js.map +1 -0
- package/dist/runtime/rebuild-webhook.d.ts +29 -0
- package/dist/runtime/rebuild-webhook.d.ts.map +1 -0
- package/dist/runtime/rebuild-webhook.js +37 -0
- package/dist/runtime/rebuild-webhook.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 +29 -1
- package/dist/runtime/rewrite.d.ts.map +1 -1
- package/dist/runtime/rewrite.js +30 -16
- package/dist/runtime/rewrite.js.map +1 -1
- package/dist/runtime/rich-allowlist.d.ts +29 -0
- package/dist/runtime/rich-allowlist.d.ts.map +1 -0
- package/dist/runtime/rich-allowlist.js +49 -0
- package/dist/runtime/rich-allowlist.js.map +1 -0
- package/dist/runtime/routes/_helpers.d.ts +33 -0
- package/dist/runtime/routes/_helpers.d.ts.map +1 -1
- package/dist/runtime/routes/_helpers.js +117 -1
- package/dist/runtime/routes/_helpers.js.map +1 -1
- package/dist/runtime/routes/admin-entry.d.ts +1 -0
- package/dist/runtime/routes/admin-entry.d.ts.map +1 -1
- package/dist/runtime/routes/admin-entry.js +3 -2
- package/dist/runtime/routes/admin-entry.js.map +1 -1
- package/dist/runtime/routes/admin.d.ts +1 -0
- package/dist/runtime/routes/admin.d.ts.map +1 -1
- package/dist/runtime/routes/admin.js +61 -9
- package/dist/runtime/routes/admin.js.map +1 -1
- package/dist/runtime/routes/auth-login.d.ts +1 -0
- package/dist/runtime/routes/auth-login.d.ts.map +1 -1
- package/dist/runtime/routes/auth-login.js +26 -8
- package/dist/runtime/routes/auth-login.js.map +1 -1
- package/dist/runtime/routes/auth-logout.d.ts +1 -0
- package/dist/runtime/routes/auth-logout.d.ts.map +1 -1
- package/dist/runtime/routes/auth-logout.js +5 -0
- package/dist/runtime/routes/auth-logout.js.map +1 -1
- package/dist/runtime/routes/auth-session.d.ts +1 -0
- package/dist/runtime/routes/auth-session.d.ts.map +1 -1
- package/dist/runtime/routes/auth-session.js +1 -0
- package/dist/runtime/routes/auth-session.js.map +1 -1
- package/dist/runtime/routes/collection-list.d.ts +1 -0
- package/dist/runtime/routes/collection-list.d.ts.map +1 -1
- package/dist/runtime/routes/collection-list.js +3 -2
- package/dist/runtime/routes/collection-list.js.map +1 -1
- package/dist/runtime/routes/collections-metadata.d.ts +1 -0
- package/dist/runtime/routes/collections-metadata.d.ts.map +1 -1
- package/dist/runtime/routes/collections-metadata.js +7 -4
- package/dist/runtime/routes/collections-metadata.js.map +1 -1
- package/dist/runtime/routes/draft.d.ts +13 -0
- package/dist/runtime/routes/draft.d.ts.map +1 -0
- package/dist/runtime/routes/draft.js +55 -0
- package/dist/runtime/routes/draft.js.map +1 -0
- package/dist/runtime/routes/editor-assets.d.ts +1 -0
- package/dist/runtime/routes/editor-assets.d.ts.map +1 -1
- package/dist/runtime/routes/editor-assets.js +1 -0
- package/dist/runtime/routes/editor-assets.js.map +1 -1
- package/dist/runtime/routes/entries.d.ts +1 -0
- package/dist/runtime/routes/entries.d.ts.map +1 -1
- package/dist/runtime/routes/entries.js +3 -2
- package/dist/runtime/routes/entries.js.map +1 -1
- package/dist/runtime/routes/history.d.ts +1 -0
- package/dist/runtime/routes/history.d.ts.map +1 -1
- package/dist/runtime/routes/history.js +24 -10
- package/dist/runtime/routes/history.js.map +1 -1
- package/dist/runtime/routes/mutate.d.ts +1 -0
- package/dist/runtime/routes/mutate.d.ts.map +1 -1
- package/dist/runtime/routes/mutate.js +7 -10
- package/dist/runtime/routes/mutate.js.map +1 -1
- package/dist/runtime/routes/publish.d.ts +10 -0
- package/dist/runtime/routes/publish.d.ts.map +1 -0
- package/dist/runtime/routes/publish.js +75 -0
- package/dist/runtime/routes/publish.js.map +1 -0
- package/dist/runtime/routes/schema.d.ts +1 -0
- package/dist/runtime/routes/schema.d.ts.map +1 -1
- package/dist/runtime/routes/schema.js +7 -4
- package/dist/runtime/routes/schema.js.map +1 -1
- package/dist/runtime/routes/studio-home.d.ts +1 -0
- package/dist/runtime/routes/studio-home.d.ts.map +1 -1
- package/dist/runtime/routes/studio-home.js +10 -9
- package/dist/runtime/routes/studio-home.js.map +1 -1
- package/dist/runtime/routes/theme-stylesheet.d.ts +1 -0
- package/dist/runtime/routes/theme-stylesheet.d.ts.map +1 -1
- package/dist/runtime/routes/theme-stylesheet.js +1 -0
- package/dist/runtime/routes/theme-stylesheet.js.map +1 -1
- package/dist/runtime/routes/upload.d.ts +1 -0
- package/dist/runtime/routes/upload.d.ts.map +1 -1
- package/dist/runtime/routes/upload.js +17 -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/static-bake.d.ts +20 -0
- package/dist/runtime/static-bake.d.ts.map +1 -0
- package/dist/runtime/static-bake.js +58 -0
- package/dist/runtime/static-bake.js.map +1 -0
- 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 +523 -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/runtime/views/studio-layout.d.ts.map +1 -1
- package/dist/runtime/views/studio-layout.js +11 -10
- package/dist/runtime/views/studio-layout.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 +265 -0
- package/static/cms/editor/config.js +10 -0
- package/static/cms/editor/helpers.js +5 -1
- package/static/cms/editor/highlight.js +44 -0
- package/static/cms/editor/sanitize.js +56 -9
- 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 +101 -4
- package/static/cms/editor/toolbar.js +171 -21
- package/static/cms/editor.js +18 -1
- package/static/cms/signin-hint.css +74 -0
- package/static/cms/studio-login.css +70 -0
- package/static/cms/studio.css +80 -13
- 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
package/dist/loader.js
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* });
|
|
15
15
|
* export const collections = { pages };
|
|
16
16
|
*/
|
|
17
|
-
import { requireRequestContext } from "./runtime/request-context.js";
|
|
17
|
+
import { getRequestContext, requireRequestContext, } from "./runtime/request-context.js";
|
|
18
|
+
import { stegaCombine } from "./runtime/stega.js";
|
|
18
19
|
export class CaretLoaderError extends Error {
|
|
19
20
|
constructor(message, cause) {
|
|
20
21
|
super(message);
|
|
@@ -24,6 +25,41 @@ export class CaretLoaderError extends Error {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Draft-mode only: hide each string field's binding key (`collection::id::field`)
|
|
30
|
+
* inside the value itself via stega. The key then rides through component props,
|
|
31
|
+
* slots, and `.map()` loops, so the editor overlay can offer click-to-edit on
|
|
32
|
+
* any rendered string with no `data-caret` attribute. Visitors are never editors,
|
|
33
|
+
* so this is a no-op for them; the rewrite middleware also strips stega from
|
|
34
|
+
* published HTML as a backstop. Nested fields use a dot-path (matching the
|
|
35
|
+
* rewrite engine's `field.path` resolution).
|
|
36
|
+
*/
|
|
37
|
+
function encodeEntryData(collection, id, data) {
|
|
38
|
+
const walk = (value, path) => {
|
|
39
|
+
if (typeof value === "string") {
|
|
40
|
+
return stegaCombine(value, `${collection}::${id}::${path}`);
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
return value.map((item, i) => walk(item, `${path}.${i}`));
|
|
44
|
+
}
|
|
45
|
+
if (value && typeof value === "object") {
|
|
46
|
+
const out = {};
|
|
47
|
+
for (const [k, v] of Object.entries(value)) {
|
|
48
|
+
out[k] = walk(v, `${path}.${k}`);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
};
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [k, v] of Object.entries(data))
|
|
56
|
+
out[k] = walk(v, k);
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
/** Whether the current request should receive stega-encoded draft content. */
|
|
60
|
+
function isEditorRequest() {
|
|
61
|
+
return getRequestContext()?.editor === true;
|
|
62
|
+
}
|
|
27
63
|
function requireAdapter() {
|
|
28
64
|
try {
|
|
29
65
|
return requireRequestContext().adapter;
|
|
@@ -50,7 +86,10 @@ export function caretLoader(collection) {
|
|
|
50
86
|
const entry = await adapter.getEntry(collection, id);
|
|
51
87
|
if (!entry)
|
|
52
88
|
return undefined;
|
|
53
|
-
|
|
89
|
+
const data = isEditorRequest()
|
|
90
|
+
? encodeEntryData(collection, entry.id, entry.data)
|
|
91
|
+
: entry.data;
|
|
92
|
+
return { id: entry.id, data };
|
|
54
93
|
}
|
|
55
94
|
catch (error) {
|
|
56
95
|
return {
|
|
@@ -62,10 +101,13 @@ export function caretLoader(collection) {
|
|
|
62
101
|
try {
|
|
63
102
|
const adapter = requireAdapter();
|
|
64
103
|
const allEntries = await adapter.listEntries(collection);
|
|
104
|
+
const editor = isEditorRequest();
|
|
65
105
|
return {
|
|
66
106
|
entries: allEntries.map((entry) => ({
|
|
67
107
|
id: entry.id,
|
|
68
|
-
data:
|
|
108
|
+
data: editor
|
|
109
|
+
? encodeEntryData(collection, entry.id, entry.data)
|
|
110
|
+
: entry.data,
|
|
69
111
|
})),
|
|
70
112
|
};
|
|
71
113
|
}
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { MarkdownAdapter } from "../../runtime/storage/markdown-adapter.js";
|
|
2
|
+
export declare function markdownStorageProvider(options?: {
|
|
3
|
+
contentRoot?: string;
|
|
4
|
+
metaRoot?: string;
|
|
5
|
+
}): MarkdownAdapter;
|
|
6
|
+
export default markdownStorageProvider;
|
|
7
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/providers/storage/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAE5E,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,eAAe,CAElB;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/providers/storage/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAE5E,MAAM,UAAU,uBAAuB,CAAC,OAGvC;IACC,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function isProxyTrusted(): boolean;
|
|
1
2
|
export declare function shouldUseSecureCookies(request?: Request): boolean;
|
|
2
3
|
export declare function sanitizeRedirect(value: string | null | undefined, fallback: string): string;
|
|
3
4
|
//# sourceMappingURL=cookie-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-utils.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/cookie-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cookie-utils.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/cookie-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,IAAI,OAAO,CAKxC;AAED,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAmBjE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ,EAAE,MAAM,GACf,MAAM,CAGR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-utils.js","sourceRoot":"","sources":["../../../src/runtime/auth/cookie-utils.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"cookie-utils.js","sourceRoot":"","sources":["../../../src/runtime/auth/cookie-utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC1C,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvC,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAiB;IACtD,2EAA2E;IAC3E,yDAAyD;IACzD,uEAAuE;IACvE,yCAAyC;IACzC,IAAI,cAAc,EAAE,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACnF,IAAI,SAAS;YAAE,OAAO,SAAS,KAAK,OAAO,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAgC,EAChC,QAAgB;IAEhB,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoBH,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACtE,eAAe,CAcjB;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,IAAI,CAWN;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,sCAAsC;AACtC,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAoB5D"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* box. Multi-instance or Workers deployments should layer Durable Objects or
|
|
5
5
|
* a WAF rate-limit rule on top — there's no shared state here.
|
|
6
6
|
*/
|
|
7
|
+
import { isProxyTrusted } from "./cookie-utils.js";
|
|
7
8
|
const DEFAULT_MAX_FAILURES = 5;
|
|
8
9
|
const DEFAULT_WINDOW_MS = 15 * 60 * 1000;
|
|
9
10
|
const windows = new Map();
|
|
@@ -46,19 +47,24 @@ export function __resetLoginRateLimiter() {
|
|
|
46
47
|
windows.clear();
|
|
47
48
|
}
|
|
48
49
|
export function extractRateLimitKey(request) {
|
|
49
|
-
// Best-effort client identifier. Astro doesn't expose remote IP directly
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
headers
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
50
|
+
// Best-effort client identifier. Astro doesn't expose remote IP directly in
|
|
51
|
+
// all adapters, so we fall back to a forwarded-for header — but ONLY when the
|
|
52
|
+
// deployment has opted into trusting its proxy via CARET_TRUST_PROXY. These
|
|
53
|
+
// headers are client-controlled: an untrusted attacker can rotate
|
|
54
|
+
// X-Forwarded-For per request to mint unlimited fresh buckets and bypass the
|
|
55
|
+
// brute-force limit entirely. When the proxy isn't trusted we fall back to a
|
|
56
|
+
// single shared "unknown" bucket — a coarser limit, but not spoofable.
|
|
57
|
+
if (isProxyTrusted()) {
|
|
58
|
+
const headers = request.headers;
|
|
59
|
+
const candidates = [
|
|
60
|
+
headers.get("cf-connecting-ip"),
|
|
61
|
+
headers.get("x-real-ip"),
|
|
62
|
+
headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? null,
|
|
63
|
+
];
|
|
64
|
+
for (const candidate of candidates) {
|
|
65
|
+
if (candidate && candidate.length > 0)
|
|
66
|
+
return candidate;
|
|
67
|
+
}
|
|
62
68
|
}
|
|
63
69
|
return "unknown";
|
|
64
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../../src/runtime/auth/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAMzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE1C,SAAS,KAAK,CAAC,MAAc,EAAE,GAAW,EAAE,QAAgB;IAC1D,MAAM,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC;IAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAMD,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,UAAqE,EAAE;IAEvE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,oBAAoB,CAAC;IAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAEtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAEtC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,WAAW;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAEnE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,GAAG,CAAC,CAAC;IAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,UAA+C,EAAE;IAEjD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAEtC,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC;IACD,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC7B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,uBAAuB;IACrC,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../../src/runtime/auth/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function isDevEditorPasswordActive(): boolean;
|
|
1
2
|
export declare function isEditorPasswordValid(candidate: string): boolean;
|
|
2
3
|
export declare function issueEditorSessionCookie(path?: string, request?: Request): string;
|
|
3
4
|
export declare function clearEditorSessionCookie(path?: string, request?: Request): string;
|
|
@@ -10,5 +11,12 @@ type CookieBagLike = {
|
|
|
10
11
|
};
|
|
11
12
|
};
|
|
12
13
|
export declare function isEditorAuthenticated(context: CookieBagLike): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The per-editor id carried by the session cookie, used to key a draft overlay.
|
|
16
|
+
* Returns null when the request has no valid editor session, or when the session
|
|
17
|
+
* predates editor ids (a legacy token). Does NOT consider demo sessions — those
|
|
18
|
+
* are keyed by their own `sessionId`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getEditorId(context: CookieBagLike): string | null;
|
|
13
21
|
export {};
|
|
14
22
|
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/session.ts"],"names":[],"mappings":"AAmDA,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AA0HD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAWhE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,SAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAS9E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,SAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAE9E;AAED,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,CAAC,EAAE;QACR,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;KACtD,CAAC;CACH,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAarE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAIjE"}
|
|
@@ -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":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAO1D,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAC5C,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAczC,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAClD,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,SAAS,2BAA2B;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;IACjF,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAED,iFAAiF;AACjF,iFAAiF;AACjF,iFAAiF;AACjF,iFAAiF;AACjF,SAAS,sBAAsB;IAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,GAAG,GACP,OAAO,4BAA4B,KAAK,QAAQ;QAC9C,CAAC,CAAC,4BAA4B;QAC9B,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO,2BAA2B,EAAE,IAAI,sBAAsB,EAAE,CAAC;AACnE,CAAC;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,MAAM,UAAU,yBAAyB;IACvC,OAAO,2BAA2B,EAAE,KAAK,IAAI,IAAI,sBAAsB,EAAE,KAAK,IAAI,CAAC;AACrF,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACpD,IAAI,UAAU,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IAElE,8EAA8E;IAC9E,8EAA8E;IAC9E,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAI,2BAA2B,EAAE,KAAK,IAAI;QAAE,OAAO,mBAAmB,CAAC;IAEvE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,6FAA6F;YAC3F,6EAA6E,CAChF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,eAAe,GAAG,IAAI,CAAC;QACvB,OAAO,CAAC,IAAI,CACV,yEAAyE;YACvE,oEAAoE,CACvE,CAAC;IACJ,CAAC;IACD,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED,SAAS,WAAW,CAAC,UAAkB;IACrC,OAAO,UAAU,CAAC,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACzF,CAAC;AAED,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,UAAkB;IACxC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,iBAAiB,GAAG,IAAI,CAAC;YACzB,OAAO,CAAC,KAAK,CACX,GAAI,GAAa,CAAC,OAAO,gDAAgD,CAC1E,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,4BAA4B,CACnC,KAAa,EACb,IAAY,EACZ,MAAc,EACd,OAAiB;IAEjB,MAAM,KAAK,GAAG;QACZ,GAAG,mBAAmB,IAAI,KAAK,EAAE;QACjC,QAAQ,IAAI,EAAE;QACd,UAAU;QACV,cAAc;QACd,WAAW,MAAM,EAAE;KACpB,CAAC;IAEF,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,UAAU,CAAC,OAAuB;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACpC,OAAO,GAAG,UAAU,IAAI,GAAG,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC;IACtC,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE3C,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,MAAc,CAAC;IACnB,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC7C,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7E,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACvB,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC3C,CAAC;QACb,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QAEhF,MAAM,OAAO,GAAG,MAAiC,CAAC;QAClD,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAClF,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QAC3C,4EAA4E;QAC5E,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAExF,OAAO,OAAyB,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;IACrC,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAE7B,wEAAwE;IACxE,uEAAuE;IACvE,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,eAAe,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC;IAChF,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9E,OAAO,eAAe,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAI,GAAG,GAAG,EAAE,OAAiB;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,mBAAmB,GAAG,IAAI,CAAC;IACpD,MAAM,KAAK,GAAG,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IACxE,OAAO,4BAA4B,CACjC,kBAAkB,CAAC,KAAK,CAAC,EACzB,IAAI,EACJ,mBAAmB,EACnB,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAI,GAAG,GAAG,EAAE,OAAiB;IACpE,OAAO,4BAA4B,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,EAAE,KAAK,IAAI,CAAC;AACtC,CAAC;AAQD,MAAM,UAAU,qBAAqB,CAAC,OAAsB;IAC1D,yEAAyE;IACzE,yEAAyE;IACzE,oEAAoE;IACpE,wEAAwE;IACxE,0EAA0E;IAC1E,yEAAyE;IACzE,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,GAAG,EAAE,QAAQ,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAErE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,UAAU,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,OAAsB;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,UAAU,CAAC,KAAK,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;AAC7C,CAAC"}
|
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"}
|