Skip to content

Commit 21f1354

Browse files
committed
Add canonical Cloudflare runtime homepage
1 parent 486bdf8 commit 21f1354

4 files changed

Lines changed: 152 additions & 14 deletions

File tree

packages/runtime-cloudflare/assets/markdown-database-integration-canonical-seed.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"schema": "wp-codebox/cloudflare-canonical-mdi-seed/v1",
33
"markdownDatabaseIntegrationRevision": "2a8ee7f6a46e1d64b4606f1ee3c97e14032dc96c",
44
"wordpressInstallSeedSha256": "7212b89f1c01f98a23b89e9a2dd2b214306a85c10adb0355b9c7a6005b4fe822",
5-
"archiveSha256": "717b53395be2eb29ba7419f5a0b7eee4fe5a6527ec09246b24133aea82b3686c",
5+
"archiveSha256": "ee84fad280beb3ee2965a6f430b849ea31ce2899d2533b2906da7dcf3f306a43",
66
"files": [
77
{
88
"path": "_options/active_plugins.json",
@@ -61,13 +61,13 @@
6161
},
6262
{
6363
"path": "_options/blogdescription.json",
64-
"sha256": "759154f66c8b9bed0810ce36349fc7a2ed8a0da3acf6c59a2e6e01f863d89c5b",
65-
"size": 106
64+
"sha256": "c2c48dc802585847cd2301fcb89c10b624104a2860afb29b4b27569cfe390136",
65+
"size": 157
6666
},
6767
{
6868
"path": "_options/blogname.json",
69-
"sha256": "2d121fcce756b914f84be99b8a0a75a1003e6a21f46e4c9d1dcf10502aa18de2",
70-
"size": 119
69+
"sha256": "bb010b37edc23e3855e5afb90109904858c0e7c1e1df070fc3af50c8cd0a06cb",
70+
"size": 127
7171
},
7272
{
7373
"path": "_options/category_base.json",
@@ -311,7 +311,7 @@
311311
},
312312
{
313313
"path": "_options/page_on_front.json",
314-
"sha256": "aff01d58fb09d4c284db6550484612b378ef54a95b2843faba230e57f3ab6da3",
314+
"sha256": "94b00bb0fc5ef8ef6af537bfdae32d3d568f64261627e15a4bbe113c79e90bc7",
315315
"size": 106
316316
},
317317
{
@@ -366,8 +366,8 @@
366366
},
367367
{
368368
"path": "_options/show_on_front.json",
369-
"sha256": "34d9c066eb8dd1f36c14e67e5b34ba4cfb041ebdc9d9ba1be2b78869879bb002",
370-
"size": 110
369+
"sha256": "fdac10eccf664e5d32e0467b7827b6fb589b7be04eafb1ff5188964521203b56",
370+
"size": 109
371371
},
372372
{
373373
"path": "_options/sidebars_widgets.json",
@@ -411,7 +411,7 @@
411411
},
412412
{
413413
"path": "_options/theme_mods_twentytwentyfive.json",
414-
"sha256": "1d251370cb28c8d1aa06c7d78a0cb604e954caff117eb306321c7111d60035c6",
414+
"sha256": "b9d65f5c32b7e37a1274a40166a4ef884540cc5aff658e40ced68cf58c4ae4a0",
415415
"size": 161
416416
},
417417
{
@@ -659,16 +659,16 @@
659659
"sha256": "a59e1935b9636e9e7fe2fa2a9699e3d75fa055f91bf05a3a298cb97f14c463b7",
660660
"size": 431
661661
},
662+
{
663+
"path": "page/cloudflare-wordpress-runtime.md",
664+
"sha256": "f3d3e42ada4bdde99f505a83d6b69c5b027289f4dd147b5d0e026e441c9914b9",
665+
"size": 4820
666+
},
662667
{
663668
"path": "page/privacy-policy.md",
664669
"sha256": "a2a87d2d22e084f5c8feb45329881f24f22dc83e0882b1b2cfe8eb5b05decc01",
665670
"size": 6118
666671
},
667-
{
668-
"path": "page/sample-page.md",
669-
"sha256": "066c9dcb78ab3c93c719161e4d819bd136c12dda7b3dacf3497839a3ab927609",
670-
"size": 1923
671-
},
672672
{
673673
"path": "post/hello-world.md",
674674
"sha256": "3accc9d34069ca26be508b15ce84de25f4740b521b8acf12c87e97003c77fc11",
Binary file not shown.

scripts/build-cloudflare-canonical-mdi-seed.php

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,103 @@ function cloudflare_seed_files( string $root ): array {
5656
$output_zip = $assets . '/markdown-database-integration-canonical-seed.zip';
5757
$output_manifest = $assets . '/markdown-database-integration-canonical-seed.json';
5858
$root = sys_get_temp_dir() . '/wp-codebox-canonical-mdi-' . getmypid() . '-' . bin2hex( random_bytes( 4 ) );
59+
$front_page_content = <<<'HTML'
60+
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
61+
<main class="wp-block-group">
62+
<!-- wp:heading {"level":1} -->
63+
<h1 class="wp-block-heading">WordPress at the edge, with durable Markdown state</h1>
64+
<!-- /wp:heading -->
65+
66+
<!-- wp:paragraph {"fontSize":"large"} -->
67+
<p class="has-large-font-size">This bounded Cloudflare runtime runs WordPress and PHP as WebAssembly at the edge while keeping durable site state outside the disposable query database.</p>
68+
<!-- /wp:paragraph -->
69+
70+
<!-- wp:heading {"level":2} -->
71+
<h2 class="wp-block-heading">Architecture flow</h2>
72+
<!-- /wp:heading -->
73+
74+
<!-- wp:columns -->
75+
<div class="wp-block-columns"><!-- wp:column -->
76+
<div class="wp-block-column"><!-- wp:group {"layout":{"type":"constrained"}} -->
77+
<div class="wp-block-group"><!-- wp:heading {"level":3} -->
78+
<h3 class="wp-block-heading">Edge request</h3>
79+
<!-- /wp:heading --><!-- wp:paragraph -->
80+
<p>WordPress/PHP WebAssembly boots for the request.</p>
81+
<!-- /wp:paragraph --></div>
82+
<!-- /wp:group --></div>
83+
<!-- /wp:column -->
84+
85+
<!-- wp:column -->
86+
<div class="wp-block-column"><!-- wp:paragraph {"align":"center","fontSize":"x-large"} -->
87+
<p class="has-text-align-center has-x-large-font-size">&rarr;</p>
88+
<!-- /wp:paragraph --><!-- wp:group {"layout":{"type":"constrained"}} -->
89+
<div class="wp-block-group"><!-- wp:heading {"level":3} -->
90+
<h3 class="wp-block-heading">Disposable SQLite</h3>
91+
<!-- /wp:heading --><!-- wp:paragraph -->
92+
<p>SQLite is reconstructed as query state, not the durable source of truth.</p>
93+
<!-- /wp:paragraph --></div>
94+
<!-- /wp:group --></div>
95+
<!-- /wp:column -->
96+
97+
<!-- wp:column -->
98+
<div class="wp-block-column"><!-- wp:paragraph {"align":"center","fontSize":"x-large"} -->
99+
<p class="has-text-align-center has-x-large-font-size">&rarr;</p>
100+
<!-- /wp:paragraph --><!-- wp:group {"layout":{"type":"constrained"}} -->
101+
<div class="wp-block-group"><!-- wp:heading {"level":3} -->
102+
<h3 class="wp-block-heading">Canonical state</h3>
103+
<!-- /wp:heading --><!-- wp:paragraph -->
104+
<p>Markdown Database Integration exports canonical Markdown and JSON into immutable, content-addressed R2 objects and revision manifests.</p>
105+
<!-- /wp:paragraph --></div>
106+
<!-- /wp:group --></div>
107+
<!-- /wp:column -->
108+
109+
<!-- wp:column -->
110+
<div class="wp-block-column"><!-- wp:paragraph {"align":"center","fontSize":"x-large"} -->
111+
<p class="has-text-align-center has-x-large-font-size">&rarr;</p>
112+
<!-- /wp:paragraph --><!-- wp:group {"layout":{"type":"constrained"}} -->
113+
<div class="wp-block-group"><!-- wp:heading {"level":3} -->
114+
<h3 class="wp-block-heading">Serialized writes</h3>
115+
<!-- /wp:heading --><!-- wp:paragraph -->
116+
<p>A Durable Object serializes writes and atomically advances the current revision. A cold runtime hydrates that manifest and reconstructs SQLite.</p>
117+
<!-- /wp:paragraph --></div>
118+
<!-- /wp:group --></div>
119+
<!-- /wp:column --></div>
120+
<!-- /wp:columns -->
121+
122+
<!-- wp:heading {"level":2} -->
123+
<h2 class="wp-block-heading">Verified capabilities</h2>
124+
<!-- /wp:heading -->
125+
126+
<!-- wp:list -->
127+
<ul class="wp-block-list"><!-- wp:list-item -->
128+
<li>Log in to WordPress.</li>
129+
<!-- /wp:list-item --><!-- wp:list-item -->
130+
<li>Edit content with the block editor and publish it.</li>
131+
<!-- /wp:list-item --><!-- wp:list-item -->
132+
<li>Render the published page publicly.</li>
133+
<!-- /wp:list-item --><!-- wp:list-item -->
134+
<li>Recover the site after a cold start from the current revision manifest.</li>
135+
<!-- /wp:list-item --></ul>
136+
<!-- /wp:list -->
137+
138+
<!-- wp:heading {"level":2} -->
139+
<h2 class="wp-block-heading">Bounded by design</h2>
140+
<!-- /wp:heading -->
141+
142+
<!-- wp:list -->
143+
<ul class="wp-block-list"><!-- wp:list-item -->
144+
<li>One site namespace is currently configured.</li>
145+
<!-- /wp:list-item --><!-- wp:list-item -->
146+
<li>Requests for a site are serialized while a write lease is held.</li>
147+
<!-- /wp:list-item --><!-- wp:list-item -->
148+
<li>Each dynamic request currently pays PHP boot cost.</li>
149+
<!-- /wp:list-item --><!-- wp:list-item -->
150+
<li>Cold recovery hydrates the full revision manifest.</li>
151+
<!-- /wp:list-item --></ul>
152+
<!-- /wp:list -->
153+
</main>
154+
<!-- /wp:group -->
155+
HTML;
59156

60157
try {
61158
mkdir( $root, 0755, true );
@@ -71,6 +168,13 @@ function cloudflare_seed_files( string $root ): array {
71168
}
72169
$pdo = new PDO( 'sqlite:' . $database );
73170
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
171+
$front_page = $pdo->prepare( 'UPDATE wp_posts SET post_title = ?, post_name = ?, post_excerpt = ?, post_content = ?, post_status = ? WHERE ID = 2 AND post_type = ?' );
172+
$front_page->execute( array( 'Cloudflare WordPress Runtime', 'cloudflare-wordpress-runtime', 'A bounded WordPress WebAssembly runtime with canonical Markdown state in R2.', $front_page_content, 'publish', 'page' ) );
173+
if ( 1 !== $front_page->rowCount() ) { throw new RuntimeException( 'Unable to configure canonical front page ID 2.' ); }
174+
$options = $pdo->prepare( "INSERT INTO wp_options (option_name, option_value, autoload) VALUES (?, ?, 'on') ON CONFLICT(option_name) DO UPDATE SET option_value = excluded.option_value" );
175+
foreach ( array( 'blogname' => 'Cloudflare WordPress Runtime', 'blogdescription' => 'WordPress WebAssembly with canonical Markdown state', 'show_on_front' => 'page', 'page_on_front' => '2' ) as $name => $value ) {
176+
$options->execute( array( $name, $value ) );
177+
}
74178
$runtime = WP_Markdown_Primary_Storage_Runtime::bootstrap_existing_cache( array( 'content_root' => $markdown_root, 'state_root' => $markdown_root ), new WP_SQLite_Connection( $pdo ), 'wordpress' );
75179
$driver = $runtime->get_driver();
76180
$theme_mods = $pdo->prepare( "INSERT INTO wp_options (option_name, option_value, autoload) VALUES ('theme_mods_twentytwentyfive', ?, 'auto') ON CONFLICT(option_name) DO UPDATE SET option_value = excluded.option_value" );

tests/cloudflare-runtime.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,3 +405,37 @@ test("canonical MDI seed generator is reproducible and validates its pinned inpu
405405
assert.match(source, /SELECT ID FROM wp_posts ORDER BY ID/)
406406
assert.match(source, /MDI_REVISION/)
407407
})
408+
409+
test("canonical MDI seed owns the Cloudflare front page and its architecture explanation", async () => {
410+
const generator = await readFile(new URL("../scripts/build-cloudflare-canonical-mdi-seed.php", import.meta.url), "utf8")
411+
const archive = await readFile(new URL("../packages/runtime-cloudflare/assets/markdown-database-integration-canonical-seed.zip", import.meta.url))
412+
const files = new Map<string, string>()
413+
for await (const entry of decodeZip(new Blob([archive]).stream())) files.set(entry.name, await entry.text())
414+
const frontPage = files.get("page/cloudflare-wordpress-runtime.md") ?? ""
415+
416+
assert.match(generator, /UPDATE wp_posts SET post_title = \?, post_name = \?, post_excerpt = \?, post_content = \?, post_status = \? WHERE ID = 2 AND post_type = \?/)
417+
assert.match(generator, /'show_on_front' => 'page', 'page_on_front' => '2'/)
418+
assert.match(generator, /'blogname' => 'Cloudflare WordPress Runtime'/)
419+
assert.ok(files.has("_options/show_on_front.json"))
420+
assert.ok(files.has("_options/page_on_front.json"))
421+
assert.match(files.get("_options/show_on_front.json") ?? "", /"page"/)
422+
assert.match(files.get("_options/page_on_front.json") ?? "", /"2"/)
423+
assert.match(frontPage, /title: Cloudflare WordPress Runtime/)
424+
for (const claim of [
425+
"WordPress/PHP WebAssembly",
426+
"SQLite is reconstructed as query state",
427+
"canonical Markdown and JSON",
428+
"content-addressed R2 objects and revision manifests",
429+
"Durable Object serializes writes and atomically advances the current revision",
430+
"cold runtime hydrates that manifest and reconstructs SQLite",
431+
"Log in to WordPress",
432+
"block editor",
433+
"Render the published page publicly",
434+
"One site namespace",
435+
"Requests for a site are serialized",
436+
"PHP boot cost",
437+
"full revision manifest",
438+
]) assert.match(frontPage, new RegExp(claim))
439+
assert.match(frontPage, /<!-- wp:columns -->/)
440+
assert.match(frontPage, /<!-- wp:list -->/)
441+
})

0 commit comments

Comments
 (0)