Skip to content

Commit 9c01418

Browse files
committed
Bundle upstream auto-draft persistence fix
1 parent a56125c commit 9c01418

7 files changed

Lines changed: 13 additions & 86 deletions

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schema": "wp-codebox/cloudflare-canonical-mdi-seed/v1",
3-
"markdownDatabaseIntegrationRevision": "6244f244f47f99af3261ba0948262cebe79e5a73",
3+
"markdownDatabaseIntegrationRevision": "7cf025f2d64aa933d937f1a18a129e278c231783",
44
"wordpressInstallSeedSha256": "7212b89f1c01f98a23b89e9a2dd2b214306a85c10adb0355b9c7a6005b4fe822",
55
"archiveSha256": "d69b700c671ebee7f9eb01fa80d58c66072cf3966560d01cc188bd26b4818895",
66
"files": [
Binary file not shown.

packages/runtime-cloudflare/src/request-routing.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ export type WorkerRequestRoute =
55
| { kind: "r2-mutate" }
66
| { kind: "canonical-auth" }
77
| { kind: "operator-reset" }
8-
| { kind: "editor-probe"; phase: EditorProbePhase }
98
| { kind: "probe"; phase: string }
109

11-
export type EditorProbePhase = "admin" | "auto-draft" | "auto-draft-no-persist" | "block-editor"
12-
1310
export function routeWorkerRequest(request: Request): WorkerRequestRoute {
1411
const phase = new URL(request.url).searchParams.get("phase")
1512
if (phase === null) return { kind: "wordpress" }
@@ -18,9 +15,5 @@ export function routeWorkerRequest(request: Request): WorkerRequestRoute {
1815
if (phase === "r2-mutate") return { kind: "r2-mutate" }
1916
if (phase === "canonical-auth") return { kind: "canonical-auth" }
2017
if (phase === "operator-reset") return { kind: "operator-reset" }
21-
if (phase === "editor-probe-admin") return { kind: "editor-probe", phase: "admin" }
22-
if (phase === "editor-probe-auto-draft") return { kind: "editor-probe", phase: "auto-draft" }
23-
if (phase === "editor-probe-auto-draft-no-persist") return { kind: "editor-probe", phase: "auto-draft-no-persist" }
24-
if (phase === "editor-probe-block-editor") return { kind: "editor-probe", phase: "block-editor" }
2518
return { kind: "probe", phase }
2619
}

packages/runtime-cloudflare/src/worker.ts

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { dependenciesTotalSize, init } from "../../../node_modules/@php-wasm/web
77
import phpWasmModule from "../../../node_modules/@php-wasm/web-8-5/asyncify/8_5_8/php_8_5.wasm"
88
import { CLOUDFLARE_RUNTIME_HEALTH_MARKER, CLOUDFLARE_RUNTIME_HEALTH_SCHEMA, cloudflareRuntimeHealthResponse } from "./health-envelope.js"
99
import { leaseRetryDelayMs } from "./lease-retry.js"
10-
import { routeWorkerRequest, type EditorProbePhase } from "./request-routing.js"
10+
import { routeWorkerRequest } from "./request-routing.js"
1111
import { toFetchResponse, toPHPRequest } from "./request-translation.js"
1212
import { deriveWordPressAuthConstants, type WordPressAuthConstant } from "./wordpress-auth.js"
1313
import { isWordPressRuntimeFile, wordpressStaticArchivePath, wordpressStaticContentType } from "./wordpress-runtime-corpus.js"
@@ -25,7 +25,7 @@ const PHP_VERSION = "8.5.8"
2525
// Browser assets must come from the same immutable WordPress release as the server corpus.
2626
const WORDPRESS_ARCHIVE_URL = (wordpressRuntimeArtifactManifest as WordPressRuntimeArtifactManifest).source.url
2727
const SQLITE_INTEGRATION_ARCHIVE_URL = "https://github.com/WordPress/sqlite-database-integration/releases/download/v2.2.23/plugin-sqlite-database-integration.zip"
28-
const MARKDOWN_DATABASE_INTEGRATION_REVISION = "6244f244f47f99af3261ba0948262cebe79e5a73"
28+
const MARKDOWN_DATABASE_INTEGRATION_REVISION = "7cf025f2d64aa933d937f1a18a129e278c231783"
2929
const SITE_URL = "https://wp-codebox-runtime.invalid"
3030
const DATABASE_PATH = "/wordpress/wp-content/database/.ht.sqlite"
3131
const MARKDOWN_ROOT = "/wordpress/wp-content/markdown"
@@ -86,7 +86,6 @@ export default {
8686
const route = routeWorkerRequest(request)
8787
const coordinator = env.WORDPRESS_STATE.getByName("default")
8888
if (route.kind === "operator-reset") return resetCanonicalWordPress(request, env, coordinator)
89-
if (route.kind === "editor-probe") return runCoordinatedEditorProbe(request, env, coordinator, route.phase)
9089
if (route.kind === "probe") {
9190
if (route.phase === "canonical-session") return canonicalSessionProbe(env.WORDPRESS_STATE_BUCKET, await coordinatorCall<{ pointer: MarkdownPointer | null }>(coordinator, request.url, "state"))
9291
return runBootProbe(route.phase, env.WORDPRESS_STATE_BUCKET)
@@ -100,60 +99,6 @@ export default {
10099
},
101100
}
102101

103-
async function runCoordinatedEditorProbe(request: Request, env: Env, coordinator: DurableObjectStub, phase: EditorProbePhase): Promise<Response> {
104-
const lease = await acquireLease(coordinator, request.url)
105-
let finalized = false
106-
try {
107-
if (!lease.pointer) throw new Error("Canonical WordPress must be initialized before running an editor probe.")
108-
const runtime = await getRuntime(env, lease.pointer, new URL(request.url).origin)
109-
if (phase === "auto-draft-no-persist") patchAutoDraftPersistenceProbe(runtime.php)
110-
patchEditorProbe(runtime.php, phase)
111-
const response = toFetchResponse(request, await runtime.requestHandler.request(await toPHPRequest(request)))
112-
await releaseLease(coordinator, request.url, lease)
113-
finalized = true
114-
await discardCachedRuntime()
115-
return response
116-
} catch (error) {
117-
if (!finalized) await abortLease(coordinator, request.url, lease)
118-
await discardCachedRuntime()
119-
throw error
120-
}
121-
}
122-
123-
function patchEditorProbe(php: PHP, phase: EditorProbePhase): void {
124-
const path = "/wordpress/wp-admin/post-new.php"
125-
const source = new TextDecoder().decode(php.readFileAsBuffer(path))
126-
const markers: Record<EditorProbePhase, string> = {
127-
admin: "require_once __DIR__ . '/admin.php';",
128-
"auto-draft": "$post_ID = $post->ID;",
129-
"auto-draft-no-persist": "$post_ID = $post->ID;",
130-
"block-editor": "require_once ABSPATH . 'wp-admin/admin-footer.php';",
131-
}
132-
const marker = markers[phase]
133-
const index = source.indexOf(marker)
134-
if (index === -1 || index !== source.lastIndexOf(marker)) throw new Error(`WordPress editor probe marker is not unique: ${phase}`)
135-
const stop = `\necho wp_json_encode( array( 'schema' => 'wp-codebox/cloudflare-editor-probe/v1', 'phase' => '${phase}', 'memoryBytes' => memory_get_usage( true ), 'peakMemoryBytes' => memory_get_peak_usage( true ) ) );\nreturn;`
136-
const insertion = phase === "block-editor" ? index : index + marker.length
137-
php.writeFile(path, new TextEncoder().encode(`${source.slice(0, insertion)}${stop}${source.slice(insertion)}`))
138-
}
139-
140-
function patchAutoDraftPersistenceProbe(php: PHP): void {
141-
const path = "/wordpress/wp-content/plugins/markdown-database-integration/inc/class-wp-markdown-write-engine.php"
142-
const source = new TextDecoder().decode(php.readFileAsBuffer(path))
143-
const needle = `if ( $id ) {
144-
$this->mark_post_dirty( (int) $id );
145-
}`
146-
const replacement = `if ( $id ) {
147-
$rows = $this->driver->query( "SELECT post_status FROM \`{$this->prefix()}posts\` WHERE ID = " . (int) $id );
148-
if ( ! is_array( $rows ) || empty( $rows ) || 'auto-draft' !== ( $rows[0]->post_status ?? '' ) ) {
149-
$this->mark_post_dirty( (int) $id );
150-
}
151-
}`
152-
const index = source.indexOf(needle)
153-
if (index === -1 || index !== source.lastIndexOf(needle)) throw new Error("MDI auto-draft persistence probe marker is not unique.")
154-
php.writeFile(path, new TextEncoder().encode(`${source.slice(0, index)}${replacement}${source.slice(index + needle.length)}`))
155-
}
156-
157102
interface MarkdownManifestFile {
158103
path: string
159104
objectKey: string

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
declare( strict_types=1 );
33

4-
const MDI_REVISION = '6244f244f47f99af3261ba0948262cebe79e5a73';
4+
const MDI_REVISION = '7cf025f2d64aa933d937f1a18a129e278c231783';
55
const REQUIRED_PATHS = array(
66
'_options/siteurl.json', '_options/home.json', '_tables/users.json', '_tables/usermeta.json',
77
'_tables/terms.json', '_tables/term_taxonomy.json', '_tables/termmeta.json', '_tables/postmeta.json',

scripts/build-cloudflare-mdi-runtime-bundle.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { readFile, writeFile } from "node:fs/promises"
22
import { decodeZip, encodeZip } from "@php-wasm/stream-compression"
33

4-
const revision = "6244f244f47f99af3261ba0948262cebe79e5a73"
4+
const revision = "7cf025f2d64aa933d937f1a18a129e278c231783"
55
const archiveUrl = `https://codeload.github.com/Automattic/markdown-database-integration/zip/${revision}`
66
const sourceDirectory = process.env.MDI_RUNTIME_SOURCE
77
const output = new URL("../packages/runtime-cloudflare/assets/markdown-database-integration-runtime.zip", import.meta.url)

tests/cloudflare-runtime.test.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ test("Cloudflare routing reserves phases while the phase-less route serves WordP
4343
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/?phase=r2-mutate")), { kind: "r2-mutate" })
4444
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/?phase=canonical-auth")), { kind: "canonical-auth" })
4545
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/?phase=operator-reset")), { kind: "operator-reset" })
46-
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/wp-admin/post-new.php?phase=editor-probe-admin")), { kind: "editor-probe", phase: "admin" })
47-
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/wp-admin/post-new.php?phase=editor-probe-auto-draft")), { kind: "editor-probe", phase: "auto-draft" })
48-
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/wp-admin/post-new.php?phase=editor-probe-auto-draft-no-persist")), { kind: "editor-probe", phase: "auto-draft-no-persist" })
49-
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/wp-admin/post-new.php?phase=editor-probe-block-editor")), { kind: "editor-probe", phase: "block-editor" })
5046
assert.deepEqual(routeWorkerRequest(new Request("https://worker.example/?phase=seeded-wordpress")), { kind: "probe", phase: "seeded-wordpress" })
5147
})
5248

@@ -118,18 +114,6 @@ test("Cloudflare lease contention honors Retry-After without exceeding the acqui
118114
assert.equal(leaseRetryDelayMs(Number.NaN, 500), 500)
119115
})
120116

121-
test("Cloudflare editor probes bound the authenticated editor lifecycle and discard their runtime", async () => {
122-
const worker = await readFile(new URL("../packages/runtime-cloudflare/src/worker.ts", import.meta.url), "utf8")
123-
const probe = worker.slice(worker.indexOf("async function runCoordinatedEditorProbe"), worker.indexOf("async function resetCanonicalWordPress"))
124-
125-
assert.match(probe, /await runtime\.requestHandler\.request/)
126-
assert.match(probe, /await releaseLease/)
127-
assert.equal((probe.match(/await discardCachedRuntime\(\)/g) ?? []).length, 2)
128-
assert.match(probe, /\/wordpress\/wp-admin\/post-new\.php/)
129-
assert.match(probe, /memory_get_peak_usage/)
130-
assert.match(probe, /'auto-draft' !== \( \$rows\[0\]->post_status/)
131-
})
132-
133117
test("Cloudflare runtime packages a provenanced canonical MDI seed", async () => {
134118
const config = JSON.parse((await readFile(new URL("../packages/runtime-cloudflare/wrangler.jsonc", import.meta.url), "utf8")).replace(/^\s*\/\/.*\n/, "")) as {
135119
rules?: Array<{ type?: string; globs?: string[] }>
@@ -146,7 +130,7 @@ test("Cloudflare runtime packages a provenanced canonical MDI seed", async () =>
146130
assert.equal(markdownIndex.subarray(0, 16).toString(), "SQLite format 3\0")
147131
assert.equal(markdownRuntime.subarray(0, 4).toString("hex"), "504b0304")
148132
assert.equal(canonicalSeed.subarray(0, 4).toString("hex"), "504b0304")
149-
assert.equal(canonicalManifest.markdownDatabaseIntegrationRevision, "6244f244f47f99af3261ba0948262cebe79e5a73")
133+
assert.equal(canonicalManifest.markdownDatabaseIntegrationRevision, "7cf025f2d64aa933d937f1a18a129e278c231783")
150134
assert.equal(canonicalManifest.wordpressInstallSeedSha256, createHash("sha256").update(sqliteInput).digest("hex"))
151135
assert.equal(canonicalManifest.archiveSha256, createHash("sha256").update(canonicalSeed).digest("hex"))
152136
assert.ok(canonicalManifest.files.some((file) => file.path.endsWith(".md")))
@@ -158,15 +142,20 @@ test("Cloudflare runtime packages a provenanced canonical MDI seed", async () =>
158142
})
159143

160144
test("Cloudflare runtime pins and bundles the public constrained MDI runtime", async () => {
161-
const revision = "6244f244f47f99af3261ba0948262cebe79e5a73"
145+
const revision = "7cf025f2d64aa933d937f1a18a129e278c231783"
162146
const generator = await readFile(new URL("../scripts/build-cloudflare-mdi-runtime-bundle.mjs", import.meta.url), "utf8")
163147
const worker = await readFile(new URL("../packages/runtime-cloudflare/src/worker.ts", import.meta.url), "utf8")
164148
const runtime = await readFile(new URL("../packages/runtime-cloudflare/assets/markdown-database-integration-runtime.zip", import.meta.url))
165149
const names: string[] = []
166-
for await (const entry of decodeZip(new Blob([runtime]).stream())) names.push(entry.name)
150+
let writeEngine = ""
151+
for await (const entry of decodeZip(new Blob([runtime]).stream())) {
152+
names.push(entry.name)
153+
if (entry.name === "inc/class-wp-markdown-write-engine.php") writeEngine = await entry.text()
154+
}
167155

168156
assert.match(generator, new RegExp(`const revision = "${revision}"`))
169157
assert.match(worker, new RegExp(`MARKDOWN_DATABASE_INTEGRATION_REVISION = "${revision}"`))
158+
assert.match(writeEngine, /! \$this->is_auto_draft\( \(int\) \$id \)/)
170159
assert.deepEqual(names.sort(), [
171160
"db.php",
172161
"inc/class-wp-markdown-db.php",

0 commit comments

Comments
 (0)