@drawnagency/primitives 0.1.55 → 0.1.56
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/dist/auth/cookies.d.ts.map +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/{chunk-PUNXQK4M.js → chunk-7IAWF7LE.js} +1 -1
- package/dist/{chunk-KDGYHU36.js → chunk-EU6NZ4GS.js} +13 -2
- package/dist/{chunk-24SUF2BC.js → chunk-KGYWQDBB.js} +4 -2
- package/dist/{chunk-B5VYSTPB.js → chunk-XTK4BR27.js} +1 -1
- package/dist/components/sections/all-sections.d.ts +214 -0
- package/dist/components/sections/all-sections.d.ts.map +1 -0
- package/dist/components/sections/register-schemas.d.ts.map +1 -1
- package/dist/components/sections/register.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts +2 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/hooks/useEditorPublish.d.ts +2 -1
- package/dist/hooks/useEditorPublish.d.ts.map +1 -1
- package/dist/index.js +17 -4
- package/dist/lib/dexie.d.ts +12 -1
- package/dist/lib/dexie.d.ts.map +1 -1
- package/dist/lib/dexie.js +15 -3
- package/dist/lib/index.js +2 -2
- package/dist/lib/registry.d.ts +0 -2
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/lib/sanitize.d.ts.map +1 -1
- package/dist/schemas/index.js +4 -2
- package/dist/schemas/shared.d.ts +1 -0
- package/dist/schemas/shared.d.ts.map +1 -1
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/types.d.ts +13 -1
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/auth/cookies.ts +6 -1
- package/src/components/sections/all-sections.ts +38 -0
- package/src/components/sections/register-schemas.ts +9 -17
- package/src/components/sections/register.ts +3 -17
- package/src/components/shell/EditorShell.tsx +42 -5
- package/src/hooks/useEditorPublish.ts +17 -4
- package/src/lib/dexie.ts +25 -0
- package/src/lib/registry.ts +0 -2
- package/src/lib/sanitize.ts +22 -1
- package/src/schemas/shared.ts +10 -0
- package/src/schemas/site-config.ts +3 -3
- package/src/storage/index.ts +1 -0
- package/src/storage/types.ts +17 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;AAMpD,eAAO,MAAM,wBAAwB,QAAe,CAAC;AAErD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAe/E;AAMD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzE;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS/E;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,OAAO,GACpB,IAAI,CAQN"}
|
package/dist/auth/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
getAllSchemas,
|
|
4
4
|
getSection,
|
|
5
5
|
getSectionSchema
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KGYWQDBB.js";
|
|
7
7
|
import {
|
|
8
8
|
safeNextPath
|
|
9
9
|
} from "./chunk-S2L3BPLS.js";
|
|
@@ -96,9 +96,20 @@ if (typeof window !== "undefined") {
|
|
|
96
96
|
return mod;
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
|
+
var sanitizeCache = /* @__PURE__ */ new Map();
|
|
100
|
+
var SANITIZE_CACHE_LIMIT = 500;
|
|
99
101
|
function sanitizeHtml(html) {
|
|
100
102
|
if (!html) return "";
|
|
101
|
-
|
|
103
|
+
if (!purifier) return html;
|
|
104
|
+
const cached = sanitizeCache.get(html);
|
|
105
|
+
if (cached !== void 0) return cached;
|
|
106
|
+
const clean = purifier(html);
|
|
107
|
+
if (sanitizeCache.size >= SANITIZE_CACHE_LIMIT) {
|
|
108
|
+
const oldest = sanitizeCache.keys().next().value;
|
|
109
|
+
if (oldest !== void 0) sanitizeCache.delete(oldest);
|
|
110
|
+
}
|
|
111
|
+
sanitizeCache.set(html, clean);
|
|
112
|
+
return clean;
|
|
102
113
|
}
|
|
103
114
|
async function ensureSanitizer() {
|
|
104
115
|
if (typeof window === "undefined") return;
|
|
@@ -62,6 +62,7 @@ var MediaReferenceSchema = z.discriminatedUnion("type", [
|
|
|
62
62
|
LinkedImageRef
|
|
63
63
|
]);
|
|
64
64
|
var HexColorSchema = z.string().regex(/^#[0-9a-fA-F]{6}$/, "must be a 6-digit hex color");
|
|
65
|
+
var FontNameSchema = z.string().max(120).regex(/^[a-zA-Z0-9 ,'"-]+$/, "contains invalid font-name characters");
|
|
65
66
|
var ColorSpaceSchema = z.object({
|
|
66
67
|
hex: HexColorSchema.optional(),
|
|
67
68
|
rgb: z.string().optional(),
|
|
@@ -260,8 +261,8 @@ var SiteConfigSchema = z3.object({
|
|
|
260
261
|
primaryColor: HexColorSchema.default("#009ca6"),
|
|
261
262
|
primaryContrast: HexColorSchema.default("#f0f0f0"),
|
|
262
263
|
darkMode: z3.enum(["light", "dark", "optional"]).default("light"),
|
|
263
|
-
headingFont:
|
|
264
|
-
bodyFont:
|
|
264
|
+
headingFont: FontNameSchema.default("system-ui"),
|
|
265
|
+
bodyFont: FontNameSchema.default("system-ui"),
|
|
265
266
|
uppercaseHeadings: z3.boolean().default(true),
|
|
266
267
|
uppercaseSubheadings: z3.boolean().default(true),
|
|
267
268
|
uppercaseNavHeadings: z3.boolean().default(true),
|
|
@@ -276,6 +277,7 @@ export {
|
|
|
276
277
|
TextLineSchema,
|
|
277
278
|
MediaReferenceSchema,
|
|
278
279
|
HexColorSchema,
|
|
280
|
+
FontNameSchema,
|
|
279
281
|
ColorSpaceSchema,
|
|
280
282
|
ColorItemSchema,
|
|
281
283
|
defineSection,
|
|
@@ -7,7 +7,7 @@ import * as jose from "jose";
|
|
|
7
7
|
var SESSION_COOKIE = "bp-session";
|
|
8
8
|
var AUDIENCE_COOKIE = "bp-audience";
|
|
9
9
|
var SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
|
|
10
|
-
var AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24
|
|
10
|
+
var AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24;
|
|
11
11
|
async function signSessionToken(session) {
|
|
12
12
|
return new jose.SignJWT({
|
|
13
13
|
userId: session.userId,
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single ordered list of built-in section definitions.
|
|
3
|
+
*
|
|
4
|
+
* Both `register.ts` (full registration for rendering) and `register-schemas.ts`
|
|
5
|
+
* (schema-only registration for /api/save validation) derive from this one
|
|
6
|
+
* array, so the two can no longer drift — previously they hand-maintained
|
|
7
|
+
* parallel 11-entry lists, and a section added to one but not the other would
|
|
8
|
+
* make the editor render a type that save rejects with a 400 (or vice versa).
|
|
9
|
+
*/
|
|
10
|
+
export declare const allSectionDefs: (import("../..").SectionDefinition<{
|
|
11
|
+
type: "link_heading";
|
|
12
|
+
content: {
|
|
13
|
+
heading: string;
|
|
14
|
+
};
|
|
15
|
+
}> | import("../..").SectionDefinition<{
|
|
16
|
+
type: "sub_heading";
|
|
17
|
+
content: {
|
|
18
|
+
heading: string;
|
|
19
|
+
excludeFromNav?: boolean | undefined;
|
|
20
|
+
};
|
|
21
|
+
}> | import("../..").SectionDefinition<{
|
|
22
|
+
type: "sub_sub_heading";
|
|
23
|
+
content: {
|
|
24
|
+
heading: string;
|
|
25
|
+
excludeFromNav?: boolean | undefined;
|
|
26
|
+
};
|
|
27
|
+
}> | import("../..").SectionDefinition<{
|
|
28
|
+
type: "prose";
|
|
29
|
+
content: {
|
|
30
|
+
body: string;
|
|
31
|
+
};
|
|
32
|
+
}> | import("../..").SectionDefinition<{
|
|
33
|
+
type: "media_grid";
|
|
34
|
+
content: {
|
|
35
|
+
columns: number;
|
|
36
|
+
media: ({
|
|
37
|
+
imageId: string;
|
|
38
|
+
type: "image";
|
|
39
|
+
caption?: string | string[] | undefined;
|
|
40
|
+
background?: string | undefined;
|
|
41
|
+
invertFrom?: string | undefined;
|
|
42
|
+
border?: boolean | undefined;
|
|
43
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
44
|
+
} | {
|
|
45
|
+
imageId: string;
|
|
46
|
+
type: "video";
|
|
47
|
+
caption?: string | string[] | undefined;
|
|
48
|
+
background?: string | undefined;
|
|
49
|
+
invertFrom?: string | undefined;
|
|
50
|
+
border?: boolean | undefined;
|
|
51
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
52
|
+
poster?: string | undefined;
|
|
53
|
+
autoplay?: boolean | undefined;
|
|
54
|
+
loop?: boolean | undefined;
|
|
55
|
+
muted?: boolean | undefined;
|
|
56
|
+
} | {
|
|
57
|
+
imageId: string;
|
|
58
|
+
type: "doDontImage";
|
|
59
|
+
doDont: "do" | "dont";
|
|
60
|
+
caption?: string | string[] | undefined;
|
|
61
|
+
background?: string | undefined;
|
|
62
|
+
invertFrom?: string | undefined;
|
|
63
|
+
border?: boolean | undefined;
|
|
64
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
65
|
+
} | {
|
|
66
|
+
imageId: string;
|
|
67
|
+
type: "linkedImage";
|
|
68
|
+
href: string;
|
|
69
|
+
caption?: string | string[] | undefined;
|
|
70
|
+
background?: string | undefined;
|
|
71
|
+
invertFrom?: string | undefined;
|
|
72
|
+
border?: boolean | undefined;
|
|
73
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
74
|
+
target?: string | undefined;
|
|
75
|
+
linkText?: string | undefined;
|
|
76
|
+
})[];
|
|
77
|
+
};
|
|
78
|
+
options: {
|
|
79
|
+
square?: boolean | undefined;
|
|
80
|
+
border?: boolean | undefined;
|
|
81
|
+
crop?: boolean | undefined;
|
|
82
|
+
showCaptions?: boolean | undefined;
|
|
83
|
+
};
|
|
84
|
+
}> | import("../..").SectionDefinition<{
|
|
85
|
+
type: "split_content";
|
|
86
|
+
content: {
|
|
87
|
+
body: string;
|
|
88
|
+
imageId?: string | undefined;
|
|
89
|
+
};
|
|
90
|
+
options?: {
|
|
91
|
+
border?: boolean | undefined;
|
|
92
|
+
imagePosition?: "left" | "right" | undefined;
|
|
93
|
+
} | undefined;
|
|
94
|
+
}> | import("../..").SectionDefinition<{
|
|
95
|
+
type: "button";
|
|
96
|
+
content: {
|
|
97
|
+
text: string;
|
|
98
|
+
link?: {
|
|
99
|
+
kind: "external";
|
|
100
|
+
href: string;
|
|
101
|
+
target: "_self" | "_blank";
|
|
102
|
+
} | {
|
|
103
|
+
kind: "internal";
|
|
104
|
+
pageId: string;
|
|
105
|
+
target: "_self" | "_blank";
|
|
106
|
+
anchorSectionId?: string | null | undefined;
|
|
107
|
+
} | undefined;
|
|
108
|
+
download?: boolean | undefined;
|
|
109
|
+
};
|
|
110
|
+
}> | import("../..").SectionDefinition<{
|
|
111
|
+
type: "colors";
|
|
112
|
+
content: {
|
|
113
|
+
colors: {
|
|
114
|
+
spaces: {
|
|
115
|
+
hex?: string | undefined;
|
|
116
|
+
rgb?: string | undefined;
|
|
117
|
+
cmyk?: string | undefined;
|
|
118
|
+
pantone?: string | undefined;
|
|
119
|
+
}[];
|
|
120
|
+
name?: string | undefined;
|
|
121
|
+
}[];
|
|
122
|
+
};
|
|
123
|
+
options?: {
|
|
124
|
+
label?: string | undefined;
|
|
125
|
+
columns?: number | undefined;
|
|
126
|
+
collapsing?: boolean | undefined;
|
|
127
|
+
showLabel?: boolean | undefined;
|
|
128
|
+
} | undefined;
|
|
129
|
+
}> | import("../..").SectionDefinition<{
|
|
130
|
+
type: "do_dont";
|
|
131
|
+
content: {
|
|
132
|
+
doItems: {
|
|
133
|
+
label: string;
|
|
134
|
+
text: string;
|
|
135
|
+
icon?: string | undefined;
|
|
136
|
+
}[];
|
|
137
|
+
dontItems: {
|
|
138
|
+
label: string;
|
|
139
|
+
text: string;
|
|
140
|
+
icon?: string | undefined;
|
|
141
|
+
}[];
|
|
142
|
+
};
|
|
143
|
+
options?: {
|
|
144
|
+
showLabel?: boolean | undefined;
|
|
145
|
+
stackText?: boolean | undefined;
|
|
146
|
+
} | undefined;
|
|
147
|
+
}> | import("../..").SectionDefinition<{
|
|
148
|
+
type: "do_dont_grid";
|
|
149
|
+
content: {
|
|
150
|
+
columns: number;
|
|
151
|
+
media: ({
|
|
152
|
+
imageId: string;
|
|
153
|
+
type: "image";
|
|
154
|
+
caption?: string | string[] | undefined;
|
|
155
|
+
background?: string | undefined;
|
|
156
|
+
invertFrom?: string | undefined;
|
|
157
|
+
border?: boolean | undefined;
|
|
158
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
159
|
+
} | {
|
|
160
|
+
imageId: string;
|
|
161
|
+
type: "video";
|
|
162
|
+
caption?: string | string[] | undefined;
|
|
163
|
+
background?: string | undefined;
|
|
164
|
+
invertFrom?: string | undefined;
|
|
165
|
+
border?: boolean | undefined;
|
|
166
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
167
|
+
poster?: string | undefined;
|
|
168
|
+
autoplay?: boolean | undefined;
|
|
169
|
+
loop?: boolean | undefined;
|
|
170
|
+
muted?: boolean | undefined;
|
|
171
|
+
} | {
|
|
172
|
+
imageId: string;
|
|
173
|
+
type: "doDontImage";
|
|
174
|
+
doDont: "do" | "dont";
|
|
175
|
+
caption?: string | string[] | undefined;
|
|
176
|
+
background?: string | undefined;
|
|
177
|
+
invertFrom?: string | undefined;
|
|
178
|
+
border?: boolean | undefined;
|
|
179
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
180
|
+
} | {
|
|
181
|
+
imageId: string;
|
|
182
|
+
type: "linkedImage";
|
|
183
|
+
href: string;
|
|
184
|
+
caption?: string | string[] | undefined;
|
|
185
|
+
background?: string | undefined;
|
|
186
|
+
invertFrom?: string | undefined;
|
|
187
|
+
border?: boolean | undefined;
|
|
188
|
+
objectFit?: "cover" | "contain" | undefined;
|
|
189
|
+
target?: string | undefined;
|
|
190
|
+
linkText?: string | undefined;
|
|
191
|
+
})[];
|
|
192
|
+
};
|
|
193
|
+
options: {
|
|
194
|
+
square?: boolean | undefined;
|
|
195
|
+
border?: boolean | undefined;
|
|
196
|
+
crop?: boolean | undefined;
|
|
197
|
+
showCaptions?: boolean | undefined;
|
|
198
|
+
};
|
|
199
|
+
}> | import("../..").SectionDefinition<{
|
|
200
|
+
type: "icon_list";
|
|
201
|
+
content: {
|
|
202
|
+
items: {
|
|
203
|
+
label: string;
|
|
204
|
+
text: string;
|
|
205
|
+
icon?: string | undefined;
|
|
206
|
+
}[];
|
|
207
|
+
};
|
|
208
|
+
options?: {
|
|
209
|
+
icon?: string | null | undefined;
|
|
210
|
+
showLabel?: boolean | undefined;
|
|
211
|
+
stackText?: boolean | undefined;
|
|
212
|
+
} | undefined;
|
|
213
|
+
}>)[];
|
|
214
|
+
//# sourceMappingURL=all-sections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all-sections.d.ts","sourceRoot":"","sources":["../../../src/components/sections/all-sections.ts"],"names":[],"mappings":"AAYA;;;;;;;;GAQG;AAKH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAY1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-schemas.d.ts","sourceRoot":"","sources":["../../../src/components/sections/register-schemas.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"register-schemas.d.ts","sourceRoot":"","sources":["../../../src/components/sections/register-schemas.ts"],"names":[],"mappings":"AAUA,wBAAgB,uBAAuB,IAAI,MAAM,CAMhD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/components/sections/register.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/components/sections/register.ts"],"names":[],"mappings":"AAIA,wBAAgB,wBAAwB,IAAI,MAAM,CAMjD"}
|
|
@@ -2,6 +2,7 @@ import type { Audience } from "../../auth/types";
|
|
|
2
2
|
export { useMediaLibrary } from "./MediaLibraryContext";
|
|
3
3
|
interface Props {
|
|
4
4
|
headSha: string;
|
|
5
|
+
draftHeadSha?: string;
|
|
5
6
|
siteId: string;
|
|
6
7
|
audiences: Audience[];
|
|
7
8
|
capabilities: {
|
|
@@ -17,5 +18,5 @@ interface Props {
|
|
|
17
18
|
role: "owner" | "editor";
|
|
18
19
|
} | null;
|
|
19
20
|
}
|
|
20
|
-
export default function EditorShell({ headSha, siteId, audiences: initialAudiences, capabilities, currentUser, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export default function EditorShell({ headSha, draftHeadSha, siteId, audiences: initialAudiences, capabilities, currentUser, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
21
22
|
//# sourceMappingURL=EditorShell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAgEjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAgEjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAIhB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,YAAY,EACZ,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CA24BP"}
|
|
@@ -19,9 +19,10 @@ interface PublishDeps {
|
|
|
19
19
|
onMediaPublished: (publishedItems: MediaItem[], publishedDeletions: string[]) => void;
|
|
20
20
|
onShasUpdated: (savedSha: string | null, mainSha: string | null) => void;
|
|
21
21
|
onPublishComplete?: () => void;
|
|
22
|
+
getBaseVersion: () => string | null;
|
|
22
23
|
}
|
|
23
24
|
export type PublishAction = "idle" | "saving" | "publishing";
|
|
24
|
-
export declare function useEditorPublish({ flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, manifestDirty, clearManifestDirty, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, onPublishComplete, }: PublishDeps): {
|
|
25
|
+
export declare function useEditorPublish({ flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, manifestDirty, clearManifestDirty, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, onPublishComplete, getBaseVersion, }: PublishDeps): {
|
|
25
26
|
publishAction: PublishAction;
|
|
26
27
|
publishFeedback: string | null;
|
|
27
28
|
handleSave: () => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAI/B,cAAc,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACrC;AAQD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,EAAE,WAAW;;;;;;EAwSb"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
LinkValueSchema,
|
|
7
7
|
MediaGridOptionsSchema,
|
|
8
8
|
slugifyAudienceName
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7IAWF7LE.js";
|
|
10
10
|
import {
|
|
11
11
|
AudienceSchema,
|
|
12
12
|
RoleSchema,
|
|
@@ -33,10 +33,11 @@ import {
|
|
|
33
33
|
safeRedirect,
|
|
34
34
|
sanitizeHtml,
|
|
35
35
|
toSectionId
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-EU6NZ4GS.js";
|
|
37
37
|
import {
|
|
38
38
|
ColorItemSchema,
|
|
39
39
|
ColorSpaceSchema,
|
|
40
|
+
FontNameSchema,
|
|
40
41
|
HexColorSchema,
|
|
41
42
|
IndexSchema,
|
|
42
43
|
MediaReferenceSchema,
|
|
@@ -58,7 +59,7 @@ import {
|
|
|
58
59
|
normalizeSiteIndex,
|
|
59
60
|
registerSchema,
|
|
60
61
|
registerSection
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-KGYWQDBB.js";
|
|
62
63
|
import {
|
|
63
64
|
AUDIENCE_COOKIE,
|
|
64
65
|
AUDIENCE_MAX_AGE_SECONDS,
|
|
@@ -70,7 +71,7 @@ import {
|
|
|
70
71
|
signSessionToken,
|
|
71
72
|
verifyAudienceToken,
|
|
72
73
|
verifySessionToken
|
|
73
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-XTK4BR27.js";
|
|
74
75
|
import {
|
|
75
76
|
isSameOriginRequest,
|
|
76
77
|
requireSessionSecret,
|
|
@@ -101,6 +102,16 @@ import {
|
|
|
101
102
|
MediaItemSchema,
|
|
102
103
|
VariantSchema
|
|
103
104
|
} from "./chunk-DKOUFIP6.js";
|
|
105
|
+
|
|
106
|
+
// src/storage/types.ts
|
|
107
|
+
var StorageConflictError = class extends Error {
|
|
108
|
+
constructor(currentVersion) {
|
|
109
|
+
super("Draft has been modified since it was loaded");
|
|
110
|
+
this.currentVersion = currentVersion;
|
|
111
|
+
this.name = "StorageConflictError";
|
|
112
|
+
}
|
|
113
|
+
currentVersion;
|
|
114
|
+
};
|
|
104
115
|
export {
|
|
105
116
|
AUDIENCE_COOKIE,
|
|
106
117
|
AUDIENCE_MAX_AGE_SECONDS,
|
|
@@ -111,6 +122,7 @@ export {
|
|
|
111
122
|
ColorSpaceSchema,
|
|
112
123
|
DEFAULT_LINK,
|
|
113
124
|
EXT_TO_MIME,
|
|
125
|
+
FontNameSchema,
|
|
114
126
|
HexColorSchema,
|
|
115
127
|
ImageManifestSchema,
|
|
116
128
|
IndexSchema,
|
|
@@ -133,6 +145,7 @@ export {
|
|
|
133
145
|
SessionSchema,
|
|
134
146
|
SiteConfigSchema,
|
|
135
147
|
SiteUserSchema,
|
|
148
|
+
StorageConflictError,
|
|
136
149
|
TextLineSchema,
|
|
137
150
|
VariantSchema,
|
|
138
151
|
buildGoogleFontsUrl,
|
package/dist/lib/dexie.d.ts
CHANGED
|
@@ -57,13 +57,24 @@ export declare function getBranchShas(): Promise<{
|
|
|
57
57
|
mainSha: string | null;
|
|
58
58
|
} | null>;
|
|
59
59
|
export declare function getDeletedSections(): Promise<string[]>;
|
|
60
|
-
export declare function cacheContent(sha: string, sections: LoadedSection[], index: SiteIndex, siteConfig: Record<string, unknown
|
|
60
|
+
export declare function cacheContent(sha: string, sections: LoadedSection[], index: SiteIndex, siteConfig: Record<string, unknown>, diff?: {
|
|
61
|
+
savedBranchSha: string | null;
|
|
62
|
+
changedSectionIds: string[];
|
|
63
|
+
mainIndex: SiteIndex | null;
|
|
64
|
+
}): Promise<void>;
|
|
61
65
|
export declare function getCachedContent(): Promise<{
|
|
62
66
|
sha: string;
|
|
63
67
|
sections: LoadedSection[];
|
|
64
68
|
index: SiteIndex;
|
|
65
69
|
siteConfig: Record<string, unknown>;
|
|
70
|
+
savedBranchSha: string | null;
|
|
71
|
+
changedSectionIds: string[];
|
|
72
|
+
mainIndex: SiteIndex | null;
|
|
66
73
|
} | null>;
|
|
74
|
+
/** Invalidate only the cached content snapshot (e.g. after a publish removes the
|
|
75
|
+
* draft), forcing the next editor load to refetch rather than serve stale diff
|
|
76
|
+
* state. Narrower than discardSavedChanges, which also clears index/meta/config. */
|
|
77
|
+
export declare function clearContentCache(): Promise<void>;
|
|
67
78
|
export declare function persistMediaManifest(manifest: MediaManifest): Promise<void>;
|
|
68
79
|
export declare function getMediaManifest(): Promise<MediaManifest | null>;
|
|
69
80
|
export declare function addPendingMediaItem(item: MediaItem, localUrls?: Record<string, string>, blobs?: Record<string, Blob>): Promise<void>;
|
package/dist/lib/dexie.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dexie.d.ts","sourceRoot":"","sources":["../../src/lib/dexie.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAe,UAAU,EAAQ,MAAM,wBAAwB,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"dexie.d.ts","sourceRoot":"","sources":["../../src/lib/dexie.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/dexie.js
CHANGED
|
@@ -263,7 +263,7 @@ async function getDeletedSections() {
|
|
|
263
263
|
const row = await getDb().siteIndex.get("current");
|
|
264
264
|
return row?.deletedSections ?? [];
|
|
265
265
|
}
|
|
266
|
-
async function cacheContent(sha, sections, index, siteConfig) {
|
|
266
|
+
async function cacheContent(sha, sections, index, siteConfig, diff) {
|
|
267
267
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
268
268
|
await getDb().contentCache.put({
|
|
269
269
|
key: "current",
|
|
@@ -271,7 +271,10 @@ async function cacheContent(sha, sections, index, siteConfig) {
|
|
|
271
271
|
sections,
|
|
272
272
|
index,
|
|
273
273
|
siteConfig,
|
|
274
|
-
updatedAt: now
|
|
274
|
+
updatedAt: now,
|
|
275
|
+
savedBranchSha: diff?.savedBranchSha ?? null,
|
|
276
|
+
changedSectionIds: diff?.changedSectionIds ?? [],
|
|
277
|
+
mainIndex: diff?.mainIndex ?? null
|
|
275
278
|
});
|
|
276
279
|
}
|
|
277
280
|
async function getCachedContent() {
|
|
@@ -281,9 +284,17 @@ async function getCachedContent() {
|
|
|
281
284
|
sha: row.sha,
|
|
282
285
|
sections: row.sections,
|
|
283
286
|
index: row.index,
|
|
284
|
-
siteConfig: row.siteConfig
|
|
287
|
+
siteConfig: row.siteConfig,
|
|
288
|
+
savedBranchSha: row.savedBranchSha ?? null,
|
|
289
|
+
changedSectionIds: row.changedSectionIds ?? [],
|
|
290
|
+
// No stored mainIndex (e.g. legacy or post-publish cache) means "no draft",
|
|
291
|
+
// so the published index equals the current index.
|
|
292
|
+
mainIndex: row.mainIndex ?? row.index
|
|
285
293
|
};
|
|
286
294
|
}
|
|
295
|
+
async function clearContentCache() {
|
|
296
|
+
await getDb().contentCache.clear();
|
|
297
|
+
}
|
|
287
298
|
async function persistMediaManifest(manifest) {
|
|
288
299
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
289
300
|
await getDb().mediaManifest.put({ key: "current", manifest, updatedAt: now });
|
|
@@ -341,6 +352,7 @@ export {
|
|
|
341
352
|
addPendingMediaItem,
|
|
342
353
|
cacheContent,
|
|
343
354
|
checkForLocalChanges,
|
|
355
|
+
clearContentCache,
|
|
344
356
|
clearPendingMedia,
|
|
345
357
|
clearPendingMediaByIds,
|
|
346
358
|
deleteSectionRows,
|
package/dist/lib/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
safeRedirect,
|
|
19
19
|
sanitizeHtml,
|
|
20
20
|
toSectionId
|
|
21
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-EU6NZ4GS.js";
|
|
22
22
|
import {
|
|
23
23
|
clearRegistry,
|
|
24
24
|
createRegistry,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
getSection,
|
|
30
30
|
registerSchema,
|
|
31
31
|
registerSection
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-KGYWQDBB.js";
|
|
33
33
|
import "../chunk-S2L3BPLS.js";
|
|
34
34
|
import {
|
|
35
35
|
env
|
package/dist/lib/registry.d.ts
CHANGED
|
@@ -91,7 +91,6 @@ export interface SectionDefinition<T = unknown> {
|
|
|
91
91
|
schema: ZodType<T>;
|
|
92
92
|
component: ComponentType<SectionProps<T>>;
|
|
93
93
|
defaults: () => T;
|
|
94
|
-
wrapper?: ComponentType<WrapperProps>;
|
|
95
94
|
settings?: SettingsSchema;
|
|
96
95
|
settingsForm?: ComponentType<any>;
|
|
97
96
|
getLabel?(content: T): string;
|
|
@@ -105,7 +104,6 @@ type DefineSectionInput<S extends ZodType> = {
|
|
|
105
104
|
schema: S;
|
|
106
105
|
component: ComponentType<SectionProps<z.infer<S>>>;
|
|
107
106
|
defaults: () => z.infer<S>;
|
|
108
|
-
wrapper?: ComponentType<WrapperProps>;
|
|
109
107
|
settings?: SettingsSchema;
|
|
110
108
|
settingsForm?: ComponentType<any>;
|
|
111
109
|
getLabel?(content: z.infer<S>): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/lib/sanitize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/lib/sanitize.ts"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBjD;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAGrD"}
|
package/dist/schemas/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
LinkValueSchema,
|
|
7
7
|
MediaGridOptionsSchema,
|
|
8
8
|
slugifyAudienceName
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-7IAWF7LE.js";
|
|
10
10
|
import {
|
|
11
11
|
AudienceSchema,
|
|
12
12
|
RoleSchema,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
ColorItemSchema,
|
|
18
18
|
ColorSpaceSchema,
|
|
19
|
+
FontNameSchema,
|
|
19
20
|
HexColorSchema,
|
|
20
21
|
IndexSchema,
|
|
21
22
|
MediaReferenceSchema,
|
|
@@ -28,7 +29,7 @@ import {
|
|
|
28
29
|
getSectionContentSchema,
|
|
29
30
|
getSectionSchema,
|
|
30
31
|
normalizeSiteIndex
|
|
31
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-KGYWQDBB.js";
|
|
32
33
|
import {
|
|
33
34
|
ImageManifestSchema,
|
|
34
35
|
MediaConfigSchema,
|
|
@@ -42,6 +43,7 @@ export {
|
|
|
42
43
|
ColorItemSchema,
|
|
43
44
|
ColorSpaceSchema,
|
|
44
45
|
DEFAULT_LINK,
|
|
46
|
+
FontNameSchema,
|
|
45
47
|
HexColorSchema,
|
|
46
48
|
ImageManifestSchema,
|
|
47
49
|
IndexSchema,
|
package/dist/schemas/shared.d.ts
CHANGED
|
@@ -78,6 +78,7 @@ export declare const MediaReferenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
78
78
|
}, z.core.$strip>], "type">;
|
|
79
79
|
export type MediaReference = z.infer<typeof MediaReferenceSchema>;
|
|
80
80
|
export declare const HexColorSchema: z.ZodString;
|
|
81
|
+
export declare const FontNameSchema: z.ZodString;
|
|
81
82
|
export declare const ColorSpaceSchema: z.ZodObject<{
|
|
82
83
|
hex: z.ZodOptional<z.ZodString>;
|
|
83
84
|
rgb: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/schemas/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwBxB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;2BAKzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAoCtD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAE/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAGlE,eAAO,MAAM,cAAc,aAEiC,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/schemas/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwBxB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;2BAKzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAoCtD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAE/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAGlE,eAAO,MAAM,cAAc,aAEiC,CAAC;AAO7D,eAAO,MAAM,cAAc,aAG6C,CAAC;AAEzE,eAAO,MAAM,gBAAgB;;;;;iBAQ5B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,eAAe;;;;;;;;iBAG1B,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC"}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by `writeFiles` when `options.baseVersion` no longer matches the
|
|
3
|
+
* draft's current version — i.e. another editor (or the same user on another
|
|
4
|
+
* device) committed since this editor loaded. Callers should surface a 409 and
|
|
5
|
+
* prompt a reload rather than clobbering the concurrent work (last-write-wins).
|
|
6
|
+
*/
|
|
7
|
+
export declare class StorageConflictError extends Error {
|
|
8
|
+
readonly currentVersion: string | null;
|
|
9
|
+
constructor(currentVersion: string | null);
|
|
10
|
+
}
|
|
1
11
|
export interface StorageProvider {
|
|
2
|
-
writeFiles(files: FileWrite[], message: string
|
|
12
|
+
writeFiles(files: FileWrite[], message: string, options?: {
|
|
13
|
+
baseVersion?: string | null;
|
|
14
|
+
}): Promise<{
|
|
3
15
|
version: string;
|
|
4
16
|
}>;
|
|
5
17
|
readFile(path: string, options?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,UAAU,CACR,KAAK,EAAE,SAAS,EAAE,EAClB,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aACjB,cAAc,EAAE,MAAM,GAAG,IAAI;gBAA7B,cAAc,EAAE,MAAM,GAAG,IAAI;CAI1D;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CACR,KAAK,EAAE,SAAS,EAAE,EAClB,OAAO,EAAE,MAAM,EAIf,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACxC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEhC,QAAQ,CACN,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5B,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAE9B,YAAY,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAE7C,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9B,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC/E;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B,CAAC"}
|
package/package.json
CHANGED
package/src/auth/cookies.ts
CHANGED
|
@@ -5,7 +5,12 @@ import { requireSessionSecret } from "./security";
|
|
|
5
5
|
export const SESSION_COOKIE = "bp-session";
|
|
6
6
|
export const AUDIENCE_COOKIE = "bp-audience";
|
|
7
7
|
export const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
|
|
8
|
-
|
|
8
|
+
// 24h, matching the editor session. A viewer audience JWT carries no rotation
|
|
9
|
+
// token, so rotating a leaked viewer password can't actively revoke an
|
|
10
|
+
// outstanding cookie — a short lifetime bounds the leak window instead of the
|
|
11
|
+
// previous 30 days. (A `token_version` claim checked at verify time would give
|
|
12
|
+
// immediate revocation without forcing daily re-auth; see backlog.)
|
|
13
|
+
export const AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24;
|
|
9
14
|
|
|
10
15
|
export async function signSessionToken(session: Session): Promise<string> {
|
|
11
16
|
return new jose.SignJWT({
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import linkHeading from "./LinkHeading";
|
|
2
|
+
import subHeading from "./SubHeading";
|
|
3
|
+
import subSubHeading from "./SubSubHeading";
|
|
4
|
+
import prose from "./Prose";
|
|
5
|
+
import mediaGrid from "./MediaGrid";
|
|
6
|
+
import splitContent from "./SplitContent";
|
|
7
|
+
import button from "./Button";
|
|
8
|
+
import colors from "./Colors";
|
|
9
|
+
import doDontList from "./DoDontList";
|
|
10
|
+
import doDontImageGrid from "./DoDontMediaGrid";
|
|
11
|
+
import iconList from "./IconList";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The single ordered list of built-in section definitions.
|
|
15
|
+
*
|
|
16
|
+
* Both `register.ts` (full registration for rendering) and `register-schemas.ts`
|
|
17
|
+
* (schema-only registration for /api/save validation) derive from this one
|
|
18
|
+
* array, so the two can no longer drift — previously they hand-maintained
|
|
19
|
+
* parallel 11-entry lists, and a section added to one but not the other would
|
|
20
|
+
* make the editor render a type that save rejects with a 400 (or vice versa).
|
|
21
|
+
*/
|
|
22
|
+
// Intentionally un-annotated: each section is SectionDefinition<its-own-shape>,
|
|
23
|
+
// and a wider `SectionDefinition<unknown>[]` annotation isn't assignable from
|
|
24
|
+
// them (generic param variance). The inferred union is what registerSection /
|
|
25
|
+
// registerSchema already accept.
|
|
26
|
+
export const allSectionDefs = [
|
|
27
|
+
linkHeading,
|
|
28
|
+
subHeading,
|
|
29
|
+
subSubHeading,
|
|
30
|
+
prose,
|
|
31
|
+
mediaGrid,
|
|
32
|
+
splitContent,
|
|
33
|
+
button,
|
|
34
|
+
colors,
|
|
35
|
+
doDontList,
|
|
36
|
+
doDontImageGrid,
|
|
37
|
+
iconList,
|
|
38
|
+
];
|
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import { registerSchema } from "../../lib/registry";
|
|
2
|
-
import
|
|
3
|
-
import subHeading from "./SubHeading";
|
|
4
|
-
import subSubHeading from "./SubSubHeading";
|
|
5
|
-
import prose from "./Prose";
|
|
6
|
-
import mediaGrid from "./MediaGrid";
|
|
7
|
-
import splitContent from "./SplitContent";
|
|
8
|
-
import button from "./Button";
|
|
9
|
-
import colors from "./Colors";
|
|
10
|
-
import doDontList from "./DoDontList";
|
|
11
|
-
import doDontImageGrid from "./DoDontMediaGrid";
|
|
12
|
-
import iconList from "./IconList";
|
|
13
|
-
|
|
14
|
-
const allDefs = [linkHeading, subHeading, subSubHeading, prose, mediaGrid,
|
|
15
|
-
splitContent, button, colors, doDontList, doDontImageGrid, iconList,
|
|
16
|
-
];
|
|
2
|
+
import { allSectionDefs } from "./all-sections";
|
|
17
3
|
|
|
4
|
+
// NOTE: this still imports the full (component-bearing) section modules via the
|
|
5
|
+
// shared manifest, so /api/save's validation path currently evaluates React/
|
|
6
|
+
// TipTap. Decoupling that (schema-only sibling modules) is deferred — see
|
|
7
|
+
// docs/superpowers/specs/2026-06-13-custom-section-channel-design.md / backlog.
|
|
8
|
+
// The shared manifest already removes the original drift risk between the two
|
|
9
|
+
// registration lists, which was the correctness bug.
|
|
18
10
|
let _ensured = false;
|
|
19
11
|
export function ensureSchemasRegistered(): number {
|
|
20
12
|
if (!_ensured) {
|
|
21
|
-
|
|
13
|
+
allSectionDefs.forEach((def) => registerSchema(def.type, def.schema));
|
|
22
14
|
_ensured = true;
|
|
23
15
|
}
|
|
24
|
-
return
|
|
16
|
+
return allSectionDefs.length;
|
|
25
17
|
}
|
|
@@ -1,25 +1,11 @@
|
|
|
1
1
|
import { registerSection } from "../../lib/registry";
|
|
2
|
-
import
|
|
3
|
-
import subHeading from "./SubHeading";
|
|
4
|
-
import subSubHeading from "./SubSubHeading";
|
|
5
|
-
import prose from "./Prose";
|
|
6
|
-
import mediaGrid from "./MediaGrid";
|
|
7
|
-
import splitContent from "./SplitContent";
|
|
8
|
-
import button from "./Button";
|
|
9
|
-
import colors from "./Colors";
|
|
10
|
-
import doDontList from "./DoDontList";
|
|
11
|
-
import doDontImageGrid from "./DoDontMediaGrid";
|
|
12
|
-
import iconList from "./IconList";
|
|
13
|
-
|
|
14
|
-
const allDefs = [linkHeading, subHeading, subSubHeading, prose, mediaGrid,
|
|
15
|
-
splitContent, button, colors, doDontList, doDontImageGrid, iconList,
|
|
16
|
-
];
|
|
2
|
+
import { allSectionDefs } from "./all-sections";
|
|
17
3
|
|
|
18
4
|
let _ensured = false;
|
|
19
5
|
export function ensureSectionsRegistered(): number {
|
|
20
6
|
if (!_ensured) {
|
|
21
|
-
|
|
7
|
+
allSectionDefs.forEach(registerSection);
|
|
22
8
|
_ensured = true;
|
|
23
9
|
}
|
|
24
|
-
return
|
|
10
|
+
return allSectionDefs.length;
|
|
25
11
|
}
|
|
@@ -80,6 +80,10 @@ type ShellState =
|
|
|
80
80
|
|
|
81
81
|
interface Props {
|
|
82
82
|
headSha: string;
|
|
83
|
+
// Head of the branch the editor actually loads (draft `saved` if it exists,
|
|
84
|
+
// else main). The content cache is keyed on this, so a load with drafts can
|
|
85
|
+
// hit the cache instead of refetching every section. Falls back to headSha.
|
|
86
|
+
draftHeadSha?: string;
|
|
83
87
|
siteId: string;
|
|
84
88
|
audiences: Audience[];
|
|
85
89
|
capabilities: {
|
|
@@ -95,6 +99,7 @@ interface Props {
|
|
|
95
99
|
|
|
96
100
|
export default function EditorShell({
|
|
97
101
|
headSha,
|
|
102
|
+
draftHeadSha,
|
|
98
103
|
siteId,
|
|
99
104
|
audiences: initialAudiences,
|
|
100
105
|
capabilities,
|
|
@@ -117,6 +122,12 @@ export default function EditorShell({
|
|
|
117
122
|
const [pendingDeleteSectionId, setPendingDeleteSectionId] = useState<string | null>(null);
|
|
118
123
|
const [savedSha, setSavedSha] = useState<string | null>(null);
|
|
119
124
|
const [mainSha, setMainSha] = useState<string | null>(null);
|
|
125
|
+
// Mirror savedSha into a ref so the save handler reads the latest draft
|
|
126
|
+
// version (the optimistic-concurrency base) without a stale closure.
|
|
127
|
+
const savedShaRef = useRef<string | null>(null);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
savedShaRef.current = savedSha;
|
|
130
|
+
}, [savedSha]);
|
|
120
131
|
const [changedSectionIds, setChangedSectionIds] = useState<Set<string>>(new Set());
|
|
121
132
|
const [mainIndex, setMainIndex] = useState<SiteIndex | null>(null);
|
|
122
133
|
const [viewSections, setViewSections] = useState<LoadedSection[] | null>(null);
|
|
@@ -253,6 +264,7 @@ export default function EditorShell({
|
|
|
253
264
|
setMainSha((prev) => newMainSha ?? prev);
|
|
254
265
|
},
|
|
255
266
|
onPublishComplete: buildStatus.startTracking,
|
|
267
|
+
getBaseVersion: () => savedShaRef.current,
|
|
256
268
|
});
|
|
257
269
|
|
|
258
270
|
const { buttonState } = useContentLifecycle({
|
|
@@ -350,14 +362,32 @@ export default function EditorShell({
|
|
|
350
362
|
let loadedConfig: SiteConfig;
|
|
351
363
|
let loadedManifest: MediaManifest = { images: {} };
|
|
352
364
|
|
|
365
|
+
// Key the content cache on the head of the branch we actually load (the
|
|
366
|
+
// draft `saved` branch if it exists, else main), provided by the SSR edit
|
|
367
|
+
// page. Previously this compared against main's head while the cache
|
|
368
|
+
// stored the saved-branch SHA, so any load with a draft missed and
|
|
369
|
+
// refetched ~2N+ files from GitHub every time.
|
|
370
|
+
//
|
|
371
|
+
// draftHeadSha is the server's view at page-load time (fresher than the
|
|
372
|
+
// client could get without a blocking round-trip). It can only be stale for
|
|
373
|
+
// the SSR->hydration window, and only if another writer moves the draft in
|
|
374
|
+
// that window AND this browser already cached the old SHA; the result is at
|
|
375
|
+
// worst momentarily-stale read content, self-corrected on reload and guarded
|
|
376
|
+
// against lost writes by the save-time 409 (optimistic concurrency). We
|
|
377
|
+
// deliberately don't block every load on a freshness fetch to validate this.
|
|
378
|
+
const cacheKeySha = draftHeadSha ?? headSha;
|
|
379
|
+
|
|
353
380
|
const cached = await getCachedContent();
|
|
354
|
-
if (cached && cached.sha ===
|
|
381
|
+
if (cached && cached.sha === cacheKeySha) {
|
|
355
382
|
loadedSections = cached.sections;
|
|
356
383
|
loadedIndex = cached.index;
|
|
357
384
|
loadedConfig = SiteConfigSchema.parse(cached.siteConfig);
|
|
358
385
|
const savedManifest = await getMediaManifest();
|
|
359
386
|
if (savedManifest) loadedManifest = savedManifest;
|
|
360
|
-
|
|
387
|
+
setSavedSha(cached.savedBranchSha ?? null);
|
|
388
|
+
setMainSha(headSha);
|
|
389
|
+
setChangedSectionIds(new Set(cached.changedSectionIds ?? []));
|
|
390
|
+
setMainIndex(cached.mainIndex ?? loadedIndex);
|
|
361
391
|
} else {
|
|
362
392
|
const response = await fetch("/api/content?branch=saved");
|
|
363
393
|
if (!response.ok) throw new Error(`Failed to load content: ${response.status}`);
|
|
@@ -365,7 +395,11 @@ export default function EditorShell({
|
|
|
365
395
|
loadedSections = data.sections;
|
|
366
396
|
loadedIndex = data.index;
|
|
367
397
|
loadedConfig = SiteConfigSchema.parse(data.siteConfig);
|
|
368
|
-
await cacheContent(data.sha, data.sections, data.index, data.siteConfig
|
|
398
|
+
await cacheContent(data.sha, data.sections, data.index, data.siteConfig, {
|
|
399
|
+
savedBranchSha: data.savedBranchSha ?? null,
|
|
400
|
+
changedSectionIds: data.changedSectionIds ?? [],
|
|
401
|
+
mainIndex: data.mainIndex ?? data.index,
|
|
402
|
+
});
|
|
369
403
|
if (data.mediaManifest) {
|
|
370
404
|
loadedManifest = data.mediaManifest as MediaManifest;
|
|
371
405
|
await persistMediaManifest(loadedManifest);
|
|
@@ -428,7 +462,7 @@ export default function EditorShell({
|
|
|
428
462
|
setShellState({ phase: "error", message: err instanceof Error ? err.message : "Failed to load content" });
|
|
429
463
|
});
|
|
430
464
|
return () => { cancelled = true; };
|
|
431
|
-
}, [headSha, siteId, applySiteConfigPreview]);
|
|
465
|
+
}, [headSha, draftHeadSha, siteId, applySiteConfigPreview]);
|
|
432
466
|
|
|
433
467
|
// --- Recovery handlers ---
|
|
434
468
|
|
|
@@ -819,7 +853,10 @@ export default function EditorShell({
|
|
|
819
853
|
onPagesClick={() => setShowPagesModal(true)}
|
|
820
854
|
/>
|
|
821
855
|
|
|
822
|
-
|
|
856
|
+
{/* Bug reports persist via Supabase. On the password-only (zero-Supabase)
|
|
857
|
+
path there's no backend and the editor session has userId: null, so
|
|
858
|
+
the button would always 401 — hide it there. */}
|
|
859
|
+
{!capabilities.passwordOnly && <BugReportFAB />}
|
|
823
860
|
|
|
824
861
|
{rejectedUploads.length > 0 && (
|
|
825
862
|
<div className="sticky top-2 z-30 mx-auto w-full max-w-3xl px-4">
|
|
@@ -2,7 +2,7 @@ import { useState, useCallback, useRef, useEffect } from "react";
|
|
|
2
2
|
import type { SiteIndex, SiteConfig } from "../schemas/site-config";
|
|
3
3
|
import type { LoadedSection } from "../lib/loader";
|
|
4
4
|
import type { MediaManifest, MediaItem } from "../media/types";
|
|
5
|
-
import { getDirtySectionRows, hasLocalChanges, discardSavedChanges, cacheContent, getPendingMediaBlobs, clearPendingMediaByIds } from "../lib/dexie";
|
|
5
|
+
import { getDirtySectionRows, hasLocalChanges, discardSavedChanges, cacheContent, clearContentCache, getPendingMediaBlobs, clearPendingMediaByIds } from "../lib/dexie";
|
|
6
6
|
|
|
7
7
|
function blobToBase64(blob: Blob): Promise<string> {
|
|
8
8
|
return new Promise((resolve, reject) => {
|
|
@@ -34,6 +34,10 @@ interface PublishDeps {
|
|
|
34
34
|
onMediaPublished: (publishedItems: MediaItem[], publishedDeletions: string[]) => void;
|
|
35
35
|
onShasUpdated: (savedSha: string | null, mainSha: string | null) => void;
|
|
36
36
|
onPublishComplete?: () => void;
|
|
37
|
+
// The draft version this editor is based on (saved-branch head, or null when
|
|
38
|
+
// no draft exists yet). Sent with saves so the server can 409 on a concurrent
|
|
39
|
+
// edit instead of silently overwriting it. Read at save time (latest value).
|
|
40
|
+
getBaseVersion: () => string | null;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
interface GatheredMedia {
|
|
@@ -62,6 +66,7 @@ export function useEditorPublish({
|
|
|
62
66
|
onMediaPublished,
|
|
63
67
|
onShasUpdated,
|
|
64
68
|
onPublishComplete,
|
|
69
|
+
getBaseVersion,
|
|
65
70
|
}: PublishDeps) {
|
|
66
71
|
const [publishAction, setPublishAction] = useState<PublishAction>("idle");
|
|
67
72
|
const [publishFeedback, setPublishFeedback] = useState<string | null>(null);
|
|
@@ -172,6 +177,7 @@ export function useEditorPublish({
|
|
|
172
177
|
content,
|
|
173
178
|
})),
|
|
174
179
|
siteIndex,
|
|
180
|
+
baseVersion: getBaseVersion(),
|
|
175
181
|
...(args.deletedSectionIds?.length ? { deletedSectionIds: args.deletedSectionIds } : {}),
|
|
176
182
|
...(args.isConfigDirty() ? { siteConfig: args.siteConfig } : {}),
|
|
177
183
|
...(gathered.hasMediaChanges ? {
|
|
@@ -189,7 +195,8 @@ export function useEditorPublish({
|
|
|
189
195
|
|
|
190
196
|
if (!response.ok) {
|
|
191
197
|
const errorBody = await response.json().catch(() => ({}));
|
|
192
|
-
|
|
198
|
+
const message = errorBody.message || errorBody.error || "Save failed";
|
|
199
|
+
throw Object.assign(new Error(message), { status: response.status });
|
|
193
200
|
}
|
|
194
201
|
|
|
195
202
|
const responseData = await response.json().catch(() => null);
|
|
@@ -247,7 +254,8 @@ export function useEditorPublish({
|
|
|
247
254
|
showFeedback("Saved", 3000);
|
|
248
255
|
} catch (error) {
|
|
249
256
|
console.error("Save failed:", error);
|
|
250
|
-
|
|
257
|
+
const isConflict = (error as { status?: number })?.status === 409;
|
|
258
|
+
showFeedback(isConflict ? (error as Error).message : "Save failed", isConflict ? 8000 : 5000);
|
|
251
259
|
} finally {
|
|
252
260
|
inFlightRef.current = false;
|
|
253
261
|
setPublishAction("idle");
|
|
@@ -275,6 +283,10 @@ export function useEditorPublish({
|
|
|
275
283
|
}
|
|
276
284
|
const { sha } = responseData;
|
|
277
285
|
|
|
286
|
+
// The draft branch is gone after publish — drop the cached content snapshot
|
|
287
|
+
// so its now-stale diff state (savedBranchSha/changedSectionIds) can't be
|
|
288
|
+
// restored on a later cache hit. (Save & Publish already re-caches instead.)
|
|
289
|
+
await clearContentCache();
|
|
278
290
|
onShasUpdated(null, sha);
|
|
279
291
|
onPublishComplete?.();
|
|
280
292
|
} catch (error) {
|
|
@@ -342,7 +354,8 @@ export function useEditorPublish({
|
|
|
342
354
|
onPublishComplete?.();
|
|
343
355
|
} catch (error) {
|
|
344
356
|
console.error("Publish failed:", error);
|
|
345
|
-
|
|
357
|
+
const isConflict = (error as { status?: number })?.status === 409;
|
|
358
|
+
showFeedback(isConflict ? (error as Error).message : "Publish failed", isConflict ? 8000 : 5000);
|
|
346
359
|
} finally {
|
|
347
360
|
inFlightRef.current = false;
|
|
348
361
|
setPublishAction("idle");
|
package/src/lib/dexie.ts
CHANGED
|
@@ -40,6 +40,12 @@ interface ContentCacheRow {
|
|
|
40
40
|
index: SiteIndex;
|
|
41
41
|
siteConfig: Record<string, unknown>;
|
|
42
42
|
updatedAt: string;
|
|
43
|
+
// Draft-vs-published diff state, cached alongside the content so a cache hit
|
|
44
|
+
// (same sha) restores the editor's "changed since published" indicators
|
|
45
|
+
// without re-deriving them from GitHub. Optional for backward compatibility.
|
|
46
|
+
savedBranchSha?: string | null;
|
|
47
|
+
changedSectionIds?: string[];
|
|
48
|
+
mainIndex?: SiteIndex | null;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
interface MediaManifestRow {
|
|
@@ -389,6 +395,7 @@ export async function cacheContent(
|
|
|
389
395
|
sections: LoadedSection[],
|
|
390
396
|
index: SiteIndex,
|
|
391
397
|
siteConfig: Record<string, unknown>,
|
|
398
|
+
diff?: { savedBranchSha: string | null; changedSectionIds: string[]; mainIndex: SiteIndex | null },
|
|
392
399
|
): Promise<void> {
|
|
393
400
|
const now = new Date().toISOString();
|
|
394
401
|
await getDb().contentCache.put({
|
|
@@ -398,6 +405,9 @@ export async function cacheContent(
|
|
|
398
405
|
index,
|
|
399
406
|
siteConfig,
|
|
400
407
|
updatedAt: now,
|
|
408
|
+
savedBranchSha: diff?.savedBranchSha ?? null,
|
|
409
|
+
changedSectionIds: diff?.changedSectionIds ?? [],
|
|
410
|
+
mainIndex: diff?.mainIndex ?? null,
|
|
401
411
|
});
|
|
402
412
|
}
|
|
403
413
|
|
|
@@ -406,6 +416,9 @@ export async function getCachedContent(): Promise<{
|
|
|
406
416
|
sections: LoadedSection[];
|
|
407
417
|
index: SiteIndex;
|
|
408
418
|
siteConfig: Record<string, unknown>;
|
|
419
|
+
savedBranchSha: string | null;
|
|
420
|
+
changedSectionIds: string[];
|
|
421
|
+
mainIndex: SiteIndex | null;
|
|
409
422
|
} | null> {
|
|
410
423
|
const row = await getDb().contentCache.get("current");
|
|
411
424
|
if (!row) return null;
|
|
@@ -414,9 +427,21 @@ export async function getCachedContent(): Promise<{
|
|
|
414
427
|
sections: row.sections,
|
|
415
428
|
index: row.index,
|
|
416
429
|
siteConfig: row.siteConfig,
|
|
430
|
+
savedBranchSha: row.savedBranchSha ?? null,
|
|
431
|
+
changedSectionIds: row.changedSectionIds ?? [],
|
|
432
|
+
// No stored mainIndex (e.g. legacy or post-publish cache) means "no draft",
|
|
433
|
+
// so the published index equals the current index.
|
|
434
|
+
mainIndex: row.mainIndex ?? row.index,
|
|
417
435
|
};
|
|
418
436
|
}
|
|
419
437
|
|
|
438
|
+
/** Invalidate only the cached content snapshot (e.g. after a publish removes the
|
|
439
|
+
* draft), forcing the next editor load to refetch rather than serve stale diff
|
|
440
|
+
* state. Narrower than discardSavedChanges, which also clears index/meta/config. */
|
|
441
|
+
export async function clearContentCache(): Promise<void> {
|
|
442
|
+
await getDb().contentCache.clear();
|
|
443
|
+
}
|
|
444
|
+
|
|
420
445
|
export async function persistMediaManifest(manifest: MediaManifest): Promise<void> {
|
|
421
446
|
const now = new Date().toISOString();
|
|
422
447
|
await getDb().mediaManifest.put({ key: "current", manifest, updatedAt: now });
|
package/src/lib/registry.ts
CHANGED
|
@@ -105,7 +105,6 @@ export interface SectionDefinition<T = unknown> {
|
|
|
105
105
|
schema: ZodType<T>;
|
|
106
106
|
component: ComponentType<SectionProps<T>>;
|
|
107
107
|
defaults: () => T;
|
|
108
|
-
wrapper?: ComponentType<WrapperProps>;
|
|
109
108
|
settings?: SettingsSchema;
|
|
110
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
110
|
settingsForm?: ComponentType<any>;
|
|
@@ -123,7 +122,6 @@ type DefineSectionInput<S extends ZodType> = {
|
|
|
123
122
|
schema: S;
|
|
124
123
|
component: ComponentType<SectionProps<z.infer<S>>>;
|
|
125
124
|
defaults: () => z.infer<S>;
|
|
126
|
-
wrapper?: ComponentType<WrapperProps>;
|
|
127
125
|
settings?: SettingsSchema;
|
|
128
126
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
127
|
settingsForm?: ComponentType<any>;
|
package/src/lib/sanitize.ts
CHANGED
|
@@ -9,6 +9,14 @@ if (typeof window !== "undefined") {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// Memoize sanitized output per input string. In the editor, every keystroke
|
|
13
|
+
// re-renders all sections, re-running DOMPurify (CPU-heavy HTML parsing) on
|
|
14
|
+
// every inactive rich-text block whose HTML hasn't changed. Caching by input
|
|
15
|
+
// value makes those repeats free. Bounded with FIFO eviction so it can't grow
|
|
16
|
+
// without limit across a long editing session.
|
|
17
|
+
const sanitizeCache = new Map<string, string>();
|
|
18
|
+
const SANITIZE_CACHE_LIMIT = 500;
|
|
19
|
+
|
|
12
20
|
/**
|
|
13
21
|
* Synchronous sanitizer — returns sanitized HTML if DOMPurify has loaded,
|
|
14
22
|
* otherwise returns raw HTML. Call `ensureSanitizer()` during component mount
|
|
@@ -16,7 +24,20 @@ if (typeof window !== "undefined") {
|
|
|
16
24
|
*/
|
|
17
25
|
export function sanitizeHtml(html: string): string {
|
|
18
26
|
if (!html) return "";
|
|
19
|
-
|
|
27
|
+
// Don't cache the pre-DOMPurify passthrough — once the purifier loads, the
|
|
28
|
+
// same input must produce sanitized output.
|
|
29
|
+
if (!purifier) return html;
|
|
30
|
+
|
|
31
|
+
const cached = sanitizeCache.get(html);
|
|
32
|
+
if (cached !== undefined) return cached;
|
|
33
|
+
|
|
34
|
+
const clean = purifier(html);
|
|
35
|
+
if (sanitizeCache.size >= SANITIZE_CACHE_LIMIT) {
|
|
36
|
+
const oldest = sanitizeCache.keys().next().value;
|
|
37
|
+
if (oldest !== undefined) sanitizeCache.delete(oldest);
|
|
38
|
+
}
|
|
39
|
+
sanitizeCache.set(html, clean);
|
|
40
|
+
return clean;
|
|
20
41
|
}
|
|
21
42
|
|
|
22
43
|
/**
|
package/src/schemas/shared.ts
CHANGED
|
@@ -76,6 +76,16 @@ export const HexColorSchema = z
|
|
|
76
76
|
.string()
|
|
77
77
|
.regex(/^#[0-9a-fA-F]{6}$/, "must be a 6-digit hex color");
|
|
78
78
|
|
|
79
|
+
// Font-family names are interpolated raw into the `style` attribute on <html>
|
|
80
|
+
// (`--font-heading: ${headingFont}, ...`). Astro HTML-escapes the attribute, so
|
|
81
|
+
// the residual risk is CSS-declaration injection via `;`/`{}`. Allow only the
|
|
82
|
+
// characters legitimate font names use (letters, digits, spaces, commas for
|
|
83
|
+
// fallback lists, quotes for quoted names, hyphens) and bound the length.
|
|
84
|
+
export const FontNameSchema = z
|
|
85
|
+
.string()
|
|
86
|
+
.max(120)
|
|
87
|
+
.regex(/^[a-zA-Z0-9 ,'"-]+$/, "contains invalid font-name characters");
|
|
88
|
+
|
|
79
89
|
export const ColorSpaceSchema = z.object({
|
|
80
90
|
hex: HexColorSchema.optional(),
|
|
81
91
|
rgb: z.string().optional(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { MediaConfigSchema } from "./media";
|
|
3
|
-
import { HexColorSchema } from "./shared";
|
|
3
|
+
import { HexColorSchema, FontNameSchema } from "./shared";
|
|
4
4
|
|
|
5
5
|
const StatusSchema = z.enum(["draft", "live", "archived", "published"]).transform(
|
|
6
6
|
(val) => val === "published" ? "live" as const : val,
|
|
@@ -137,8 +137,8 @@ export const SiteConfigSchema = z.object({
|
|
|
137
137
|
primaryColor: HexColorSchema.default("#009ca6"),
|
|
138
138
|
primaryContrast: HexColorSchema.default("#f0f0f0"),
|
|
139
139
|
darkMode: z.enum(["light", "dark", "optional"]).default("light"),
|
|
140
|
-
headingFont:
|
|
141
|
-
bodyFont:
|
|
140
|
+
headingFont: FontNameSchema.default("system-ui"),
|
|
141
|
+
bodyFont: FontNameSchema.default("system-ui"),
|
|
142
142
|
uppercaseHeadings: z.boolean().default(true),
|
|
143
143
|
uppercaseSubheadings: z.boolean().default(true),
|
|
144
144
|
uppercaseNavHeadings: z.boolean().default(true),
|
package/src/storage/index.ts
CHANGED
package/src/storage/types.ts
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by `writeFiles` when `options.baseVersion` no longer matches the
|
|
3
|
+
* draft's current version — i.e. another editor (or the same user on another
|
|
4
|
+
* device) committed since this editor loaded. Callers should surface a 409 and
|
|
5
|
+
* prompt a reload rather than clobbering the concurrent work (last-write-wins).
|
|
6
|
+
*/
|
|
7
|
+
export class StorageConflictError extends Error {
|
|
8
|
+
constructor(public readonly currentVersion: string | null) {
|
|
9
|
+
super("Draft has been modified since it was loaded");
|
|
10
|
+
this.name = "StorageConflictError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
1
14
|
export interface StorageProvider {
|
|
2
15
|
writeFiles(
|
|
3
16
|
files: FileWrite[],
|
|
4
17
|
message: string,
|
|
18
|
+
// `baseVersion` is the draft version the edits were based on. When present,
|
|
19
|
+
// the write is rejected with StorageConflictError if the draft has moved
|
|
20
|
+
// since (null means "expected no draft to exist yet").
|
|
21
|
+
options?: { baseVersion?: string | null },
|
|
5
22
|
): Promise<{ version: string }>;
|
|
6
23
|
|
|
7
24
|
readFile(
|