Site builder: security & data-loss hardening + unified asset picker + audit backlog #3

Merged
jknapp merged 61 commits from builder-hardening-2026-07 into main 2026-07-13 01:13:28 +00:00
3 changed files with 6 additions and 13 deletions
Showing only changes of commit cf56f2a388 - Show all commits
+4 -4
View File
@@ -2,10 +2,10 @@ import { describe, test, expect } from 'vitest';
import { buildSavePayload } from './useWhpApi'; import { buildSavePayload } from './useWhpApi';
import { PageData } from '../types'; import { PageData } from '../types';
const pageA: PageData = { id: 'home', name: 'Home', slug: 'index', craftState: 'STORED_HOME', headCode: '' }; const pageA: PageData = { id: 'home', name: 'Home', slug: 'index', craftState: 'STORED_HOME' };
const pageB: PageData = { id: 'page_2', name: 'About', slug: 'about', craftState: 'STORED_ABOUT', headCode: '' }; const pageB: PageData = { id: 'page_2', name: 'About', slug: 'about', craftState: 'STORED_ABOUT' };
const headerPage: PageData = { id: '__header__', name: 'Header', slug: '__header__', craftState: 'STALE_HEADER', headCode: '' }; const headerPage: PageData = { id: '__header__', name: 'Header', slug: '__header__', craftState: 'STALE_HEADER' };
const footerPage: PageData = { id: '__footer__', name: 'Footer', slug: '__footer__', craftState: 'STALE_FOOTER', headCode: '' }; const footerPage: PageData = { id: '__footer__', name: 'Footer', slug: '__footer__', craftState: 'STALE_FOOTER' };
describe('buildSavePayload', () => { describe('buildSavePayload', () => {
test('editing header: live serialize lands in header_craft_state, not in any page slot', () => { test('editing header: live serialize lands in header_craft_state, not in any page slot', () => {
+2 -8
View File
@@ -116,8 +116,8 @@ export const DEFAULT_HEADER_STATE = JSON.stringify({
const PageContext = createContext<PageContextValue>({ const PageContext = createContext<PageContextValue>({
pages: [], pages: [],
headerPage: { id: HEADER_ID, name: 'Header', slug: '__header__', craftState: null, headCode: '' }, headerPage: { id: HEADER_ID, name: 'Header', slug: '__header__', craftState: null },
footerPage: { id: FOOTER_ID, name: 'Footer', slug: '__footer__', craftState: null, headCode: '' }, footerPage: { id: FOOTER_ID, name: 'Footer', slug: '__footer__', craftState: null },
activePageId: 'home', activePageId: 'home',
isEditingHeader: false, isEditingHeader: false,
isEditingFooter: false, isEditingFooter: false,
@@ -166,7 +166,6 @@ const DEFAULT_PAGE: PageData = {
name: 'Home', name: 'Home',
slug: 'index', slug: 'index',
craftState: null, craftState: null,
headCode: '',
}; };
const DEFAULT_HEADER: PageData = { const DEFAULT_HEADER: PageData = {
@@ -174,7 +173,6 @@ const DEFAULT_HEADER: PageData = {
name: 'Header', name: 'Header',
slug: '__header__', slug: '__header__',
craftState: DEFAULT_HEADER_STATE, craftState: DEFAULT_HEADER_STATE,
headCode: '',
}; };
const DEFAULT_FOOTER: PageData = { const DEFAULT_FOOTER: PageData = {
@@ -182,7 +180,6 @@ const DEFAULT_FOOTER: PageData = {
name: 'Footer', name: 'Footer',
slug: '__footer__', slug: '__footer__',
craftState: null, craftState: null,
headCode: '',
}; };
export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) => { export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
@@ -307,7 +304,6 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
name, name,
slug: uniqueSlug(requestedSlug, prev.map((p) => p.slug)), slug: uniqueSlug(requestedSlug, prev.map((p) => p.slug)),
craftState: null, craftState: null,
headCode: '',
}, },
]); ]);
@@ -380,7 +376,6 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
// ALWAYS the landing page → slug 'index' → file index.html. // ALWAYS the landing page → slug 'index' → file index.html.
slug: i === 0 ? 'index' : p.slug, slug: i === 0 ? 'index' : p.slug,
craftState: p.craftState, craftState: p.craftState,
headCode: '',
}))); })));
}, []); }, []);
@@ -500,7 +495,6 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
name: p.name, name: p.name,
slug, slug,
craftState: treeToState(p.tree), craftState: treeToState(p.tree),
headCode: '',
}; };
}); });
setPages(built); setPages(built);
-1
View File
@@ -16,7 +16,6 @@ export interface PageData {
name: string; name: string;
slug: string; slug: string;
craftState: string | null; craftState: string | null;
headCode: string;
} }
export interface AssetData { export interface AssetData {