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 { PageData } from '../types';
const pageA: PageData = { id: 'home', name: 'Home', slug: 'index', craftState: 'STORED_HOME', headCode: '' };
const pageB: PageData = { id: 'page_2', name: 'About', slug: 'about', craftState: 'STORED_ABOUT', headCode: '' };
const headerPage: PageData = { id: '__header__', name: 'Header', slug: '__header__', craftState: 'STALE_HEADER', headCode: '' };
const footerPage: PageData = { id: '__footer__', name: 'Footer', slug: '__footer__', craftState: 'STALE_FOOTER', 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' };
const headerPage: PageData = { id: '__header__', name: 'Header', slug: '__header__', craftState: 'STALE_HEADER' };
const footerPage: PageData = { id: '__footer__', name: 'Footer', slug: '__footer__', craftState: 'STALE_FOOTER' };
describe('buildSavePayload', () => {
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>({
pages: [],
headerPage: { id: HEADER_ID, name: 'Header', slug: '__header__', craftState: null, headCode: '' },
footerPage: { id: FOOTER_ID, name: 'Footer', slug: '__footer__', craftState: null, headCode: '' },
headerPage: { id: HEADER_ID, name: 'Header', slug: '__header__', craftState: null },
footerPage: { id: FOOTER_ID, name: 'Footer', slug: '__footer__', craftState: null },
activePageId: 'home',
isEditingHeader: false,
isEditingFooter: false,
@@ -166,7 +166,6 @@ const DEFAULT_PAGE: PageData = {
name: 'Home',
slug: 'index',
craftState: null,
headCode: '',
};
const DEFAULT_HEADER: PageData = {
@@ -174,7 +173,6 @@ const DEFAULT_HEADER: PageData = {
name: 'Header',
slug: '__header__',
craftState: DEFAULT_HEADER_STATE,
headCode: '',
};
const DEFAULT_FOOTER: PageData = {
@@ -182,7 +180,6 @@ const DEFAULT_FOOTER: PageData = {
name: 'Footer',
slug: '__footer__',
craftState: null,
headCode: '',
};
export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
@@ -307,7 +304,6 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
name,
slug: uniqueSlug(requestedSlug, prev.map((p) => p.slug)),
craftState: null,
headCode: '',
},
]);
@@ -380,7 +376,6 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
// ALWAYS the landing page → slug 'index' → file index.html.
slug: i === 0 ? 'index' : p.slug,
craftState: p.craftState,
headCode: '',
})));
}, []);
@@ -500,7 +495,6 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
name: p.name,
slug,
craftState: treeToState(p.tree),
headCode: '',
};
});
setPages(built);
-1
View File
@@ -16,7 +16,6 @@ export interface PageData {
name: string;
slug: string;
craftState: string | null;
headCode: string;
}
export interface AssetData {